Arduino WebServer input

I'm writing a sketch to control Roomba over internet. However I'm having most problems with processing webpage input in the sketch :frowning:
Below is the test sketch I use, it just displays page with simple links that pass variables via GET method. It just outputs to serial some text depending on which link is pressed (i.e. Go Forward!).
However for some reason it doesn't work right. For example when I click forward first time, it echoes Go Forward!, but if I now click Backward it echoes "Go Forward! Go Backward!". I have no clue why it does it. It seems to remember last value...

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1, 113);

EthernetServer server(80);

String HTTP_req;          // stores the HTTP request
boolean LED_status = 0;   // state of LED, off by default
byte LEDPin  = 13;

void setup()
{
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    Serial.begin(115200);       // for diagnostics
    Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

void loop()
{
    EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                HTTP_req += c;  // save the HTTP request 1 char at a time
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    sendHeader(client);
                    // send web page
                    showBody(client);
                    processDir(client);
                    Serial.print(HTTP_req);
                    HTTP_req = "";    // finished with request, empty string
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(1);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

void sendHeader(EthernetClient client){
   client.println("HTTP/1.1 200 OK");
   client.println("Content-Type: text/html");
   client.println("Connection: close");
   client.println();
}

void showBody (EthernetClient client){
 client.println ("<html><head><title></title></head>");
 client.println ("<body><h1>Test Page</h1><p><a href='?myDir=FW'>Forward </a>| <a href='?myDir=BW'>Back </a>| <a href='?myDir=ST'>Stop</a></p></p></body></html>");
		
}

void processDir (EthernetClient client){
  if (HTTP_req.indexOf("myDir=FW") > -1) Serial.println ("Go Forward!");
  if (HTTP_req.indexOf("myDir=BW") > -1) Serial.println ("Go Back!");
  if (HTTP_req.indexOf("myDir=ST") > -1) Serial.println ("All Stop!");
}

And by all means if you can suggest a better way to process input please do. Using Strings (memory leaks) and "indexOf" kind of bothers me, but I'm not sure if there's a better way :slight_smile:

bratan:
And by all means if you can suggest a better way to process input please do. Using Strings (memory leaks) and "indexOf" kind of bothers me, but I'm not sure if there's a better way :slight_smile:

Use strings (null terminated char array) and strstr(). You can reduce the size of the string buffer by processing line by line, rather than all at once.

bratan:
Using Strings (memory leaks) and "indexOf" kind of bothers me, but I'm not sure if there's a better way :slight_smile:

There is the standard C string, (array of chars), which in my opinion are easier to use (since I never used the String class). With arrays of chars you use the function strcmp (or maybe better in your case: strncmp) to compare 2 strings. Try it, it will most likely solve your problem :wink:

guix:

bratan:
Using Strings (memory leaks) and "indexOf" kind of bothers me, but I'm not sure if there's a better way :slight_smile:

There is the standard C string, (array of chars), which in my opinion are easier to use (since I never used the String class). With arrays of chars you use the function strcmp (or maybe better in your case: strncmp) to compare 2 strings. Try it, it will most likely solve your problem :wink:

Thank you!
You mean define string as: char myString[X] ? How would I know that size of array should be?

bratan:
Thank you!
You mean define string as: char myString[X] ? How would I know that size of array should be?

If you go line by line, it would only need to be big enough to accommodate the line that has the data you're looking for. You just have to be careful to make sure you don't put more data in it than it can handle.

                    processDir(client);
                    Serial.print(HTTP_req);
                    HTTP_req = "";    // finished with request, empty string

Why not print the GET request first? That way, you'd know what you are parsing.

Why not share that output with us? You are the only one that can see it, so there is only one of us that can actually help you.

PaulS:

                    processDir(client);

Serial.print(HTTP_req);
                    HTTP_req = "";    // finished with request, empty string



Why not print the GET request first? That way, you'd know what you are parsing.

Why not share that output with us? You are the only one that can see it, so there is only one of us that can actually help you.

Good point. I switched it around. Here's output. I basically first loaded page, then pressed Forward, then Back twice.

server is at 192.168.1.113
GET / HTTP/1.1
Host: 192.168.1.113
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive

GET /?myDir=FW HTTP/1.1
Host: 192.168.1.113
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.113/
Connection: keep-alive

Go Forward!
GET /?myDir=BW HTTP/1.1
Host: 192.168.1.113
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.113/?myDir=FW
Connection: keep-alive

Go Forward!
Go Back!
GET /?myDir=BW HTTP/1.1
Host: 192.168.1.113
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.113/?myDir=BW
Connection: keep-alive

Go Back!
Referer: http://192.168.1.113/?myDir=FW

There's your problem, the last link you pressed becomse the referrer. How about searching for

GET /?myDir=FW

Instead of just

myDir=FW

?

Arrch:

Referer: http://192.168.1.113/?myDir=FW

There's your problem, the last link you pressed becomse the referrer. How about searching for

:fearful: That's it! :astonished:
Thank you thank you thank you thank you!!! :slight_smile: Totally works now! :slight_smile:

GET /?myDir=BW HTTP/1.1
Host: 192.168.1.113
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.113/?myDir=FW
Connection: keep-alive

So, this blovk of text DOES contain both "myDir=BW" AND "myDir=FW", so the output you get is correct.

Now, only one of those strings follows GET /?, which might prove useful...

Some simple web page control code.

//zoomkat 4-1-12
//simple button GET for servo and pin 5
//for use with IDE 1.0
//open serial monitor to see what the arduino receives
//use the \ slash to escape the " in the html, or use ' instead of " 
//address will look like http://192.168.1.102:84 when submited
//for use with W5100 based ethernet shields

#include <SPI.h>
#include <Ethernet.h>
#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
byte ip[] = { 192, 168, 1, 102 }; // ip in lan
byte gateway[] = { 192, 168, 1, 1 }; // internet access via router
byte subnet[] = { 255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port

String readString; 

//////////////////////

void setup(){

  pinMode(5, OUTPUT); //pin selected to control
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  server.begin();

  myservo.write(90); //set initial servo position if desired
  myservo.attach(7);  //the pin for the servo control
  //enable serial data print 
  Serial.begin(9600); 
  Serial.println("server servo/pin 5 test 1.0"); // so I can keep track of what is loaded
}

void loop(){
  // Create a client connection
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string 
          readString += c; 
          //Serial.print(c);
        } 

        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.println(readString); //print to serial monitor for debuging 

          client.println("HTTP/1.1 200 OK"); //send new page
          client.println("Content-Type: text/html");
          client.println();

          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("<TITLE>Arduino GET test page</TITLE>");
          client.println("</HEAD>");
          client.println("<BODY>");

          client.println("<H1>Zoomkat's simple Arduino button</H1>");
          
          client.println("<a href=\"/?on\">ON</a>"); 
          client.println("<a href=\"/?off\">OFF</a>"); 

          client.println("</BODY>");
          client.println("</HTML>");
 
          delay(1);
          //stopping client
          client.stop();

          ///////////////////// control arduino pin
          if(readString.indexOf("on") >0)//checks for on
          {
            myservo.write(40);
            digitalWrite(5, HIGH);    // set pin 5 high
            Serial.println("Led On");
          }
          if(readString.indexOf("off") >0)//checks for off
          {
            myservo.write(140);
            digitalWrite(5, LOW);    // set pin 5 low
            Serial.println("Led Off");
          }
          //clearing string for next read
          readString="";

        }
      }
    }
  }
}

zoomkat:
Some simple web page control code.

Neat! Thanks for sharing!
I also got mine working. It drives Roomba across the room :slight_smile: Although bumper sensors are not working for some strange reason (I enabled Safe mode which suppose to override any movement if Roomba encounters obstacle). Am attaching the code (very rough, but it works!) in case anyone is interested. It uses Serial1 ports of Arduino Mega, so if you have Uno you'll need to adjust it (use SoftwareSerial instead).

Roomba_500_test_www3.ino (6.27 KB)