Web page does not work in my SD card

Hello everybody, I have an arduino ethernet Rev. 3 and I have a problem when I try to show my website stored in my SD card. I tryed 2 codes, one single and the other a little more complex. The simplest works and another does not.

This is the code that works:

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

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10,0,0,177); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80

File webFile;

void setup()
{
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(9600);       // for debugging
    
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        Serial.println("ERROR - Can't find index.htm file!");
        return;  // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                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("Connection: close");
                    client.println();
                    // send web page
                    webFile = SD.open("index.htm");        // open web page file
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }
                        webFile.close();
                    }
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

This is the code that does not work:

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

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10,0,0,177); // IP address, may need to change depending on network
EthernetServer server(80);  // create a server at port 80

File webFile;

String HTTP_req = "";     // stores the received HTTP request

void setup()
{
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(9600);       // for debugging
    
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        Serial.println("ERROR - Can't find index.htm file!");
        return;  // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                HTTP_req += c;          // save HTTP request character
                // print HTTP request character to serial monitor
                Serial.print(c);
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send web page
                    if ((HTTP_req.indexOf("GET / ") > -1) || (HTTP_req.indexOf("GET /index.htm") > -1)) 
                    {
                        Serial.println("index");
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-Type: text/html");
                        client.println("Connnection: close");
                        client.println();
                        webFile = SD.open("index.htm");        // open web page file
                        Serial.println(webFile);
                    }
                    else if (HTTP_req.indexOf("GET /page2.htm") > -1) {
                        Serial.println("pagina 2");
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-Type: text/html");
                        client.println("Connnection: close");
                        client.println();
                        webFile = SD.open("page2.htm");        // open web page file
                    }
                    else if (HTTP_req.indexOf("GET /pic.jpg") > -1) {
                        webFile = SD.open("pic.jpg");
                        if (webFile) {
                            client.println("HTTP/1.1 200 OK");
                            client.println();
                        }
                    }
                    if (webFile) {
                        while(webFile.available()) {
                            client.write(webFile.read()); // send web page to client
                        }
                        webFile.close();
                    }
                    HTTP_req = "";  // empty the string
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

These codes have taken some forums, they are not mine, but apparently are very similar and I can not know where can be the error.

both codes write this serial monitor:

Initializing SD card…
SUCCESS - SD card initialized.
SUCCESS - Found index.htm file.

but when I print “Serial.println(webFile)” in the first code return 1 and in the secon code return 0.

Greetings, thank you very much.

I haven't gone over your code to see what doesn't work, but I have been playing a lot with similar code. I found this link really helpful:

http://startingelectronics.com/tutorials/arduino/ethernet-shield-web-server-tutorial/SD-card-gauge/

It's an entire tutorial. I found Part 15 really cool. It uses HTML5 code and canvas to draw a really neat analog gauge. Part 16 shows how the server will respond to 2 or more clients and update all clients with correct pin status etc.

There are some really good examples to use.

I hope this helps.

                        webFile = SD.open("index.htm");        // open web page file
                        Serial.println(webFile);

webFile is a pointer to the file. It is NOT a pointer to data in the file. You need to actually, strange as it may seem, read() the file. Printing a pointer is a silly idea, generally.

PaulS:                         webFile = SD.open("index.htm");        // open web page file                         Serial.println(webFile);

webFile is a pointer to the file. It is NOT a pointer to data in the file. You need to actually, strange as it may seem, read() the file. Printing a pointer is a silly idea, generally.

To add to this, getting anything other than a zero, which is a valid value for a pointer, should indicate you have successfully opened the file.

My question is: does the second server serve you index.htm?

Exactly Pauls, I print webFile because when webFile is not a valid pointer neturn 0 else 1 (or any value other than 0) and my problem is justly this. In the first code when I print webFile then my output is 1 and in the second code when I print webFile is 0. There is something in the second code that does not allow to my Webfile variable pointing correctly to the file index.htm

Sorry for my english.

Hi liudr, well I have in my SD card 3 files:

index.htm
page2.htm
pic.jpg

when load the first code in my arduino, I don’t have a problem and can i see my webpage in firefox, but I can’t access to page2.htm and pic.jpg; then the second code can show the 2 web files and image, but this is my problem because when I print webFile I note that it is not pointing correctly to the file.

Can you understand me?

The SD class uses 1/4 of the memory on a 328-based Arduino. The Ethernet class uses a fair bit of memory. The major difference I see between the code that works and the code that doesn't is that the code that doesn't uses the String class. While zoomkat has never had a problem with the String class, and therefore KNOWS that it is perfect, plenty of other people have found that the use of the String class pushes them over the limit in terms of memory used. Perhaps dispensing with the String class is in order.

I am puzzled. If you can see both web pages then the index.htm IS properly opened and SHOULD have non-zero return value when it is printed.

I completely agree with PaulS regarding the String class. I have never touched it. Learn some old-fashioned c-string. The success that zoomkat experiences with String class is non-typical. This kind of depends on whether someone writes code that grows a zero-length String one character at a time to a very long String, which is most problematic. I don't think zoomkat is doing that but rather doing other stuff that won't show the problem of using the String class.

Thank you..! then how should I declare my variable? this variable need to know what page they are asking me.

then how should I declare my variable?

char varName[varSize];

You will need to experiment to determine what is a valid value for the size of the array. Both too large and too small are problematic.

I with this resulting char. honestly do not think that by using only one string type variable is using all the memory of my arduino. If so then talk bad hardware.

I with this resulting char. honestly do not think that by using only one string type variable is using all the memory of my arduino. If so then talk bad hardware.

You are free to believe what you like. But, it isn't a string. It's a String. They are NOT the same thing.

of course I'm free to think what you want, I do not get to write that in a forum. Sorry if I hurt your love for arduino.

mblanch: but when I print "Serial.println(webFile)" in the first code return 1 and in the secon code return 0.

What is the name of the file you tried to open? You only check the existence of index.htm, but you have code that may try to open two other files as well and you have not tested whether they exist.

mblanch:
I with this resulting char. honestly do not think that by using only one string type variable is using all the memory of my arduino. If so then talk bad hardware.

Below is how I get different files from the SD card and send to a browser. Kind of clunky but you might try it with your files. I haven’t come across a good way to use a single function to open and send different files.

//zoomkat 1/26/13
//SD server slider test code
//open serial monitor to see what the arduino receives
//address will look like http://192.168.1.102:84/servosld.htm when submited
//for use with W5100 based ethernet shields
//put the servosld.htm, slider.js, bluev_sl.gif,
//and bluev_bg.gif on the SD card
//files at http://web.comporium.net/~shb/servoslider.htm page


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

#include <Servo.h> 
Servo myservoa, myservob, myservoc, myservod;  // create servo object to control a servo 
Servo myservoe, myservof, myservog;
String readString, pos;

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

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

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);

  //delay(2000);
  server.begin();
  Serial.println("Ready");
  
  myservoa.attach(2);  //the pin for the servoa control
  myservob.attach(3);  //the pin for the servob control
  myservoc.attach(5);  //the pin for the servoc control
  myservod.attach(6);  //the pin for the servod control 
  myservoe.attach(7);  //the pin for the servoa control
  myservof.attach(8);  //the pin for the servob control
  myservog.attach(9);  //the pin for the servoc control
  //myservoh.attach(10);  //the pin for the servod control 

}

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
         
         //select proper header for file to be sent to browser
           if(readString.indexOf("Submit") >=0) { //don't send new page
           client.println("HTTP/1.1 204 Zoomkat");
           client.println();
           client.println(); }
           
          //client.println("HTTP/1.1 200 OK"); //send new page
          if(readString.indexOf("servosld") >=0) {
          client.println("HTTP/1.1 200 OK"); //send new page          
          client.println("Content-Type: text/html");
          client.println(); }

          if(readString.indexOf("slider") >=0) {
          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: application/x-javascript");
          client.println(); }
          
          if(readString.indexOf("bluev") >=0) {
          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: image/gif");
          client.println(); }
          
          //select file to send to browser
          if(readString.indexOf("servosld") >=0) {
            File myFile = SD.open("SERVOSLD.HTM");
            if (myFile) {
              while (myFile.available()) {
                client.write(myFile.read());
              }
              myFile.close();
            }
          }

          if(readString.indexOf("slider") >=0) {
            File myFile = SD.open("slider.js");
            if (myFile) {
              while (myFile.available()) {
                client.write(myFile.read());
              }
              myFile.close();
            }
          }

          if(readString.indexOf("bluev_sl") >=0) {
            File myFile = SD.open("bluev_sl.gif");
            if (myFile) {
              while (myFile.available()) {
                client.write(myFile.read());
              }
              myFile.close();
            }
          }

          if(readString.indexOf("bluev_bg") >=0) {
            File myFile = SD.open("bluev_bg.gif");
            if (myFile) {
              while (myFile.available()) {
                client.write(myFile.read());
              }
              myFile.close();
            }
          }

          delay(1);
          //stopping client
          client.stop();

          //process GET string request from client and and position servo
          
          pos = readString.substring(8, 12); //get the first four characters         
          //Serial.println(pos);
          int n = pos.toInt();  //convert readString into a number   
          Serial.println(n); 
          Serial.println();
          
          if(readString.indexOf("?0") >0) myservoa.writeMicroseconds(n);
          if(readString.indexOf("?1") >0) myservob.writeMicroseconds(n);
          if(readString.indexOf("?2") >0) myservoc.writeMicroseconds(n);
          if(readString.indexOf("?3") >0) myservod.writeMicroseconds(n);
          if(readString.indexOf("?4") >0) myservoe.writeMicroseconds(n);
          if(readString.indexOf("?5") >0) myservof.writeMicroseconds(n);
          if(readString.indexOf("?6") >0) myservog.writeMicroseconds(n);
          //only seven servo pins, so back to myservoa for testing
          if(readString.indexOf("?7") >0) myservoa.writeMicroseconds(n);

          //clearing string for next read
          readString="";
          pos="";
        }
      }
    }
  } 
}

Moderator edit: pointless diatribe removed

Moderator edit: pointless diatribe removed

Moderator person, PaulS made the below statements about me when I hadn't even posted in this thread. Why do you remove my comments concerning PaulS, yet you leave his comments about me? Hmmm... ;)

While zoomkat has never had a problem with the String class, and therefore KNOWS that it is perfect, plenty of other people have found that the use of the String class pushes them over the limit in terms of memory used.

mblanch: I with this resulting char. honestly do not think that by using only one string type variable is using all the memory of my arduino. If so then talk bad hardware.

Variables don't use all the memory of the Arduino. However repeated use of the String class can cause memory fragmentation. That would apply whatever the hardware was.

PaulS knows what he is talking about, I would listen to what he says.

          //store characters to string 
          readString += c;

This might be one variable but you are using it many times. Adding a single character to a String is typical code that causes memory fragmentation. First it allocates one byte of memory, then it allocates two, then three and so on. You just don't notice this as much when using a PC with a gigabyte of memory, but it still happens.

PeterH:

mblanch: but when I print "Serial.println(webFile)" in the first code return 1 and in the secon code return 0.

What is the name of the file you tried to open? You only check the existence of index.htm, but you have code that may try to open two other files as well and you have not tested whether they exist.

To reiterate - have you confirmed that the file you're trying to open actually exists?

The below version of the “listfiles” example should list the files detected on the SD card. This is modified from the listfiles code examples in the IDE to operate with the Ethernet shield.

/*
  SD card basic file example
 
 This example shows how to create and destroy an SD card file 	
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4
 
 created   Nov 2010
 by David A. Mellis
 updated 2 Dec 2010
 by Tom Igoe
 
 This example code is in the public domain.
 	 
 */
#include <SD.h>

File root;

void setup()
{
  Serial.begin(9600);
  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(4, OUTPUT);

  // 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");

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

  root = SD.open("/");
  
  printDirectory(root, 0);
  
  Serial.println("done!");
}

void loop()
{
  // nothing happens after setup finishes.
}

void printDirectory(File dir, int numTabs) {
   while(true) {
     
     File entry =  dir.openNextFile();
     if (! entry) {
       // no more files
       //Serial.println("**nomorefiles**");
       break;
     }
     for (uint8_t i=0; i<numTabs; i++) {
       Serial.print('\t');
     }
     Serial.print(entry.name());
     if (entry.isDirectory()) {
       Serial.println("/");
       printDirectory(entry, numTabs+1);
     } else {
       // files have sizes, directories do not
       Serial.print("\t\t");
       Serial.println(entry.size(), DEC);
     }
   }
}

Nick,

I was looking for the malloc.c which is probably compiled into .o file in Arduino IDE. Looking at it will resolve the issue of "String will mess up" vs. "String will not mess up". I am with you but still kind of blindly believing the free() is to be blamed. The explanation of the avr malloc is good enough but I need to see the actual code.