DKWatson:
String msgField[25];
String fullMsg = "";
Not just String, not just arrays of String, but unsafe array usage. Sigh. If only there were a better way to parse GPS data...
@benskylinegodzilla, here are two ways to watch for the magic ColVal in the incoming stream of bytes. Both sketches use Serial for the client so you can simply paste the HTTP request into the Serial Monitor window and press Send.
Line-oriented processing with C string functions
One line is accumulated at a time. Then the line is searched with strstr for the special match string. If a match is found, it steps over the match string to the value characters and uses atoi to convert the digits into an int.
Once the match string and color value are found, it skips the rest of the request until the two newlines are found.
#define client Serial
void setup()
{
client.begin( 9600 );
}
const char match[] = "GET /HourRed/ColVal="; // watch for this
uint8_t redColorValue = 0;
void loop()
{
if (client.available())
{
char c = client.read();
Serial.write(c); // echo for testing
if (parseRequest( c )) {
sendResponse();
}
}
}
// Some variables to receive a line of characters
const size_t MAX_CHARS = 64;
char line[ MAX_CHARS ];
size_t count = 0;
bool previousWasNewline = false;
bool colorReceived = false;
bool parseRequest( char c )
{
bool isNewline = (c == '\n');
// Only pay attention until a color value is received. Then ignore.
if (not colorReceived) {
if (not isNewline) {
// Only save the printable characters, if there's room
if ((' ' <= c) and (count < MAX_CHARS-1)) {
line[ count++ ] = c;
}
} else {
// The newline is here, line completely received
line[count] = '\0'; // terminate the string
count = 0; // reset for next time
// See if it is the special string
char *found = strstr( line, match );
if (found != nullptr) {
// The value is after the match string. Start at the
// found position and step by the match string length.
char *colorValuePtr = &found[ sizeof(match)-1 ];
// Convert the next characters to an int value.
// atoi stops at the first non-digit.
redColorValue = atoi( colorValuePtr );
colorReceived = true;
// Do something with the value now? Look at it later?
Serial.print( "\nRed Color Value = " );
Serial.println( redColorValue );
}
}
}
bool done = (isNewline and previousWasNewline) and colorReceived;
if (done) {
// Reset a few things
colorReceived = false;
previousWasNewline = false;
} else {
previousWasNewline = isNewline; // remember for next time
}
return done;
} // parseRequest
void sendResponse()
{
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK\n"
"Content-type:text/html\n"
"Connection: close\n"); // one print!
//HTML body Code goes here
client.println("<!DOCTYPE html>");
client.println("<html>");
// This is where all the HTML code is
// there is one line that says
client.print(" <a href=\"/HourRed/\" onmouseup=\"location.href=this.href+'ColVal='+sliderHourRed.value;return false;\">");
client.println( "</html>" );
//END OF HTML
// The HTTP response ends with another blank line
client.println();
}
Finite-State Machine
Instead of accumulating an entire line, it compares each character as it arrives to a "match" string. As the characters continue to match, it increments a counter. When the entire string has matched, it knows to start watching for the color value.
Again, instead of saving the complete color value string, it accumulates the color value as the digits arrive. When a non-digit character arrives, it knows that the value is complete. The rest of the response can be ignored, until two newline characters arrive.
Each character affects the FSM as it arrives. There is no reason to hold on to the entire HTTP request string.
#define client Serial
void setup()
{
client.begin( 9600 );
}
const char match[] = "GET /HourRed/ColVal="; // watch for this
size_t count = 0;
bool previousWasNewline = false;
uint8_t redColorValue = 0;
enum parsingState_t { WAITING_FOR_MATCH, GETTING_VALUE, VALUE_READY };
parsingState_t state = WAITING_FOR_MATCH;
void loop()
{
if (client.available())
{
char c = client.read();
Serial.write(c); // echo for testing
if (parseRequest( c )) {
sendResponse();
}
}
}
bool parseRequest( char c )
{
bool isNewline = (c == '\n');
switch (state) {
case WAITING_FOR_MATCH:
if (c == match[ count ]) {
count++;
if (count == sizeof(match)-1) {
// FOUND the match string
count = 0; // reset for next time
redColorValue = 0; // initial value
state = GETTING_VALUE;
}
} else {
count = 0; // didn't match, start over
}
break;
case GETTING_VALUE:
if (isdigit(c)) {
// Accumulate the red color value
uint8_t digit = c - '0';
redColorValue = redColorValue * 10 + digit;
} else {
// It wasn't a digit, so we must have all the
// color digits. The value is ready to use.
state = VALUE_READY;
// Do something with the value now? Look at it later?
Serial.print( "\nRed Color Value = " );
Serial.println( redColorValue );
}
break;
case VALUE_READY:
// Ignore the rest of the request?
break;
}
bool colorReceived;
if (isNewline and previousWasNewline) {
// End of request!
colorReceived = (state == VALUE_READY);
// reset FSM for next request
state = WAITING_FOR_MATCH;
count = 0;
previousWasNewline = false;
} else {
colorReceived = false;
previousWasNewline = isNewline; // remember for next time
}
return colorReceived;
} // parseRequest
void sendResponse()
{
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK\n"
"Content-type:text/html\n"
"Connection: close\n"); // one print!
//HTML body Code goes here
client.println("<!DOCTYPE html>");
client.println("<html>");
// This is where all the HTML code is
// there is one line that says
client.print(" <a href=\"/HourRed/\" onmouseup=\"location.href=this.href+'ColVal='+sliderHourRed.value;return false;\">");
client.println( "</html>" );
//END OF HTML
// The HTTP response ends with another blank line
client.println();
}
In either case, watching for two newline characters is actually a simple FSM. If a non-newline character is received, a flag is cleared. If a newline is received, a flag is set. If the flag was already set, you know that two newlines were received in a row. This flag is a "state" variable.
Cheers,
/dev