web server loading image problem

Hi folks, I'm at my wits end on this one.

When I write one byte at a time it work. I can see in the browser the image draws in line by line (SLOWLY).

 File myFile = SD.open(param_value);        // open file
        if (myFile) {
                 client.println("HTTP/1.1 200 OK");
                 if(webParser.contains(param_value, ".jpg")){
                   client.println("Content-Type: image/jpeg");
                 } else if(webParser.contains(param_value, ".gif")){
                   client.println("Content-Type: image/gif");
                 } else if(webParser.contains(param_value, ".png")){
                   client.println("Content-Type: image/png");
                 }
                 
                 client.println();
                 
                  while(myFile.available()) {
                            client.write(myFile.read());
                  }
                 

                  myFile.close();

but when I use the packet method, only a missing image icon shows up in the browser.

 byte tBuf[64];
 int clientCount = 0;
 File myFile = SD.open(param_value);        // open file
        if (myFile) {
          
                 client.println("HTTP/1.1 200 OK");
                 if(webParser.contains(param_value, ".jpg")){
                   client.println("Content-Type: image/jpeg");
                    Serial.print("JPEG!!");
                 } else if(webParser.contains(param_value, ".gif")){
                   client.println("Content-Type: image/gif");
                 } else if(webParser.contains(param_value, ".png")){
                   client.println("Content-Type: image/png");
                 }
                 
                 client.println();
                  
                 
                  while(myFile.available()) {
                        tBuf[clientCount] = myFile.read();
                        clientCount++;
                        if(clientCount > 63) {
                          
                          client.write(tBuf,64);
                          clientCount = 0;
                         
                        }
    
                  }
                  //write in any stragglers
                  if(clientCount > 0) {
                        client.write(tBuf,clientCount);
                  }
                  
                  myFile.close();

I've checked everything. The the server finds the file, there's actual data coming in but the end result on the browser is a missing image. Not sure what's going on. thanks.

Test code where you can hard code a file name and see if the file downloads and displays.

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

            byte clientBuf[64];
            int clientCount = 0;

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

              if(clientCount > 63)
              {
                // Serial.println("Packet");
                client.write(clientBuf,64);
                clientCount = 0;
              }
            }
            //final <64 byte cleanup packet
            if(clientCount > 0) client.write(clientBuf,clientCount);            
            // close the file:
            myFile.close();
          }
          delay(1);
          //stopping client
          client.stop();
          readString="";
        }
      }
    }
  } 
}

Yeah, I tried hard coding the file name too. It didn't work.

I don't know if the browser sees 'fan.jpg' differently from '/fan.jpg' . I'll have to see in the html. That's the only thing I can think of. The server is seeing and writing to the client but the client doesn't know?

zoomkat: Test code where you can hard code a file name and see if the file downloads and displays.

Ok, a file downloaded but it's not an image. Just a 'document' the same file size as the image. So it didn't write a proper image? A missing byte somewhere? like a eof byte?

In the code I posted the two lines below are probably important. The first line below tells the browser what is being sent, and the second opens a jpg file on the SD drive for sending. Note in my code the browser does not know what is being sent until the file type header and file are sent. In the arduino IDE in the line below, the URL is high lighted and I just click on it to open the browser and down load the image.

client.println("Content-Type: image/jpeg");

File myFile = SD.open("HYPNO.JPG");

//address will look like http://192.168.1.102:84 when submited

The server is on wifi. Does that matter and using port 80?

I'm just getting GET / HTTP/1.1 in the serial monitor

Beside that, I'm using you main code.

                  while(myFile.available()) {
                        tBuf[clientCount] = myFile.read();
                        clientCount++;
                        if(clientCount > 63) {

This is silly. The read function is overloaded to take an array and a size. It populates the array for you, and returns the number of bytes actually written.

//write in any stragglers
                  if(clientCount > 0) {
                        client.write(tBuf,clientCount);
                  }

You incremented clientCount (you are NOT counting clients, so that's a crappy name), so there are only actually clientCount-1 characters left to write.

The server is on wifi. Does that matter and using port 80?

If you are using a wifi shield, my code may not work as I use a w5100 ethernet shield. Below is what I get in the serial monitor when I open the serial monitor and then click on the URL in my code info header in the IDE. The default browser opens and the hypno.jpg is downloaded and displayed by IE. Note that the IE browser also requested a favorites icon.

Starting SD..ok
Ready
GET / HTTP/1.1

GET /favicon.ico HTTP/1.1

PaulS:                   while(myFile.available()) {                         tBuf[clientCount] = myFile.read();                         clientCount++;                         if(clientCount > 63) {

This is silly. The read function is overloaded to take an array and a size. It populates the array for you, and returns the number of bytes actually written.

Where is this documented?

This is from SD.h.

  int read(void *buf, uint16_t nbyte);

I didn't know about that function when I wrote that silly routine. You must take PaulS for who he is. He is the "Chuck Norris" of the forum.

But he really is a nice guy. I'm using his wifi card to attempt to get the wifi firmware debugged.

The server is on wifi. Does that matter and using port 80?

try typing WiFi.config(ip); in the void setup() section.

SurferTim: This is from SD.h.

  int read(void *buf, uint16_t nbyte);

I didn't know about that function when I wrote that silly routine. You must take PaulS for who he is. He is the "Chuck Norris" of the forum.

But he really is a nice guy. I'm using his wifi card to attempt to get the wifi firmware debugged.

yeah, I had to open up SD.h to see but I don't think it helps. Not sure what void *buf means. That's a pointer to a function? and uint16_t is too small for an image.

Well I have no idea why the WIFI isn't loading the image with the packet method. I'll load it externally (external server).

That's a pointer to a function? and uint16_t is too small for an image.

No. It's a pointer whose type is undefined. All pointers are the same size, so the pointer could point to byte or char or int or float and the function would fill the array with the specified number of bytes.

You can't send 32000 bytes in a packet, and you can't create an array, on any Arduino, with 32000 elements, so the fact that reading an image requires multiple read/send iterations is not a problem.

Well, I gave it a try and it comes up empty The typical file size is 3000.

        File myFile = SD.open(page); 
        if (myFile) {
            unsigned long fileSize = myFile.size();
            byte clientBuf[fileSize];
            Serial.println(fileSize);
            while(myFile.available()) {
                  myFile.read(clientBuf, fileSize);
            }
            client.write(clientBuf, fileSize);
        
            myFile.close();
         }

Well the fact that the below works

client.write(myFile.read());

And

client.write(tBuf,64);

doesn't work leads me to the conclusion that the wifi library client.write(array,int) has a bug. The image sent to the browser is always partial in file size with this method.

I just bought a cheap ethernet clone and will try that.

The wifi library has some bugs, but that is not one of them. I have tested that with a wifi shield and it uploads images ok. There are rather nasty 2 second delays every few seconds, but the upload always works.

The wifi library does have problems with more than one client connected at a time. That will cause the wrong file or a corrupted file to be uploaded.

            unsigned long fileSize = myFile.size();
            byte clientBuf[fileSize];

So, how big is this array supposed to be? How much SRAM do you have? They didn’t let the super-secret 2 terabyte model out, did they?

PaulS:             unsigned long fileSize = myFile.size();             byte clientBuf[fileSize];

So, how big is this array supposed to be? How much SRAM do you have? They didn't let the super-secret 2 terabyte model out, did they?

heh, it was only for fun. It was your suggestion after all.

SurferTim: The wifi library has some bugs, but that is not one of them. I have tested that with a wifi shield and it uploads images ok. There are rather nasty 2 second delays every few seconds, but the upload always works.

The wifi library does have problems with more than one client connected at a time. That will cause the wrong file or a corrupted file to be uploaded.

Yeah, the more I use the wifi, the less I like it. I'm switching to the ethernet board. If they made the yun on a Mega board, it would be great.

heh, it was only for fun. It was your suggestion after all.

I never suggested that you could read the whole file at once.