web server to read file from SD card and show its content as HTML

I'm working on a monitoring project that logs some data to the SD card of the official Ethernet Shield as csv file, I want to show the logs contents on a web page that is produced by the arduino , but when I try to open the csv file for reading after the client is connected to the server , I get an error but when I try to open it on startup its working OK.

I have read that I should switch between ethernet SS PIN and SD card SS pin but I cannot manage to make it work !!

Is it possible to switch ethernet SS pin while the client is connected and then switch it back after reading from SD card without losing the client connection??

here is my code :

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,2, 230);
EthernetServer server(80);

File myFile;

void setup()
{
  
  Ethernet.begin(mac, ip);
  server.begin();

  Serial.begin(9600); 
  
  Serial.print("Initializing SD card...");
  pinMode(10, OUTPUT);
  
   if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
}


void loop() 
{
EthernetClient client = server.available();
  if (client)
  {
    boolean current_line_is_blank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n' && current_line_is_blank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<h2>CSV Data : </h2>");

         // csv file data
         myFile = SD.open("datalog.csv");
         if (myFile) {
         Serial.println("datalog.csv:");
   
        // read from the file until there's nothing else in it:
        while (myFile.available()) {
           client.println(myFile.read());
        }
        myFile.close();
      } else {
        Serial.println("error opening datalog.csv"); // ################### I GOT THIS ERROR
      }

          break;
        }
        if (c == '\n') {
          current_line_is_blank = true;
        } else if (c != '\r') {
          current_line_is_blank = false;
        }
      }
    }
    delay(1);
    client.stop();
  }

}

Is it possible to switch ethernet SS pin while the client is connected and then switch it back after reading from SD card without losing the client connection??

Yes. I use both for FTP. Here is my code:
http://playground.arduino.cc/Code/FTP
It uses two sockets and the SD simultaneously to transfer files to or from my FTP server.

The SS pins are handled by the low level libraries of each device. The trick is setting them up. Both devices need the SS line HIGH when leaving the setup() function.

Thank you Tim for your answer ,
I have changed my code to set them both HIGH before the end of setup()..
but still having the same error !

If you can't open the file with SD.open(filename), then there are normally two reasons.

  1. Opening a SD file takes a lot of SRAM, and you ran out.
  2. The file doesn't exist

I get an error but when I try to open it on startup its working OK.

Post the code that did work when you opened the file in setup().

I'm sure the file exists because the same exact code is working OK on startup():
and the file is only about 21 words ..

void setup()
{
  
  Ethernet.begin(mac, ip);
  server.begin();

  Serial.begin(9600); 
  
  Serial.print("Initializing SD card...");
  pinMode(10, OUTPUT);
  
   if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

          myFile = SD.open("datalog.csv");
         if (myFile) {
         Serial.println("datalog.csv:");
   
        // read from the file until there's nothing else in it:
        while (myFile.available()) {
           Serial.println(myFile.read());// ################ I GOT THE FILE CONTENTS ON THE SERIAL MONITOR SCREEN
        }
        myFile.close();
      } else {
        Serial.println("error opening datalog.csv");
      }
}

still having the same error !

Could you describe the error, please?

-br

billroy:
Could you describe the error, please?

-br

I cannot open a file for reading from SD card when a client is connected to a web server on my arduino UNO r3 with Ethernet Shield ,
the full code on the first post..

Thank you..

I used this as a test, and it worked good.

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// change to your network settings
IPAddress ip( 192,168,2,2 );
IPAddress gateway( 192,168,2,1 );
IPAddress subnet( 255,255,255,0 );

EthernetServer server(80);

void setup()
{
  Serial.begin(9600);

  // disable w5100 while setting up SD
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  Serial.print("Starting SD..");
  if(!SD.begin(4)) Serial.println("failed");
  else Serial.println("ok");
  
  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  digitalWrite(10,HIGH);

  delay(2000);
  server.begin();
  Serial.println("Ready");
}

void loop()
{
  EthernetClient client = server.available();
  if(client) {
    boolean currentLineIsBlank = true;
    boolean currentLineIsGet = true;
    int tCount = 0;
    char tBuf[64];

    Serial.print("Client request: ");
    
    while (client.connected()) {
      while(client.available()) {
        char c = client.read();

        if(currentLineIsGet && tCount < 63)
        {
          tBuf[tCount] = c;
          tCount++;
          tBuf[tCount] = 0;          
        }

        if (c == '\n' && currentLineIsBlank) {
          Serial.println(tBuf);
          Serial.print("POST data: ");
          while(client.available()) Serial.write(client.read());
          Serial.println();

          // send a standard http response
          Serial.println("Sending response");
          client.write("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");

          File fh = SD.open("index.htm");

          if(fh) {
            
            byte clientBuf[64];
            int clientCount = 0;
  
            while(fh.available()) {
              clientBuf[clientCount] = fh.read();
              clientCount++;
    
              if(clientCount > 63)
              {
                Serial.println("Packet");
                client.write(clientBuf,64);
                clientCount = 0;
              }
            }
          
            if(clientCount > 0) client.write(clientBuf,clientCount);

            fh.close();
          }
          else Serial.println("file open failed");

          client.stop();
        }
        else if (c == '\n') {
          currentLineIsBlank = true;
          currentLineIsGet = false;
        } 
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    Serial.println("done");
  }
}

I uploaded a file to the SD card with the html in it as index.htm. Here is the contents.

<html><body>
TEST
</body></html>

Does this work for you?

SurferTim:
Does this work for you?

no !!!

The web page is blank, and I got "file open failed" error on the serial monitor:""

Starting SD..ok
Ready
Client request: GET / HTTP/1.1

POST data: 
Sending response
file open failed
done

this is driving me crazy !!! I have tried tens of codes with no lock ...

What Arduino are you using? I am testing this on a Mega 2560, and it is showing that code has barely enough SRAM to run on an Uno. Maybe you are running out of SRAM.

I'm using Arduino Uno Rev3..

can I test the SRAM some how ?

or is there is away to reset the arduino to its "factory settings"?

I include this function code to any sketch I want to check the SRAM.

int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);  
}

Then call it something like this.

Serial.print("Free SRAM = ");
Serial.println(freeRam());

It does not show 0 when you run out of memory. It will show an unrealistic amount of SRAM remaining. If I run my Mega out of memory, it will return more free SRAM than my Mega has.

or is there is away to reset the arduino to its "factory settings"?

It is returned to it's "factory settings" every time you upload a new sketch (except for EEPROM, but that has nothing to do with your issue).

Thanks you all..

The SRAM is 657 right before the open file failed..
and 813 right before the end of setup()....

That should be pretty close to correct. I figured a bit over 300 remaining as an estimate. If you are not out of memory, I don't know what to tell you. It should work.

Thank you very much Tim for your support and patience,

after hours of debugging I found out that the file does not open from the first time I call "SD.open" , but does open correctly the second time,

I have tried to delay some time after the open call and before the read call , but with no success..

so I added the open code once again right after the first call and it's working :slight_smile: :

          File fh = SD.open("index.htm");
          fh = SD.open("index.htm");

That seems odd I know , but still better than nothing..

Below is some test code you might try if you know you have a good file on your sd card. I've noticed that under some conditions the sd card may become unaccessable and require the card to be removed and reinserted or the arduino cold booted with the card in it to regain access to the sd card.

//zoomkat 12/26/12
//SD server test code
//open serial monitor to see what the arduino receives
//address will look like http://192.168.1.102:84 when submited
//for use with W5100 based ethernet shields

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port
String readString; 

//////////////////////

void setup(){

  Serial.begin(9600);

  // disable w5100 while setting up SD
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);
  Serial.print("Starting SD..");
  if(!SD.begin(4)) Serial.println("failed");
  else Serial.println("ok");

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  digitalWrite(10,HIGH);

  //delay(2000);
  server.begin();
  Serial.println("Ready");

}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {
          //store characters to string 
          readString += c; 
          //Serial.print(c);
        } 
        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString); //print to serial monitor for debuging 

          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: text/html");
          //client.println("Content-Type: image/jpeg");
          //client.println("Content-Type: image/gif");
          //client.println("Content-Type: application/x-javascript");
          //client.println("Content-Type: text");
          
          client.println();

          //File myFile = SD.open("boom.htm");
          File myFile = SD.open("HYPNO.JPG");
          //File myFile = SD.open("BLUEH_SL.GIF");
          //File myFile = SD.open("SERVOSLD.HTM");
          if (myFile) {
            //Serial.println("test.txt:");
            // read from the file until there's nothing else in it:
            while (myFile.available()) {
              client.write(myFile.read());
            }
            // close the file:
            myFile.close();

          }
            delay(1);
            //stopping client
            client.stop();
            readString="";
          //}
        }
      }
    }
  } 
}