Ethernet shield / WEB server / string issues

Hi there.

We'll I have my Arduino UNO and Ethernet shield Chicken Coop opener/closer up and working but I am having some issues and wonder if someone can shed some light...

This is what it does:

  • The Server starts and listens on port 80 for a client connection...
  • When client connects the HTML page is served up with 3 buttons Open, Close and Refresh plus some headings and fluffery
  • When 'Close' is clicked the Web server receives the following string: GET /?Close=10&%21= HTTP/1.1 or GET /?Open=20&%21= HTTP/1.1 for an Open button click
  • The server detects the '20' (or '10' for a Open) then operates a motor gearbox combination via an RC servo/microswitch setup which opens or closes the door. It all

works fine

  • As the door reaches max open or close a further 2 limit microswitches are used to detect the door position limit and stop the motor by centering the RC servo which

deactivates the motor/gearbox micro switches. In addition, the motor will only ever run for about 1 second in case the microswitches are faulty

This is the problem:
All working fine until I decided to add some more functionality and add an LDR to monitor light levels. The LDR is on analog pin 0 and works fine (0-1024)
When I try and send some information back to the client in the form of some text (strStatus) server the requests from the client become corrupted with bits of the HTML missing:

When I cut the strings down to a minimum, all works fine

Any ideas

/*
Monday 08 April 2013 - Arranged to monitor limit switches whilst opening and closeing
Introduce counter which can be used as a rough timer (appros 12 secs) to auto cancel if limit switchs fail to save motor
*/
#include <SPI.h>  
#include <Ethernet.h>
#include <Servo.h> 
#include <stdio.h>
byte mac[] = { 
  0x90, 0xA2, 0xDA, 0x0D, 0x12, 0xB2 }; 
//byte ip[]  = {   217, 46, 221, 235 };                 
byte ip[]  = {192,168,1,177};                 

byte subnet[]  = { 
  255, 255, 255, 0 };

EthernetServer server(80);
String ReadString="";
String InputString="";    
String ServoString="";
String OutputString ="";
String strState="";
int ind1 = 0;
int ind2 = 0;
boolean Error = false;
int DoorAction;


Servo servoMain;
int AnalogLDRPin=0;
int AnalogValue=0;
String strLDR;
int cStop=0;
int cClose=1;
int cOpen=2;

int nCounterTimer=0;
String strDoorMovements;
int cAboutOneSecond = 8000;//Overriding timer which will kick in if limit switch failed

int LimitSwitchOpen=2;
int LimitSwitchClose=3;
int LimitSwitchOpenState=0;
int LimitSwitchCloseState=0;
int ServoPort=4;
int Direction=0;//0=Nothing, 1=Up, 2=Down

void setup()
{
  Ethernet.begin(mac, ip, subnet);
  server.begin();
  servoMain.attach(ServoPort);
  servoMain.write(90);
  pinMode(LimitSwitchOpen, INPUT);
  pinMode(LimitSwitchClose, INPUT);
  Serial.begin(9600); 
}

void loop()
{

  OutputString = "";
  Direction = cStop;  //Default state if Action not detected
  EthernetClient client = server.available();
  if (client)
  {
    while (client.connected()) 
    {
      if (client.available()) 
      {

      char c = client.read();
      ReadString = ReadString + c;
      if (c == '\n')
        {  

          OutputString = "";
          Serial.print("From client:" + ReadString);
          ind1 = ReadString.indexOf("=");
          ind2 = ReadString.indexOf("&");
          ServoString = ReadString.substring(ind1+1, ind2);  
               
          char servochar[ServoString.length()+1];
          ServoString.toCharArray(servochar, ServoString.length()+2);
          servochar[ServoString.length()+1]='X';
          servochar[ServoString.length()+2]='\0';
          DoorAction = atoi(servochar);
          

          if (DoorAction == 10)
          {
            Direction = cClose;
            OutputString="Closed";
          } //Close
          if (DoorAction == 20)
          {
            Direction = cOpen;
            OutputString="Opening...";
          } //Open

         AnalogValue = analogRead(AnalogLDRPin);
          strLDR = "LDR:" + String(AnalogValue) + "( 0=Bright Sun. 1024=Dark)";


    //Problem identified to this area
    strState="This text is fine";// it locks up";
    //strState="This text plus a bit more locks up";


//Limit switch states back to client - but locks up with long strings
//    if (LimitSwitchCloseState == 1) {strState = "Closed (Limit switch detected)!";}
//   if (LimitSwitchCloseState == 0) {strState = "May not be closed - Check with camera";}
//   if (LimitSwitchOpenState == 1) {strState = "Opened (Limit switch detected)!";}
//    if (LimitSwitchOpenState == 0) {strState = "May not be open - Check with camera";}

    
//  Serial.println(AnalogValue);



          //--------------------------HTML------------------------
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println();
          client.print("<html><head>");
          client.print("<title>ICoop V1.0</title>");
          client.println("</head>");
          client.print("<body bgcolor='black'>");
          client.println("
<hr />");
          client.println("<h1><div align='center'><font color='#FFFFFF'>Who'll Let The Chooks Out</font color></div></h1>");
          client.println("<hr />
");
          client.println("<tr bgColor='#222222'>");
          client.println("<td bgcolor='#222222'><font face='Verdana' color='#FFFFFF' size='2'>View camera then click below
</font></td>");
          client.println("<td align='center' bgcolor='#222222'><form method=get><input type='hidden' name='Open' value='20'><input type='hidden' name='!'><input type='submit' value='Open'></form></td>");
          client.println("<td align='center' bgcolor='#222222'><form method=get><input type='hidden' name='Close' value='10'><input type='hidden' name='!'><input type='submit' value='Close'></form></td>");
          client.println("<td align='center' bgcolor='#222222'><form method=get><input type='hidden' name='Refresh' value='00'><input type='hidden' name='!'><input type='submit' value='Refresh'></form></td>");
          client.println("<td align='center'><font color='green' size='3'>");
          client.println(OutputString);
          client.println(strLDR);
          client.println(strState);
//          client.print("Motor battery level= 6.1V 
");
 //         client.print("Light levels       = 123");
          client.println("</tr>");
          client.println("</tr>");
          client.println("</table>");
          client.println("</body></html>");
          InputString="";
          ServoString="";
          ReadString="";  
          client.stop();
        Serial.println(OutputString);        
      } 
      }
    }
  }  


      //******************************************************
      //Open logic - Close logic is the same
      //******************************************************
      if (Direction == cOpen)
      {
        LimitSwitchOpenState=digitalRead(LimitSwitchOpen);     
        nCounterTimer=0;
        while (LimitSwitchOpenState == 0 && nCounterTimer <= cAboutOneSecond)
        {
          nCounterTimer++;
          servoMain.write(70); 
          //Keep opening until Close Microswitch closed
          LimitSwitchOpenState=digitalRead(LimitSwitchOpen);     
        }
        servoMain.write(90);//Turn off
      }
      //******************************************************
    
      //******************************************************
      //Close logic (Same as Open logic)
      //******************************************************
      if (Direction == cClose)
      {
        LimitSwitchCloseState=digitalRead(LimitSwitchClose);     
        nCounterTimer=0;
        while (LimitSwitchCloseState == 0 && nCounterTimer <= cAboutOneSecond)
        {
          nCounterTimer++;
          servoMain.write(110); 
          LimitSwitchCloseState=digitalRead(LimitSwitchClose);//Keep opening until Close Microswitch closed
        }

        servoMain.write(90);//Turn off
      }
      //******************************************************

    Serial.print(OutputString);



}// Void Loop (Main loop)

You're wasting your RAM!

Don't use the String class. It has two problems: it's programmed for a full-fledged PC with a memory management unit where RAM is not an issue. It fragments the available memory making it impossible to allocate bigger memory chunks in no time. Additionally it suffers from an implementation bug in the dynamic memory allocation within the avr-gcc code leading to memory leaks.

The use the F() macro! All classes inheriting from the Print class (almost all having the print() and println() methods) allow you to use the F() macro for constant strings (literals specified in double quotes). These constant strings are the read directly from the flash memory avoiding to make a copy of them in the RAM.
Example:

 client.println("<p>This is just an example with some text provided as a constant</p>");

becomes

 client.println(F("<p>This is just an example with some text provided as a constant</p>"));

pylon

Thanks for the reply. Your example covers constant strings, I am building the string as I go then sending it to the client

I am building the string as I go then sending it to the client

No, you aren't. Read your own code.

No, you aren't. Read your own code.

Really? Is this a constant? I don't think it is, I think it is a dynamic

What do YOU think it is?

strLDR = "LDR:" + String(AnalogValue) + "( 0=Bright Sun. 1024=Dark)";

This is dynamic. That is the problem.

strLDR = "LDR:" + String(AnalogValue) + "( 0=Bright Sun. 1024=Dark)";

I think what is causing your problem is the string constants in your response to the client. They are using almost all of your SRAM before you get to this. The String data type dynamically allocates memory as you use it. If you had only 4 bytes of available SRAM just before this memory allocation, how much would you have after it?

Did you read pylon's post? Did you use the F() macro as he suggested?

Hi SurferTim

Thanks for your reply, Yes I have converted all the string constants from :
client.print("blah blah blah");
to ...
client.print(F("blah blah blah"));

and it seems to have worked

BTW, is there a way to find out how much memory is available so I can keep an eye on looming problems?

Thanks

I use the freeRam() function to determine remaining SRAM at different parts of my programs. Here is another post with the code.

I am building the string as I go then sending it to the client

You are not "building the string as I go". A String is not a string. And never will be.