I'm an old web programmer. I spent many years writing PERL and PHP and eventually I got burned out. But on rare occasion, I get an idea that I want to try and dust off the old code writing tools. My c++ game is weak, I admit.
I need to parse a GET string into useful data. I've come to terms with the fact that I'm limited to single character parameter names in order to make the code efficient and avoid the String class. That's fine. I'm only looking to handle a half dozen parameters at most.
But the value can not be limited to a single integer. The value may be 2 it may be 2000 or it may be 0.002 (not implemented in the code, but definitely feasible)
After several days of failure, frustration and useless google results (every other attempt I've read uses String), I think I have something that works. But I'm not convinced it's the best way.
The end goal is to pass data via WiFi to the Arduino via HTTP requests and have it send a response back as JavaScript code, most likely altered variables at which point, the browser would execute a new action based on the response.
Pretend we have a bi-ped robot.
Sample HTTP request: "GET /action?s=45&d=90 HTTP/1.1 (more lines for host etc.)". Hypothetical action "turn 90 degrees, take 45 steps and wait for the next command. It would be up to the browser to determine that if you should walk 45 steps then turn, the command would be "...s=45&d=0" followed by "s=0&d=90" Or maybe the Arduino would walk in an arc taking one step and then turning 2 degrees before the next step for the combined request... I haven't thought that far into this example. Throughout the walk, the browser would check in on the arduino to see if it's done yet. This request would be "GET /info?o=1 HTTP/1.1". Every few seconds, it asks "are you done yet?" and the arduino would respond accordingly. (currently returning the arduino clock for example purposes)
What I'd like to know is iterating over the GET request one character at a time and acting on each character the best way to handle a string of data without using a String?
Secondly, is there any way to work with the 80-character GET_str that doesn't require the code to make sure it's not simply a shorter string than 80 characters and stop the iteration in a for loop? Is a
while (i<sizeof(x) && x[i] != NULL){
...
i++;
}
the only other option?
#include <ESP8266WiFi.h>
const char* ssid = "Verizon";
const char* password = "12345678";
// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);
void setup() {
pinMode(LED_BUILTIN, OUTPUT); //set the built in LED to an output
digitalWrite(LED_BUILTIN, 1);
Serial.begin(115200);
delay(1000);
// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
digitalWrite(LED_BUILTIN, 0); //turn the LED on to show connected to WiFi
// Start the server
server.begin();
Serial.println("Server started");
// Print the IP address
Serial.println(WiFi.localIP());
}
void loop() {
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}
// Wait until the client sends some data
Serial.println("new client");
while(!client.available()){
delay(1);
}
client.flush();
// Read the first line of the request
char c;
int i = 0;
int spaces_received = 0;
int bufindex = 0; // reset buffer
char GET_str[80] = {};
char store_value;
int steps = 0;
int degree = 0;
int question_mark_position = 0;
// read the first line to determinate the request page
while (c != '\r') {
c = client.read();
if(c == ' '){
spaces_received++;
continue;
}
if(spaces_received == 0) continue; //HTTP request starts with a method followed by a space, so until we get the first space, ignore it.
if(spaces_received > 1) break; //if we already got a seconds space, we have all the information we need, stop collecting it.
GET_str[bufindex] = c;
/*Serial.print(bufindex);
Serial.print(':');
Serial.println(c);
*/
bufindex++;
}
if(GET_str[1] == 'a'){ //perform the action routine url: /action/x?foo=bar&et=al
for (i=0; i<sizeof(GET_str); i++) {
if(GET_str[i] == '?'){
question_mark_position = i;
//Serial.print("Question Mark Position:");
//Serial.println(i);
continue; //now we know the start position of the get string; No need to store it.
}
if(question_mark_position == NULL) continue;
if(GET_str[i] == '&'){ //new variable to store, reset the store_value and skip this iteration
Serial.println("Found an ampersand");
store_value = NULL;
continue;
}
if(GET_str[i] == NULL) continue; //most likely the request already ended, but we're going to keep looping to be sure, just skipping for now to prevent arithmetic problems.
if(GET_str[i] == 'd' || store_value == 'd'){
store_value = 'd';
if(GET_str[i] == 'd' || GET_str[i] == '=') continue; //don't store the variable name or equals sign.
Serial.print("storing d. ");
Serial.print(" old value: ");
Serial.print(degree);
degree *= 10; //move the next numerically stored one slot to the left;
Serial.print(" temp value: ");
Serial.print(degree);
Serial.print(" adding ");
Serial.print(GET_str[i]);
degree = degree + ((int) GET_str[i] - 48); //the interface received an ASCII character, which is 48 decimal higher
Serial.print(" new value ");
Serial.println(degree);
}else if(GET_str[i] == 's' || store_value == 's'){
store_value = 's';
if(GET_str[i] == 's' || GET_str[i] == '=') continue; //don't store the variable name or equals sign.
steps *= 10; //move the currently numerically stored decimal one slot to the left;
steps = steps + ((int) GET_str[i] - 48); //the interface received an ASCII character, which is 48 decimal higher
}
}
}else if(GET_str[1] == 'i'){ //perform the info routine currently outputs arduino clock
client.print("HTTP/1.1 200 OK\r\nContent-Type: text/javascript\r\n\r\n"); //HTTP header
client.print("var current_time = \"");
client.print(millis());
client.print("\";");
return;
}else{ // everything else is a 404
client.print("HTTP/1.1 404 NOT FOUND\r\nContent-Type: text/html\r\n\r\n"); //HTTP header
client.print("The file you are looking for ");
for (i=0; i<sizeof(GET_str); i++)
if(GET_str[i] != NULL)
client.print(GET_str[i]);
client.print(" could not be found.");
return;
}
client.print("HTTP/1.1 200 OK\r\nContent-Type: text/javascript\r\n\r\n"); //HTTP header
client.print("var current_time = \"");
client.print(millis());
client.println("\";");
client.print("var degree = \"");
client.print(degree);
client.println("\";");
client.print("var steps = \"");
client.print(steps);
client.println("\";");
client.flush();
delay(1);
Serial.println("Client disonnected");
// The client will actually be disconnected
// when the function returns and 'client' object is detroyed
}