Arduino web server with sd

Hi all,

i run into a problem trying to setup a web server with SD card. Te problem is speed. I read already a lot of related posts and i know that Arduino is not a fastest thing out there for this porpuse. But I think that in my case is a bit more slow than it "should be". I tested it in Firebug and what I see is that it downloads data with stops and also it takes sometimes long client waiting time. I am using Mega and a wifi shield with 10 rated SD card. Here is the server part of the code which I am using (I just found it somewhere on the web). If someone could give me some insight on what is going wrong it would be grate. Thankyou in advance.

pinMode(53, OUTPUT);
digitalWrite(53, HIGH);
if (!SD.begin(4)) {
Serial.println("No se pudo iniciar tarjeta SD");
return; // SD card initialization failed
}
server.begin();
}

void loop() {
// if an incoming client connects, there will be bytes available to read:
WiFiClient client = server.available();
if (client) {
while (client.connected()) {
if (ServiceClient(client)) {
// received request from client and finished responding
break;
}
}
delay(1);
client.stop();
}
}

bool ServiceClient(WiFiClient client){
static boolean currentLineIsBlank = true;
char cl_char;
File webFile;
// file name from request including path + 1 of null terminator
char file_name[FILE_NAME_LEN + 1] = {0}; // requested file name
char http_req_type = 0;
char req_file_type = FT_INVALID;
const char *file_types[] = {"text/html", "image/x-icon", "text/css", "application/javascript", "image/jpeg", "image/png", "image/gif", "text/plain"};

static char req_line_1[40] = {0}; // stores the first line of the HTTP request
static unsigned char req_line_index = 0;
static bool got_line_1 = false;

if (client.available()) { // client data available to read
cl_char = client.read();

if ((req_line_index < 39) && (got_line_1 == false)) {
if ((cl_char != '\r') && (cl_char != '\n')) {
req_line_1[req_line_index] = cl_char;
req_line_index++;
}
else {
got_line_1 = true;
req_line_1[39] = 0;
Serial.println(req_line_1);
}
}

if ((cl_char == '\n') && currentLineIsBlank) {
// get HTTP request type, file name and file extension type index

http_req_type = GetRequestedHttpResource(req_line_1, file_name, &req_file_type);
Serial.println(file_name);
if (http_req_type == HTTP_GET) { // HTTP GET request
if (req_file_type < FT_INVALID) { // valid file type
webFile = SD.open(file_name);// open requested file
if (webFile) {
// send a standard http response header
client.println(F("HTTP/1.1 200 OK"));
client.print(F("Content-Type: "));
client.println(file_types[req_file_type]);
client.println(F("Connection: close"));
client.println();

// send web page
while(webFile.available()) {
int num_bytes_read;
char byte_buffer[64];
// get bytes from requested file
num_bytes_read = webFile.read(byte_buffer, 64);
Serial.println(num_bytes_read);
// send the file bytes to the client
client.write(byte_buffer, num_bytes_read);
}

webFile.close();
}
else {
// failed to open file
Serial.println("No puede abrir archivo");
}
}
else {
Serial.println("invalid file type");
}
}
else if (http_req_type == HTTP_POST) {
// a POST HTTP request was received
}
else {
// unsupported HTTP request received
}
req_line_1[0] = 0;
req_line_index = 0;
got_line_1 = false;
// finished sending response and web page
return 1;
}
if (cl_char == '\n') {
currentLineIsBlank = true;
}
else if (cl_char != '\r') {
currentLineIsBlank = false;
}
} // if (client.available())
return 0;

}

// extract file name from first line of HTTP request
char GetRequestedHttpResource(char *req_line, char *file_name, char *file_type)
{
char request_type = HTTP_invalid; // 1 = GET, 2 = POST. 0 = invalid
char *str_token;

*file_type = FT_INVALID;

str_token = strtok(req_line, " "); // get the request type
if (strcmp(str_token, "GET") == 0) {
request_type = HTTP_GET;
str_token = strtok(NULL, " "); // get the file name
if (strcmp(str_token, "/") == 0) {
strcpy(file_name, "temp.htm");
*file_type = FT_HTML;
}
else if (strlen(str_token) <= FILE_NAME_LEN) {
// file name is within allowed length
strcpy(file_name, str_token);
// get the file extension
str_token = strtok(str_token, ".");
str_token = strtok(NULL, ".");

if (strcmp(str_token, "html") == 0) {*file_type = 0;}
else if (strcmp(str_token, "ico") == 0) {*file_type = 1;}
else if (strcmp(str_token, "css") == 0) {*file_type = 2;}
else if (strcmp(str_token, "js") == 0) {*file_type = 3;}
else if (strcmp(str_token, "jpg") == 0) {*file_type = 4;}
else if (strcmp(str_token, "png") == 0) {*file_type = 5;}
else if (strcmp(str_token, "gif") == 0) {*file_type = 6;}
else if (strcmp(str_token, "txt") == 0) {*file_type = 7;}
else {*file_type = 8;}
}
else {
// file name too long
}
}
else if (strcmp(str_token, "POST") == 0) {
request_type = HTTP_POST;
}

return request_type;
}

Please read and follow the directions in the "How to use this forum" post. Edit your post to add code tags.

while(webFile.available()) {
num_bytes_read = webFile.read(byte_buffer, 64);
client.write(byte_buffer, num_bytes_read);
}

This is why it is painfully slow. you are printing each bit as it is read from the sd card. This is essentially the same thing as using client.print(F("stuff to print")); where it prints one bit at a time. I found the arduino mega didn't have enough SRAM to not use (F( but using (F( was to slow, so I hacked the crap out it to make it so that it worked the way I needed so I could use (F( while at the same time not loosing time to do it.

What you want to do, is create a buffer and when the buffer is full, it client prints all the chars in the buffer at once, then clears the buffer.

Here,
put something like this in the global section

int XLSChars=80;
char currentLine[XLSChars];
static byte TempNN=0;

while (webFile.available() > 0)
              { char c = webFile.available();
                currentLine[TempNN]=c;
                TempNN++;
                if (TempNN>15) // buffer is 15, if you want it bigger change this (don't go past XLSChars size without making that larger too
                { client.print(currentLine);
                  ClearcurrentLine();
                }
              }
              if (TempNN>0)
              client.print(currentLine);
              ClearcurrentLine();
            }
    webFile.close();

and add this somewhere

void ClearcurrentLine()
{
  TempNN=0;
  while (TempNN<XLSChars)
  { currentLine[TempNN]='\0';
    TempNN++;
  }
  TempNN=0;
}

@Thomas499: He is using a 64 byte buffer. This reads up to 64 bytes and returns the number read. Then it sends that many bytes over the client connection.

              while(webFile.available()) {
                num_bytes_read = webFile.read(byte_buffer, 64);
                client.write(byte_buffer, num_bytes_read);                   
              }

@Thomas499: He is using a 64 byte buffer. This reads up to 64 bytes and returns the number read. Then it sends that many bytes over the client connection.

but does it wait until the 64 byte buffer is full, or does it client print something each time a new char is found?

If your code requests 64 bytes, and the SD card has 64 or more bytes remaining in the file, it sends 64 bytes. Only the last packet may contain less than 64 bytes.