[CONSEIL] MEGA Datalogger, ADC 16buts + NTP + DS1307 + SD + WebServer

Bien le bonjour à tous!

J'ai comme projet la réalisation d'un datalogger comme beaucoup ont déjà réalisé.
Ce dernier a la particularité d'utiliser un ADC 16 bits (AD7715) en SPI multiplexé par
un DG408 (clone d'un CD 4051 aPasCher). Je vous passerais les détails épiques de ce
p*t**n de AD7715 et de sa cohabitation avec le chip Ethernet et de la carte SD, mais
ça fonctionne!!!
La partie NTP est issue en l'état d'une newsletter de SkyWodd, le WebServer et la carte
SD des sketchs par défaut, et le DS1307 est en attente de câblage.

Donc tout va bien dans le meilleur des mondes... à ceci prêt qu'au bout d'un certain
moment, le serveur n'arrive plus à fournir les infos que j'ai préalablement loggées dans
la carte SD (bien que ces même infos "semblent" continuer de se logger normalement)

La cause me semble être une latence trop grande dans la réponse du serveur Web.
Un fichier log qui fait "planter" fait un peu plus de 400Ko (je pense que le serveur Web
plantait déjà bien en dessous...). Je viens de relancer un log tout neuf pour faire des
tests complémentaires... mais en l'état, un
time wget 192.168.1.x // adresse de mon Arduino
prends déjà un peu plus de 2 secondes pour 40 lignes de
1 TimeStamp + 8 n°voies + 8 valeurs ADC + 8 valeurs ADC% comme celle ci-dessous:
2013-02-09 07:09:00 UTC;1;1.00;0.00;2;1.00;0.00;3;1.00;0.00;4;28129.90;42.92;5;65535.00;100.00;6;65535.00;100.00;7;65535.00;100.00;8;28134.90;42.93

En gros, je ne sais pas trop quoi faire pour éviter ce genre de désagrément... Dans
l'absolu, je n'ai pas besoin de "Web'iser" l'intégralité des données, mais je ne vois pas
comment faire pour limiter le set de données à afficher, tout en sachant que la
totalité des données devra tout de même être contenue dans la carte SD...
J'ai pensé à une mémoire tournante, mais la quantité de RAM nécessaire pour 3 jours
serait de 26Ko pour une cadence de 10 mesures de 8 voies par heure...
Implémenter cette mémoire tournante à partir d'un fichier texte... trop usine à mon goût
Faire un fichier par jour... exploitation laborieuse

Mon code est peut-être foireux:

void listenForEthernetClients() {
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("Got a client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connnection: close");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          // add a meta refresh tag, so the browser pulls again every 5 seconds:
          //client.println("<meta http-equiv=\"refresh\" content=\"5\">");
          client.println("TEST TEST TEST TEST");
          client.println("
");

          File dataFile = SD.open("test125.txt", FILE_READ);
          char cc;
          String buffer;
          if (dataFile) {
            while (dataFile.available()) {
              cc = dataFile.read();
              if(cc == 13){  // CR
                dataFile.available();
                dataFile.read();  // LF
                client.print(buffer);
                client.println("
");
                buffer = "";
              }
              else{
                buffer += cc;                
              }              
            }
            dataFile.close();            
            client.println("</html>");
          } 
          else {
            client.println(F("Fichier NOK"));
          }
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  }

Des idées?

Bonne journée studieuse et pluvieuse!

9 secondes pour 200 lignes, soit environ 30Ko
Le pas de temps est à la minute pour test, donc ça grossit vite!

Je vais poser ma question autrement:
Est-ce qu'un débit de 3.75 Ko/s vous parait un débit plausible en réseau local?

Je me pose une autre question du coup:
L' ethernet et la carte SD partagant le bus SPI, et dans la logique de tous les codes
trouvés ici et là, il y a un ping pong permanent entre
lire un char du fichier sur la SD
basculer sur le chip ethernet
écrire dans le buffer du chip ethernet (enfin j'imagine)
basculer sur la SD
lire un autre char du fichier sur la SD
etc...
Cela me parait diablement inefficace, non?

Levaillant:
Est-ce qu'un débit de 3.75 Ko/s vous parait un débit plausible en réseau local?

Sans buffering, en envoi direct octet par octet ça me parait plausible.
Si pour chaque paquet tu envois un octet, en comptant les octets de commande, les vérifs des registres, la vitesse relativement lente du port SPI, ... ça ne parait pas impossible d'avoir quelques Ko/s de débit au final.

Levaillant:
Cela me parait diablement inefficace, non?

Ça l'est, lit / envoi des paquets de 32 octets (ou plus) tu devrais voir une augmentation notable de la vitesse de transfert.

Merci Skywodd!

Je fais déjà (un peu) ce travail de concaténation de char avant l'envoi au client Ethernet.
En gros je fais un readLine avant de l'envoyer... et oui cela a améliorer très notablement
le débit (faudrait que je quantifie tout de même).
J'utilise un String pour ce faire (pas taper! pas taper :-))
Bon du coup, j'ai essayé de poursuivre un peu en dimensionnant à la louche ce String:

          File dataFile = SD.open("test125.txt", FILE_READ);
          char cc;
          String buffer;
          buffer.reserve(200);
          if (dataFile) {
            while (dataFile.available()) {
              cc = dataFile.read();
              if(cc == 13){  // CR
                //dataFile.available();
                dataFile.read();  // LF
                buffer += "
";
                client.println(buffer);
                buffer = "";
              }
              else{
                buffer += cc;                
              }              
            }
            dataFile.close();            
            client.println("</html>");
          } 
          else {
            client.println(F("Fichier NOK"));
          }

Les résultats sont peu concluants... 3.4 Ko/s

Viens ma nouvelle question:
Comment créer une mémoire tournante ?
Je vois bien un tableau de String assez grand pour contenir x jours de données qui,
à chaque nouvelle mesure, pousserait la donnée précédente à l'indice n +1
Je m'y attelle

Raaa une string ! Au bucher hérétique ! :grin:

Pour ta mémoire tournante regarde le principe du buffer circulaire :wink:

skywodd:

Levaillant:
Est-ce qu'un débit de 3.75 Ko/s vous parait un débit plausible en réseau local?

Sans buffering, en envoi direct octet par octet ça me parait plausible.
Si pour chaque paquet tu envois un octet, en comptant les octets de commande, les vérifs des registres, la vitesse relativement lente du port SPI, ... ça ne parait pas impossible d'avoir quelques Ko/s de débit au final.

Levaillant:
Cela me parait diablement inefficace, non?

Ça l'est, lit / envoi des paquets de 32 octets (ou plus) tu devrais voir une augmentation notable de la vitesse de transfert.

bonsoir
j'avais fait un test sd+ethernet là

ça depassait difficilement les 90Ko/s

Entre 4Ko/s et 90Ko/s, il y a une grosse marge de progression... non?
Je viens de relire ton post, et télécharger ton exemple (je ne peux tester ce soir...).
Je veux bien essayer la lib TinyWebServer, mais sur le coup faudra bien m'expliquer
comment cette dernière balance des données à plus de 50Ko/s, alors que mon maigre
sketch, simple au possible n'en balance que 4 au max...

M'enfin pourquoi pas :slight_smile:

Sinon, je me suis lancé dans ma mémoire tournante ou buffer circulaire comme dit Skywodd :wink:

const unsigned int NB_MESURE_RAM = 100;

typedef struct {
  long timeStamp;
  unsigned int voie1;
  unsigned int voie2;
  unsigned int voie3;
  unsigned int voie4;
  unsigned int voie5;
  unsigned int voie6;
  unsigned int voie7;
  unsigned int voie8;
}  
uneMesure;

uneMesure listeMesure[NB_MESURE_RAM];

void memoireTournante(){
  for(int i = (NB_MESURE_RAM - 1) ; i == 1 ; i--){
    // de la fin du tableau au début, moins un element zappé pour la bonne cause
    // on copie l'element n vers n+1, faut partir de la fin
    listeMesure[i+1].timeStamp = listeMesure[i].timeStamp;
    listeMesure[i+1].voie1 = listeMesure[i].voie1;
    listeMesure[i+1].voie2 = listeMesure[i].voie2;
    listeMesure[i+1].voie3 = listeMesure[i].voie3;
    listeMesure[i+1].voie4 = listeMesure[i].voie4;
    listeMesure[i+1].voie5 = listeMesure[i].voie5;
    listeMesure[i+1].voie6 = listeMesure[i].voie6;
    listeMesure[i+1].voie7 = listeMesure[i].voie7;
    listeMesure[i+1].voie8 = listeMesure[i].voie8;
  }
}

Je regarde aussi du coté de EDB :
http://playground.arduino.cc//Code/ExtendedDatabaseLibrary
cela donne des idées!

Sur ce bonne soirée!