I am using the Webduino port to implement a web server on the Spark Core. This works quite well with a few elements but seems to hang if the html code grows beyond 10 or 15 lines.
Is this a limitation to the Core or is it a limitation to the software?
Can the Core handle a more complex web server?
One of the problems on Spark (and Arduino) is that client.print("this is some data"); produces a network packet for each character in the string by default.
I know that this is getting fixed but in the mean time you can try sending your data using the client.write(buf, len); method instead. If you look around here in the forum you will find others have tried that it worked out for them.
I attempted the change but my browser timed out. I’m not sure if I implemented it properly. I’ve got a fairly shaky grasp of web servers so I modified some example code from the Webduino library. This is what I have so far:
#include "application.h"
#include "WebServer/WebServer.h"
#include "SparkIntervalTimer/SparkIntervalTimer.h"
SYSTEM_MODE(AUTOMATIC);
#define PREFIX "/buzz"
WebServer webserver(PREFIX, 80);
String index_part1("<!DOCTYPE html> <html> <head> <title>Uni Web UI Mobile</title> <link rel='icon' type='image/png' href='images/icon.ico'> <style> html, body { background-color: blue; padding:0; margin:0; height:100%; } </style> </head> <body> <table> <tr> <th></th> <th>Start Time</th> <th>Stop Time</th> <th>Picture Frequency</th> </tr> <tr> <td>Sunday</td> <td><input type='time' value='--:--'></td> <td><input type='time' value='--:--'></td> <td><input type='number' style='width:50px'> minutes</td> </tr> <tr> <td>Monday</td> <td><input type='time' value='--:--'></td> <td><input type='time' value='--:--'></td> <td><input type='number' style='width:50px'> minutes</td> </tr> <tr> <td>Tuesday</td> <td><input type='time' value='--:--'></td> <td><input type='time' value='--:--'></td> <td><input type='number' style='width:50px'> minutes</td> </tr> <tr> <td>Wednesday</td> <td><input type='time' value='--:--'></td> <td><input type='time' value='--:--'></td> <td><input type='number' style='width:50px'> minutes</td> </tr> <tr> <td>Thursday</td> <td><input type='time' value='--:--'></td> <td><input type='time' value='--:--'></td> <td><input type='number' style='width:50px'> minutes</td> </tr> <tr> <td>Friday</td> <td><input type='time' value='--:--'></td> <td><input type='time' value='--:--'></td> <td><input type='number' style='width:50px'> minutes</td> </tr> <tr> <td>Saturday</td> <td><input type='time' value='--:--'></td> <td><input type='time' value='--:--'></td> <td><input type='number' style='width:50px'> minutes</td> </tr> </table> </body> </html>");
int timeLapse = 0;
void timeCmd(WebServer &server, WebServer::ConnectionType type, char *, bool)
{
if (type == WebServer::POST)
{
bool repeat;
char name[16], value[16];
do
{
repeat = server.readPOSTparam(name, 16, value, 16);
/* this is a standard string comparison function. It returns 0
* when there's an exact match. We're looking for a parameter
* named "buzz" here. */
if (strcmp(name, "buzz") == 0)
{
/* use the STRing TO Unsigned Long function to turn the string
* version of the delay number into our integer timeLapse
* variable */
timeLapse = strtoul(value, NULL, 10);
EEPROM.write(0, timeLapse);
}
} while (repeat);
// after procesing the POST data, tell the web browser to reload
// the page using a GET method.
server.httpSeeOther(PREFIX);
return;
}
/* for a GET or HEAD, send the standard "it's all OK headers" */
server.httpSuccess();
/* we don't output the body for a HEAD request */
if (type == WebServer::GET)
{
server.write((uint8_t*)index_part1.c_str(),index_part1.length());
}
}
int ledPin = D7;
int pushButton = D5;
int blinkCount = 0;
IntervalTimer myTimer;
// Pre-define ISR callback functions
void blinkLED(void);
// Callback for Timer 1
void blinkLED(void) {
blinkCount++;
}
/* This function is called once at start up ----------------------------------*/
void setup()
{
webserver.setDefaultCommand(&timeCmd);
webserver.begin();
// Digital I/O
pinMode(ledPin, OUTPUT);
pinMode(pushButton, INPUT);
// AUTO allocate blinkLED to run every 500ms (1000 * .5ms period)
myTimer.begin(blinkLED, 2000, hmSec);
timeLapse = EEPROM.read(0);
}
void loop()
{
// process incoming connections one at a time forever
webserver.processConnection();
if (blinkCount >= timeLapse)
{
blinkCount = 0;
digitalWrite(ledPin, HIGH);
delay(100);
}else
{
digitalWrite(ledPin, LOW);
}
}
I am not sending any POST data in this example so it’s mainly just supposed to spit out a webpage when a GET request is sent from a browser.
You can save RAM by making your index_part1 a const char array instead a string (assuming you don’t need to change it) since then it will live in flash and not RAM.
It works! The original length was 1560, I broke it into two chunks and it worked without hanging. Is a 1400 byte length a general rule for serving pages on the Core?
When you are using the client.write(buf,len) interface, you are directly generating packets and the TI part has a 1468 byte limit on packet size (called the MTU setting). It should be pretty easy to write a loop to chunk up a larger array in to packets that are less than 1468 bytes each.