Hi All,
I'm having some issues making a webserver that is able to host pages that reference different files hosted on the server.
i.e. my webpage (index.htm) references several .css and .js files.
I have Arduino code that interprets the incoming GET commands from the client, and responds with the correct file.
When I reference one or two small files, it works great.
It's when I start referencing more/larger files that I get the issue.
On my client,I used the inspect feature in Chrome to try and see what's happening.
I've attached a screenshot from that to this post.
It shows that index.htm, styls.css and icon32.png are all being received OK.
It also shows that menu.js and livedata.js are not being received.
If I refresh the page multiple times, occasionally one of the .js files will be received OK, so I don't believe the issue is down to how my server interprets GET requests for .js files.
I get the feeling that the client is sending a request for all the files at the same time, and the Arduino is just responding to the last one. If this is the issue, I was hoping there is a way i can specify the the client to wait for the last file to be received before sending the next request.
I guess another option would be to periodically read the incoming GET requests and line them up in a buffer. That might require some sort of interrupt that will trigger even when the server is in the process of writing the file to the client. I wanted to avoid this if possible.
My code is broken down into three files.
The first file holds the setup and loop functions. These call other functions within separate Ethernet and SD Card files.
Setup/Loop Function File:
#include <SPI.h>
#include <Ethernet2.h>
#include <SD.h>
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println("Starting now!");
setupSd();
setupEthernet();
}
void loop() {
runWebServer();
}
Ethernet File:
// Define ETHERNET Variables
#define BUFSIZ 100 //Line buffer size (Max chars on one line of SD card files)
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //MAC Address
IPAddress dnServer(192, 168, 0, 1); // DNS server ip
IPAddress gateway(192, 168, 0, 1); // Router's gateway address:
IPAddress subnet(255, 255, 255, 0); // Subnet:
IPAddress ip(192,168,0,50); // IP address
EthernetServer server(80); // HTTP port (80 is standard for http)
// Function to setup Ethernet
void setupEthernet() {
Serial.println("Starting ethernet");
Ethernet.begin(mac,ip, dnServer, gateway, subnet);
// start listening for clients
server.begin();
//print out the ip address
Serial.print("Server IP Address = ");
Serial.println(Ethernet.localIP());
}
//Function to run webserver
void runWebServer() {
char clientline[BUFSIZ];
char name[17];
int index = 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;
// Print it out for debugging
Serial.println();
Serial.println(clientline);
// Look for substring such as a request to get the file
if (strstr(clientline, "GET /") != 0) {
// this time no space after the /, so a sub-file!
char *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;
if(filename[strlen(filename)-1] == '/') { // Trim a directory filename
filename[strlen(filename)-1] = 0; // as Open throws error with trailing /
}
Serial.print(F("Web request for: ")); Serial.println(filename); // print the file being requested
File file = SD.open(filename, O_READ);
if ( file == 0 ) { // Opening the file with return code of 0 is an error in SDFile.open
client.println("HTTP/1.1 404 Not Found");
client.println("Content-Type: text/html");
client.println();
client.println("<h2>File Not Found!</h2>");
client.println("
<h3>Couldn't open the File!</h3>");
break;
}
Serial.print("File Opened: ");
Serial.println(filename);
client.println("HTTP/1.1 200 OK");
if (file.isDirectory()) {
Serial.println("is a directory");
//file.close();
client.println("Content-Type: text/html");
client.println();
client.print("<h2>Files in /");
client.print(filename);
client.println(":</h2>");
ListFiles(client,LS_SIZE,file);
file.close();
} else {
// Any non-directory clicked, server will send file to client for download
byte fileType = getFiletype(filename);
if (fileType == 1) client.println("Content-Type: text/html");
if (fileType == 2) client.println("Content-Type: text/css");
if (fileType == 3) client.println("Content-Type: text/javascript");
if (fileType == 4) client.println("Content-Type: text/x-icon");
if (fileType == 5) client.println("Content-Type: image/png");
client.println("Connection: close");
client.println();
char file_buffer[16];
int avail;
while (avail = file.available()) {
int to_read = min(avail, 16);
if (to_read != file.read(file_buffer, to_read)) {
break;
}
client.write(file_buffer, to_read);
}
file.close();
Serial.println("File was sent to client");
}
} else {
// everything else is 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();
}
}
void ListFiles(EthernetClient client, uint8_t flags, File dir) {
client.println("<ul>");
while (true) {
File entry = dir.openNextFile();
// done if past last used entry
if (! entry) {
// no more files
break;
}
// print any indent spaces
client.print("<li><a href=\"");
client.print(entry.name());
if (entry.isDirectory()) {
client.println("/");
}
client.print("\">");
// print file name
client.print(entry.name());
if (entry.isDirectory()) {
client.println("/");
}
client.print("</a>");
client.println("</li>");
entry.close();
}
client.println("</ul>");
}
byte getFiletype(char* filename) {
int8_t len = strlen(filename);
byte result;
if (strstr(strlwr(filename + (len - 4)), ".htm"))
{
return 1;
}
else if (strstr(strlwr(filename + (len - 4)), ".css"))
{
return 2;
}
else if (strstr(strlwr(filename + (len - 3)), ".js"))
{
return 3;
}
else if (strstr(strlwr(filename + (len - 4)), ".ico"))
{
return 4;
}
else if (strstr(strlwr(filename + (len - 4)), ".png"))
{
return 5;
}
else
{
return 0;
}
return result;
}
A lot of code came from other posts on the Arduino Forums. Thanks to those I've taken it from!
Am I barking up the wrong tree? Does anyone have any advice on how I might be able to fix this issue?
This is my first post, so please go easy on me!
I'm using an ATmega32U4 based microcontroller together with Ethernet and SD card modules.
The ethernet module is a W5500 that looks like this: