Problem browsing files of a SD card throught Ethernet (WebServer)

Hi,

I'm currently developing a program on my Arduino uno.
The purpose of my project is to get the water and energy consumption of my home.
The first step of this project is to be able to browse files stored on the SD card and to publish the content of a text file on a web interface. Then I would be able to treat and display data with a web application.

I need your help because I encounter problems with my code.
I manage to display all the files stored (3 files) in my SD card on the web browser of my PC.
The problem comes when I refresh the page. No more files are displayed.
Here is my code :

#include <SD.h>
#include <Ethernet.h>
#include <SPI.h>

//Objet permettant d'accéder aux fichiers de la carte SD
File myFile;

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,2,177);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(80);

void setup()
{
  // Ouvrir la communication série et attendre l'ouverture du port
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // Démarrer le lecteur de carte SD
  Serial.print("Initializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
  pinMode(10, OUTPUT);

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  // Démarrer le service Ethernet
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());

}

#define BUFSIZ 100

void loop()
{
  char clientline[BUFSIZ];
  int index = 0;
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.println(c);
        //Serial.write(c);
        // 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' && c != '\r') {
          clientline[index] = c;
          index++;
          // are we too big for the buffer? start tossing out data
          if (index >= BUFSIZ) 
            index = BUFSIZ -1;

          // continue to read more data!
          continue;
        }

        // got a \n or \r new line, which means the string is done
        clientline[index] = 0;

        // Look for substring such as a request to get the root file
        if (strstr(clientline, "GET / ") != 0) 
        {
          Serial.println("Publier la liste des fichiers du répertoire");
          PublierListeFichiers("/",client);
          //PublierListeFichiers("/",client);
          break;
        }
        else if (strstr(clientline, "GET /") != 0) 
        {
          //PublierFichier("/ARDTEST2.CSV",client);
        }

        if (c == '\n' && currentLineIsBlank) 
        {
          //PublierFichier("/ARDTEST2.CSV",client);
          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();
    Serial.println("client disonnected");
  }
}

//Publier l'entête HTML
void PublierEnteteHTML(EthernetClient client)
{
  // send a standard http response header
  client.write("HTTP/1.1 200 OK\n");
  client.write("Content-Type: text/html\n");
  client.write("Connnection: close\n");
  client.write("\n");
  client.write("<!DOCTYPE HTML>\n");
  client.write("<html>");
  client.write("<body>");
  // add a meta refresh tag, so the browser pulls again every 5 seconds:
  //client.println("<meta http-equiv=\"refresh\" content=\"5\">");
}


//Publier la liste des fichier présent dans un répertoire
boolean PublierListeFichiers(char* path,EthernetClient client)
{
  File myDir, entry;
  PublierEnteteHTML(client);
  client.write("Liste des fichiers du répertoire ");
  //client.write(path);
  //client.write(" :</p>");
  myDir=SD.open(path,FILE_READ);

  //  myDir.rewindDirectory();
  myDir.seek(0);
  entry = myDir.openNextFile();
  client.write("<ul>");
  while(entry)
  {
    Serial.println(entry.name());
    client.write("<li>");
    //client.write(myDir.position());
    client.write("<a href=\"");
    client.write(entry.name());
    client.write("\">");
    client.write(entry.name());
    client.write("</a>");
    // files have sizes, directories do not
    client.write("    ");
    client.print(entry.size(), DEC);
    client.write(" octets</li>");
    entry =  myDir.openNextFile();
  }
  //close files
  myDir.close();
  entry.close();
  client.write("</ul>");
  client.write("fin </P>");
  client.write("</body>");
  client.write("</html>");
}


//Publier le contenu du fichier sur une page WEB
boolean PublierFichier(char* filename,EthernetClient client)
{
  PublierEnteteHTML(client);
  //Ouvrir le fichier
  myFile = SD.open(filename,FILE_READ);
  if (myFile) {
    Serial.print("Affichage du fichier ");
    Serial.println(filename);

    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      client.write(myFile.read());
      //client.println((char)myFile.read());
    }
    // close the file:
    myFile.close();
  } 
  else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  client.println("</body>");
  client.println("</html>");

  return true;
}

Further more, when I uncomment those 2 lines :

  client.write(path);
  client.write(" :</p>");

Only 2 files appears ... It's really bizarre

Is somebody have an idea of what is wrong in my source code ?

Thanks

Adrien

Lot's of string constants, lots of buffers, and lots of objects. A good first pass at solving the problem would be to move the string constants to Flash.

void setup()
{
// Ouvrir la communication série et attendre l'ouverture du port
Serial.begin(9600);
while ( ! Serial ) {
; // wait for serial port to connect. Needed for Leonardo only
}
...

I suspect that while loop is not doing what you think it is doing. I suggest removing it for the Uno.

I am not sure why you are using the general approach of listing files for the project you described.
A much simpler approach is to simply use the files you know are there.

For general remote access to your project's files consider including a tiny ftp implementation you might find elsewhere. Especially if the next thing you want to do is retrieve, rename or delete files.

Coding Badly :
Thank you for the advice, I will store string constants into Flash.
I'm not yet familiar with embded developements best practices.

Dgerman :
You're right; a simpler way would be just to use the files I know. I may be trying to make something too complicated for my needs.
I already think about a tiny FTP implementation. But I didn't find any source code.
I think I will try to create my own one.
Did you have link to a tiny ftp realization?

Adrien

I already think about a tiny FTP implementation. But I didn't find any source code.
I think I will try to create my own one.
Did you have link to a tiny ftp realization?

Look in the Networking section. SurferTim wrote one. You can search for it as easily as I could.

I snipped some stuff to illustrate the problem:

boolean PublierListeFichiers(char* path,EthernetClient client)
{
  File myDir, entry;
  myDir=SD.open(path,FILE_READ);

  entry = myDir.openNextFile();
  while(entry)
  {
    Serial.println(entry.name());
    entry =  myDir.openNextFile();
  }
  //close files
  myDir.close();
  entry.close();
}

You open the directory. Then, you open each file in the directory. Then, you close the last file opened, and close the directory. Pretty soon, you run out of file handles.

You need to close each file BEFORE you open the next one.

Shame on me.

Thank you PaulS. I didn't test it, but you must be right.

I'm going to make the correction and to look for the code writing by SurferTim.

Thank you again.

Adrien