Webserver and html file

Hi, I experience an issue and I don't how to solve it: I'm trying to return a html page stored in the SD card. When I connect with the browser the page does not end to load. I tought the page may be too big, but I tried with a smaller one and I received a lot of number insted of html code. I post some code

void helloCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  server.httpSuccess();
  if (type == WebServer::HEAD)
    return;
    readFile("arduino.htm", server);
    //server.print("vediamo se lo scrive"); //IS WORKING WELL
}
void readFile(char* nomeFile, WebServer &server)
{
  if (SD.exists(nomeFile))
  {
    File file;
    
    file = SD.open(nomeFile);
    if (file)  {
      while (file.available())
      {
        //server.write(file.read()); NOT WORK
        server.print(file.read()); NOT WORK
      }
      file.close();
    }
  }else{
    Serial.println("file does not exist");
  }
}

How can I send the response to the client?

There are several problems with that snippet you posted. First, it's impossible to guess what types a number of the instances are. Seeing the whole code, including the #include statements is neccessary.

Second, sending one character at a time in a packet to the client is really not a good idea. Read and buffer a number of characters, and send the whole buffer in one packet.

Third: "it doesn't work" gives us nothing to go on. You are reading data from the file, presumably, though you don't echo to the serial port to confirm that. You don't say what happens on the client end. It's hard to fix issues when we don't know what the problem is.

Simply echoing to the serial monitor each byte read from the file would enable you to get a much better understanding of what your sketch is doing.

PaulS: There are several problems with that snippet you posted. First, it's impossible to guess what types a number of the instances are. Seeing the whole code, including the #include statements is neccessary.

sorry for few information I posted, I'm going to post the whole sketch:

declaration

#include "SPI.h"
#include "Ethernet.h"
#include "WebServer.h"
#include "aJSON.h"
#include "SD.h"
#define NAMELEN 32
#define VALUELEN 32

static uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
static uint8_t ip[] = { 192, 168, 1, 210 };
int inByte;
char c;

WebServer webServer("", 80);
void readFile(char* nomeFile, WebServer &server)
{
  if (SD.exists(nomeFile))
  {
    File file;
    
    file = SD.open(nomeFile);
    if (file)  {
      while ((c = file.read()) > 0)
      {
        //server.write(file.read());
        server.print((char)c);
      }
      file.close();
    }
  }else{
    Serial.println("il file non esiste");
  }
}
void helloCmd(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
  server.httpSuccess();
  if (type == WebServer::HEAD)
    return;
    readFile("prova.htm", server);
    //server.print("vediamo se lo scrive");
}
void loop()
{
  char buff[64];
  int len = 64;
  webServer.processConnection(buff, &len);
}
void setup() 
{
  Ethernet.begin(mac, ip);
  webServer.setDefaultCommand(&helloCmd);
  webServer.addCommand("jsonStatus", &sendJsonString);
  webServer.begin();
  SD.begin(4);
  Serial.begin(9600);
}

PaulS: Second, sending one character at a time in a packet to the client is really not a good idea. Read and buffer a number of characters, and send the whole buffer in one packet.

I realize now that my sketch is sending one packet per byte, how can I buffer a number of chars without full the ram?

PaulS: Third: "it doesn't work" gives us nothing to go on. You are reading data from the file, presumably, though you don't echo to the serial port to confirm that. You don't say what happens on the client end. It's hard to fix issues when we don't know what the problem is.

I tryed to explain what happen but the behaviour is strange and not constant: after downloading, the first page request is slow but it is a success, after some request arduino answer with a part of the page and we reach last point where arduino does not answer anymore.

PeterH: Simply echoing to the serial monitor each byte read from the file would enable you to get a much better understanding of what your sketch is doing.

The serial monitor print correctly the content of the file, even when a part of the webpage is loaded.

how can I buffer a number of chars without full the ram?

The read() method has two forms:

  virtual int read();
  int read(void *buf, uint16_t nbyte);

The first, that you are using, returns one character (or an error). The second returns the number of characters stored in the buffer that is the first argument. The second argument is the size of the buffer.

char fileBuf[81];

int charCnt = file.read(fileBuf, 80);
fileBuf[charCnt] = '\0';
server.write(fileBuf, charCnt);

Thanks, it is working almost fine, following the code:

char buffer[500];
int charCnt;
file.open(&root, "arduino.htm", O_READ);
while ((charCnt = file.read(buffer, 499)) > 0) {
   buffer[charCnt] = '\0';
   client.write(buffer);
}

I also changed the sketch to another that fill the memory for 23000 bytes compared with previous of 29000.
I used the sketch in this page Arduino Tutorials - Ethernet+SD, but I’m experiencing an issue when I have to respond a request of json string, I post the code:

#include "SPI.h"
#include "Ethernet.h"
#include "SD.h"

#define NAMELEN 32
#define VALUELEN 32

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

char buffer[500];
int charCnt;

Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

typedef enum URLPARAM_RESULT { URLPARAM_OK, URLPARAM_NAME_OFLO, URLPARAM_VALUE_OFLO, URLPARAM_BOTH_OFLO,URLPARAM_EOS };

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))
void setup() {
  Serial.begin(9600);
 
  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();
}
void loop()
{
  char clientline[BUFSIZ];
  int index = 0;
  char name[NAMELEN];
  char value[VALUELEN];  

  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;
        
        // 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) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          file.open(&root, "arduino.htm", O_READ);
          while ((charCnt = file.read(buffer, 499)) > 0) {
              // uncomment the serial to debug (slow!)
              //Serial.print((char)c);
              buffer[charCnt] = '\0';
              client.write(buffer);
          }
          file.close();
        } else if (strstr(clientline, "GET /") != 0) {
            char *filename;
            char *url_param;
            
            url_param = strstr (clientline,"?") + 1;
            (strstr(url_param, " HTTP"))[0] = 0;
//            filename = clientline + 16; 
//            (strstr(clientline, " HTTP"))[0] = 0;
            
            int rc;
            char parametri[4];
            if (strlen(url_param))  
            {
              int j = 0;
              while (strlen(url_param))
              {
                rc = decodeURLparam(&url_param, name, NAMELEN, value, VALUELEN);
                if (rc != 0)  
                {
                  parametri[j] = value[0];
                  j = j + 1;
                }
              }
            }
            writeIO(parametri[0], (int)parametri[1], (int)parametri[2]);
            
**********| THIS PART SEEMS TO HAVE SOME PROBLEM |**********************
            //client.println("HTTP/1.1 200 OK");
            //client.println("Content-Type: text/html");
            //client.println();
            client.println("{di:[{pin:2,v:0},{pin:3,v:1},{pin:4,v:1}]}");
*************************************************************
        } else {
          // everything else is a 404
          client.println("HTTP/1.1 404 Not Found");
          client.println("Content-Type: text/html");
          client.println();
          client.println("<h2>File Not Found!</h2>");
        }
        break;
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }
}

When I request the page by browser I receive the right response, but from an AJAX call ajax script cannot connect to that page. If I copy the page content in a text file and try from ajax to connect is working fine. In my opinion the content type of the response should be configured properly but if I remove the comments from the following lines

          lient.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");

and I try to connect by browser I don’t receive anything, blank page.
I tryed to change the content-type (text/html, text/json, application/json, text/plain), nothing change.

I also changed the sketch to another that fill the memory for 23000 bytes compared with previous of 29000.

What does this mean? No Arduino has 29000 bytes of memory for you to fill. Or even 230000.

  char clientline[BUFSIZ];

Where is BUFSIZ defined?

You seem to have some fundamental misconception about just how much memory you have available. Until you recognize that the Arduino doesn't have 4Gig of real memory and nearly unlimited amounts of virtual memory, you will continue to have problems.

I cannot say the opposite, I read this link http://www.arduino.cc/playground/Learning/Memory and I understand that 32k are available for User Program. The previous sketch was filling flash for 29k and the new one for 23k. This has been the reason of change. Because,in future, I will may want to copy some variable in the flash memory with avr/pgmspace.h library using strcpy_P function to keep the SRAM free.

Sorry for BUFSIZE

#define BUFSIZ 100

The previous sketch was filling flash for 29k and the new one for 23k.

Ah, that makes more sense.

            (strstr(url_param, " HTTP"))[0] = 0;

This is not how I would NULL terminate url_param.

            if (strlen(url_param))  
            {
              int j = 0;
              while (strlen(url_param))
              {

The strlen() function does not return a boolean. It’s better if you explicitly define if what and while what.

**********| THIS PART SEEMS TO HAVE SOME PROBLEM |**********************
            //client.println("HTTP/1.1 200 OK");
            //client.println("Content-Type: text/html");
            //client.println();
            client.println("{di:[{pin:2,v:0},{pin:3,v:1},{pin:4,v:1}]}");
*************************************************************

Aside from the fact that it won’t even compile?

What problem? You are sending a literal string to the client instance. How is that causing the Arduino a problem?

Using the SD class requires a 512 character buffer. The Ethernet class needs some memory. The 500 character array, buffer, takes nearly a quarter of the available SRAM. The 100 character array, clientline, uses up a lot of the remaining memory. I’d hazard a guess that you are running out of memory.

There is still code you haven’t posted. What does writeIO() do? What does decodeURLparam() do?