Webserver from SD card and picture problem

I'm using webserver from SD card :

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10,20,90,66);
File htmlFile;
EthernetServer server(80);

void setup()
{
Serial.begin(9600);
Ethernet.begin(mac, ip);
server.begin();
if (!SD.begin(4)) { return; }
}
void loop()
{
EthernetClient client = server.available();
if (client) {
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n' && currentLineIsBlank) {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
Serial.print("OteviRm index.htm");
htmlFile = SD.open("index.htm");
if (htmlFile) {
while (htmlFile.available()) {
client.write(htmlFile.read());
}
// close the file:
htmlFile.close();
}
break;
}
if (c == '\n') {
currentLineIsBlank = true;
}
else if (c != '\r') {
currentLineIsBlank = false;
}
}
}
delay(1);
client.stop();
}
}

Into index.htm I can write my HTML code, but question is how display on webserver also jpg picture from SD card.
If I will write into index.htm : and file picture.jpg I will copy to root of SD card, webserver will not show this picture - only square with cross.

What's wrong ?

Thanks for help

Alda

You don't even read what the client is sending to you so you cannot parse it too. In the client's request it specifies what resource (file) it wants, you don't care and just send the HTML file. You have to parse the client's request, at least the first line, else you won't be able to serve more than the current HTML file.

If you search for Webduino on Google you'll find a webserver for Arduino that is probably doing what you wanna do.

Yes, I made a update to :

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

/************ ETHERNET STUFF ************/
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10,20,90,66);
char rootFileName[] = "index.htm";
EthernetServer server(80);

/************ SDCARD STUFF ************/
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))

void error_P(const char* str) {
PgmPrint("error: ");
SerialPrintln_P(str);
if (card.errorCode()) {
PgmPrint("SD error: ");
Serial.print(card.errorCode(), HEX);
Serial.print(',');
Serial.println(card.errorData(), HEX);
}
while(1);
}

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

PgmPrint("Free RAM: ");
Serial.println(FreeRam());

// initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
// breadboards. use SPI_FULL_SPEED for better performance.
pinMode(10, OUTPUT); // set the SS pin as an output (necessary!)
digitalWrite(10, HIGH); // but turn off the W5100 chip!

if (!card.init(SPI_HALF_SPEED, 4)) error("card.init failed!");

// initialize a FAT volume
if (!volume.init(&card)) error("vol.init failed!");

PgmPrint("Volume is FAT");
Serial.println(volume.fatType(),DEC);
Serial.println();

if (!root.openRoot(&volume)) error("openRoot failed");

// list file in root with date and size
PgmPrintln("Files found in root:");
root.ls(LS_DATE | LS_SIZE);
Serial.println();

// Recursive list of all directories
PgmPrintln("Files found in all dirs:");
root.ls(LS_R);

Serial.println();
PgmPrintln("Done");

// Debugging complete, we start the server!
Ethernet.begin(mac, ip);
server.begin();
}

// How big our line buffer should be. 100 is plenty!
#define BUFSIZ 100

void loop()
{

char clientline[BUFSIZ];
char *filename;
int index = 0;
int image = 0;

EthernetClient client = server.available();
if (client) {
// an http request ends with a blank line
boolean current_line_is_blank = true;

// reset the input buffer
index = 0;

while (client.connected()) {
if (client.available()) {
char c = client.read();

// If it isn't a new line, add the character to the buffer
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;
filename = 0;

// Print it out for debugging
Serial.println(clientline);

// Look for substring such as a request to get the root file
if (strstr(clientline, "GET / ") != 0) {
filename = rootFileName;
}
if (strstr(clientline, "GET /") != 0) {
// this time no space after the /, so a sub-file

if (!filename) filename = clientline + 5; // look after the "GET /" (5 chars)
// a little trick, look for the " HTTP/1.1" string and
// turn the first character of the substring into a 0 to clear it out.
(strstr(clientline, " HTTP"))[0] = 0;

// print the file we want
Serial.println(filename);

if (! file.open(&root, filename, O_READ)) {
client.println("HTTP/1.1 404 Not Found");
client.println("Content-Type: text/html");
client.println();
client.println("

File Not Found!

");
break;
}

Serial.println("Opened!");

client.println("HTTP/1.1 200 OK");
if (strstr(filename, ".htm") != 0)
client.println("Content-Type: text/html");
else if (strstr(filename, ".css") != 0)
client.println("Content-Type: text/css");
else if (strstr(filename, ".png") != 0)
client.println("Content-Type: image/png");
else if (strstr(filename, ".jpg") != 0)
client.println("Content-Type: image/jpeg");
else if (strstr(filename, ".gif") != 0)
client.println("Content-Type: image/gif");
else if (strstr(filename, ".3gp") != 0)
client.println("Content-Type: video/mpeg");
else if (strstr(filename, ".pdf") != 0)
client.println("Content-Type: application/pdf");
else if (strstr(filename, ".js") != 0)
client.println("Content-Type: application/x-javascript");
else if (strstr(filename, ".xml") != 0)
client.println("Content-Type: application/xml");
else
client.println("Content-Type: text");

client.println();

int16_t c;
while ((c = file.read()) >= 0) {
// uncomment the serial to debug (slow!)
//Serial.print((char)c);
client.print((char)c);
}
file.close();
} else {
// everything else is a 404
client.println("HTTP/1.1 404 Not Found");
client.println("Content-Type: text/html");
client.println();
client.println("

File Not Found!

");
}
break;
}
}
// give the web browser time to receive the data
delay(1);
client.stop();
}
}

Now I can see also picture from SDcard, but my next question is - is possible insert into this webserver any line which will show me actual values ( analog values ) of andruino ?

Thanks

Alda

I have seen examples which do that. Sorry I can't find link now I'm traveling.

This works to display JPG? Great! I want to do this too! Please let me know if you have any problems with this code you provided. Because I would like to use it soon. Will you update it here with any improvements?

It's working for me without problems, now I can have all stored on SDcard, also pictures, but show picture on the webserver is quite slow.
You can also click on three places on the picture which will open other page....

But I'm still looking for improvements ( see values on the screen with picture and speed up loading )

Alda

What 3 places on picture? What is the other page? I cannot test it today.

Hello Alda,

i have downloaded your update code and turned it into a wifi shield code. It functions so somewhat with my modifications.

I don t know how do you call pictures from the sd card. Please tell me.

Many Greetings.

Rokitz.

Thanks for your advice ,,, but pictures downloading slowly when i open the webpage do u know why ?

mohamed66:
Thanks for your advice ,,, but pictures downloading slowly when i open the webpage do u know why ?

The arduino is slow compared to computer based servers.

but pictures downloading slowly when i open the webpage do u know why ?

Additionally to zoomkat's explanation there's another reason:

          int16_t c;
          while ((c = file.read()) >= 0) {
              // uncomment the serial to debug (slow!)
              //Serial.print((char)c);
              client.print((char)c);
          }

You're reading the file byte by byte and then hand it over to the Ethernet library using the print() method. This way you create a packet for every byte you want to send. This is highly inefficient. It's a drawback of the Ethernet library but there is a reason for this: the lack of memory in the Arduino forced that decision. If you create a buffer of let's say 256 bytes and read that quarter kB from the card and send it using the write() method you will get faster (but not fast) responses.

Some discussion of interest below.

http://arduino.cc/forum/index.php/topic,134868.0.html

Je mets le code complet (Je débute donc c'est peut être pas très propre :blush:) mais ce qui me surprend c'est que ce code "allegé" ne marche pas tout de suite. Il faut le transferer 2 ou 3 fois avant que ca remarche...juste transferer 2 ou 3 fois sans rien modifier...

//**********************************************************************************************************************************
//**********************************************************************************************************************************



#include <Ethernet.h>
#include <SD.h> // crée automatiquement un objet racine SD représentant la carte mémoire SD
#include <SPI.h>



/* Détails technique de la connexion ethernet */
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 
  192,168,1, 177 };
byte gateway[] = { 
  192,168,1, 1 };

// Attachement d'un objet "server" sur le port 1337
EthernetServer server(80);






//**********************************************************************************************************************************
//**********************************************************************************************************************************

void setup()
{

  // Variables d'Usage
  int Resultat_fct = false;
  
  // Initialisation port serie
  Serial.begin(115200);
  
  // Affichage de la SRAM utilisée
//  Serial.print(F("Memoire SRAM restante :"));
//  Serial.println(freeRam());

  // Affectation des directions pins
  pinMode(53, OUTPUT); // broche de selection WIZNET
  pinMode(4, OUTPUT); // broche de selection SD card
  digitalWrite(4,LOW);
  digitalWrite(53,HIGH);
 
  // Initialisation de la carte SD avec broche 4 en tant que CS
  Resultat_fct=SD.begin(4); 
  if (Resultat_fct!=true) 
  { 
    Serial.println(F("Echec initialisation SD!"));
  }
  
  delay(1000);
  
  // Initialisation de la librairie ethernet
  Ethernet.begin(mac, ip, gateway);
  server.begin();

} 

//**********************************************************************************************************************************
//          MAIN
//**********************************************************************************************************************************

void loop()
{ 
      // Scrutation reseau
      Com_reseau();
} 

//**********************************************************************************************************************************
//          FONCTION COMMUNICATION RESEAU
//**********************************************************************************************************************************

void Com_reseau()
{ 

   //_____________________________________________________________________________________
  
   // Variables d'usage
   String chaineRecue="";           // réception chaine requete
   int comptChar=0;                 // comptage des caractères reçus
   int resultat_SD=0;               // resultat fonction lecture carte SD
   int index_paquet=0;              // numéro de ligne à lire dans la carte SD
   int datas[150];               // ligne lue dans la carte SD
   char c;                          // caractère récupéré par Ethernet
   
  //_____________________________________________________________________________________

   // Crée un objet client basé sur le client connecté au serveur
   EthernetClient client = server.available();
  
  // si l'objet client n'est pas vide
  if (client)
  { 
      // si le client est connecté
      if (client.connected()) 
      { 
            
            //_____________________________________________________________________________________
            
            // Initialisation variables
            comptChar = 0;
            chaineRecue = "";
            
            // Boucle sur reception client
            while (client.available()) 
            { 
              
              // l'octet suivant reçu du client est mis dans la variable c 
              c = client.read();
              
              // incrémente le compteur de caractère reçus
              comptChar=comptChar+1; 

              // Concatenation caractere dans une chaine dans une limite de 50 caracteres
              if (comptChar<50)
              {
                  chaineRecue=chaineRecue+c;
              }
              
            }
            
             //_____________________________________________________________________________________
            
             // Chaine reçue est une requete GET alors affichage page Web
             if (chaineRecue.startsWith("GET / HTTP")) 
             { 
                  // Lecture carte SD et affichage page Web
                  while (resultat_SD!=1 && resultat_SD<100) // Tant que pas fin de fichier texte et pas d'erreur
                  {
                      resultat_SD = Lecture_ligne_SD(index_paquet,"/Web/Image.txt",datas);
                      int idx=0;
                      while(idx<150 && datas[idx]>0)
                      {
                          if (datas[idx]>0)
                          {
                            client.print((char)datas[idx]);
                            idx++;
                          }
                      }
                      index_paquet++;
                  }              
             }
          
            
            //_____________________________________________________________________________________
                   
            // Attente et libération client     
            delay(1); 
            client.stop();
 
            //_____________________________________________________________________________________
                        
      }  
    
  }     
      
      
} 

//**********************************************************************************************************************************
//          FONCTION DE RECUPERATION D'UNE LIGNE DANS UN FICHIER TXT D'UNE CARTE SD
//**********************************************************************************************************************************

int Lecture_ligne_SD(int index_paquet,char path[20], int tableau[150])
{

    //_____________________________________________________________________________________
  
    // Variables d'Usage
    int File_exist=0;
    File myFile; // objet file

    //_____________________________________________________________________________________
    
    // Selection de la SD Card
    digitalWrite(53,HIGH);
    digitalWrite(4,LOW);
    
    //_____________________________________________________________________________________
    
    // Test si le fichier existe - renvoie true/false
    File_exist=SD.exists(path); 

     // Si fichier n'existe pas    
     if (File_exist!=true)  
     { 
       return 100;
     }
     // Si fichier existe
     else 
     { 
         
          // Ouverture du fichier en lecture 
          myFile=SD.open(path,FILE_READ);
          myFile.seek(index_paquet*150);

          for (int index=0;index<=150;index++)
          {
             tableau[index] = 0;
          }
          
          for (int index_c_ec=0;index_c_ec<150;index_c_ec++)
          {
             tableau[index_c_ec] = myFile.read();

             if (tableau[index_c_ec]<0)
             {
                 //tableau[index_c_ec]=0;
                 return 1;
             }
          }
          return 2;
    
     }            

     
    //_____________________________________________________________________________________
 
    // Selection du Wiznet
    digitalWrite(53,LOW);
    digitalWrite(4,HIGH);  
    
    //_____________________________________________________________________________________
    
}


//**********************************************************************************************************************************
//          FONCTION LECTURE SRAM UTILISEE
//**********************************************************************************************************************************

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

Oops Sorry I post here by error :astonished:

I have tried the code but it doesn't show the picture from sd.
In which directory a jpg picture must be placed?

As far as I can understand, the web server as it is, is rather minimal, yet enough for many simple applications.
For an application I am working on (on Mega and Ethernet shield) I preferred to develop something more systematic and complete. You can find it at An HTTP Server for Arduino Mega with file upload/download and AJAX capabilities - Networking, Protocols, and Devices - Arduino Forum, where I posted what I have done.
If you are working on UNO, it needs to be downsized a bit, anyway you may take it as a starting point.
HTH,
eca