Pages: [1]   Go Down
Author Topic: Webserver & external files from SD card, no show...  (Read 6236 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

HI,

I'm experimenting with a webserver. Everything (UNO, 5100 Ethernetshield) runs fine as long as I put all the html code inline in the sketch.
When I try to load the html from a SD card only the text shows. I shamelessly copied the following sketch from another post on this forum (http://arduino.cc/forum/index.php/topic,158718.0.html), I only reduced the buffer sizes to 64.
I tried other examples too, i.e. the one from this post: http://arduino.cc/forum/index.php?topic=156244.0 and other from around the web, but every time only text shows up. No javascript loads, no external css files load etc.

This is the code I tried before giving in and ask for help:

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

// MAC address from Ethernet shield sticker under board
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xE7, 0xAC };
IPAddress ip(192, 168, 16, 100); // IP address, may need to change depending on network
byte dn[] = {8, 8, 8, 8 };
byte gw[] = { 192, 168, 16, 254 };
byte mask[] = { 255, 255, 255, 0 };
EthernetServer server(80);  // create a server at port 80

File webFile;
char header[64];
char filename[64];
int txtlen;
uint8_t buf[64];
int aantal;

void setup()
{
    pinMode(10, OUTPUT);
    Ethernet.begin(mac, ip, dn, gw, mask);
    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.");
}

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

    txtlen = 0;
    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
                if (txtlen < 63) {
                  header[txtlen++] = c;
                  header[txtlen] = 0;
                }
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                Serial.write(c);
                if (c == '\n' && currentLineIsBlank) {
                  webFile = SD.open("index.htm");            // open web file
                  if (!webFile) {
                    Serial.println("File not found!!");
                    client.println("HTTP/1.1 404 NOT FOUND");
                  }
                  else {
                    // 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
                  if (webFile) {
                        while(aantal = webFile.available()) {
                            if (aantal > 63) {
                              webFile.read(buf, 64);
                              client.write(buf, 64);
                            }
                            else {
                              webFile.read(buf, aantal);                             
                              client.write(buf, aantal); // 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(100);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

and this is the html:

Code:
<html>

<head>
<meta http-equiv="Content-Language" content="nl">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>This picture is from the Arduino</title>
</head>

<body>

<p><font size="5">This picture is from the Arduino webserver:</font></p>
<p>
<img border="0" src="picture.jpg" width="349" height="262"></p>
<p>&nbsp;</p>

</body>

</html>

Both picture.jpg and index.htm are in the root of the SD card. The card initializes fine, the index.htm is found and is shown in the browser. But where the picture should be just the 'missing image' symbol is shown.
I'm guessing it is a memory problem, but I have no idea how to find out. Or is it something to do with mime-types? I'm lost here...
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 610
Posts: 49086
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
                char c = client.read(); // read 1 byte (character) from client
You don't seem to care what the client is asking for. At least not to the extent of printing the client's request.

The client initially asks for the page. You supply that. The page includes an img tag, so the client says "Aha, I need to ask for that, too.". It does, but you don't care. You do not respond properly to that request. Ergo, the image is not supplied, and the image does not appear.

Not exactly rocket surgery to figure out what to do. Respond (appropriately) to the client request, without assuming that you know what the client is asking for.

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, that makes perfect sense. But even though it's not rocket science to figure out what to do, figuring out how to do it is beyond me at the moment. (As is the reason this code appears to work for others, but that's another topic).
I've looked for tutorials and examples for hosting files from a SD card, but so far I've not found much (except for the forementioned examples that don't seem to work for me). I don't want anybody to write the code for me, but maybe a pointer to a tutorial dealing with this problem?
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 610
Posts: 49086
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't know of such a tutorial, but I think that if you Serial.print(c), you'll see the problem, and perhaps the solution. Suppose the client sends "GET / HTTP 1.0" to the Arduino. Currently, you ignore what the client asks for, and send a reply. As it happens, that is the correct response, in this case.

But, the page you send back has an image tag in it. So, the client sees this, and makes another request -
"GET /picture.jpg HTTP 1.0". You don't care what the client asked for, so you send the base page again. This does not satisfy the request, so the client discards the data.

What you need to do is collect the client request in a string (a NULL terminated array of chars), which you are doing, and then parse that request to see what the client is asking for. If the client IS asking for / or /index.htm, send that. If the client is asking for /picture.jpg, send that.

zoomkat has posted some code that reads image data from an SD card and sends it back to a client.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, that also explains why the code I copied probably worked in it's original form. It had an 'extract filename' function:

Code:
void ExtractFileName()
{
  int i, j;
 
  i=0;
  while (header[i++] != ' ') {
    ;
  }
  j=0;
  while (header[i] != ' ') {
    filename[j++] = header[i++];
  }
  filename[j] = 0;
  if (filename[0] == '/' && filename[1] == 0) {
    strcpy(filename, "index.htm");
  }
}

And in stead of just opening SD.open("index.htm") it had:

Code:
                  ExtractFileName();
                  Serial.print("Extracted filename is: ");
                  Serial.println(filename);
                  webFile = SD.open(filename);            // open web file


However I kept getting "Extracted filename is /index.htm"  "file not found".
I now put back that code and now I see the picture appear. As far as I know the code now is identical to what I was doing before (giving me the constant "file not found") so I don't quite understand what went wrong the first time. As it turns out it's a good thing though.
Your explanation put me back on track, I now (sort of) understand what this code is doing and why it's there. Time to dive deeper into this.

Thanks a lot,

A
Logged

0
Offline Offline
Tesla Member
***
Karma: 141
Posts: 9555
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Below is some test code that loads a web page containing files served from the SD card.

Code:
//zoomkat 2/26/13
//SD server slider test code
//open serial monitor to see what the arduino receives
//browser 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
//download flies at:
// http://web.comporium.net/~shb/pix/servosld.htm
// http://web.comporium.net/~shb/pix/slider.js
// http://web.comporium.net/~shb/pix/bluev_bg.gif
// http://web.comporium.net/~shb/pix/bluev_sl.gif
//

#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; // myservoh not used due to lack of another free pin
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

          client.println("HTTP/1.1 200 OK"); //send new page
          if(readString.indexOf("servosld") >=0) {
            client.println("Content-Type: text/html");
            client.println();
          }

          if(readString.indexOf("slider") >=0) {
            client.println("Content-Type: application/x-javascript");
            client.println();
          }

          if(readString.indexOf("bluev") >=0) {
            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) {

              byte clientBuf[64];
              int clientCount = 0;             

              while (myFile.available())
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }               
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);           
              myFile.close();
            }
          }

          if(readString.indexOf("slider") >=0) {
            File myFile = SD.open("slider.js");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;             

              while (myFile.available())
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }               
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);
              myFile.close();
            }
          }

          if(readString.indexOf("bluev_sl") >=0) {
            File myFile = SD.open("bluev_sl.gif");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;             

              while (myFile.available())
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }               
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);
              myFile.close();
            }
          }

          if(readString.indexOf("bluev_bg") >=0) {
            File myFile = SD.open("bluev_bg.gif");
            if (myFile) {

              byte clientBuf[64];
              int clientCount = 0;             

              while (myFile.available())
              {
                clientBuf[clientCount] = myFile.read();
                clientCount++;

                if(clientCount > 63)
                {
                  client.write(clientBuf,64);
                  clientCount = 0;
                }               
              }
              if(clientCount > 0) client.write(clientBuf,clientCount);
              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="";
        }
      }
    }
  }
}

Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Offline Offline
Newbie
*
Karma: 0
Posts: 17
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Slightly different approach, learned something again so thanks!

A
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey guys,
Using this code and it works great. The one problem I have with it is, I'm using it with a text file, and spitting that out instead of HTML. The problem with this is, unlike when I spit the same data out over serial, when I do it with this code to send it to the requesting client, it doesn't preserve linebreaks and so my text file is coming out all on one line. Kind of unreadable!
 
Any ideas?
Thanks
Tk

Code:
myFile = SD.open("beeest.txt");
    if (myFile) {
                        while(aantal = myFile.available()) {
                            if (aantal > 63) {
                              myFile.read(buf, 64);
                              client.write(buf, 64);
                            }
                            else {
                              myFile.read(buf, aantal);                             
                              client.write(buf, aantal); // send web page to client
                            }
                        }
                        myFile.close();
                }
         
Logged

0
Offline Offline
Tesla Member
***
Karma: 141
Posts: 9555
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How are you viewing the received text?
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Miramar Beach, Florida
Offline Offline
Faraday Member
**
Karma: 144
Posts: 5986
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you want to view text files on a web browser...
Code:
// change this
client.println("Content-Type: text/html");
// to this
client.println("Content-Type: text/plain");
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The earlier part of the code sends HTML tags to display a basic website. I suppose this is why it's not preserving the line breaks? Because I'm sending HTML, then straight away sending plaintext with no tags for nextline, etc? I guess that may be the issue.
Logged

0
Offline Offline
Tesla Member
***
Karma: 141
Posts: 9555
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Below is a text file on an apache server that usually downloads and displays on IE with the lines as they are in the text file. 

http://web.comporium.net/~shb/arduino.txt
Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Pages: [1]   Go Up
Jump to: