SOLVED: Global variable values rest?

Update/Solved: turns out its the buffer I allow for copying html from the flash memory to the http request response.

I replaced char buffer[90]; with char buffer[200];
Now 200 is probably too high but I was in a hurry and didn’t really care. For reference I ran freeMemory in several locations (one at a time) and it always returned “1123”

After running this code my state variables reset quickly. I don’t understand why. I have an UNO and a microSD ehternet shield. I had this working then tweaked my html to look cleaner. Then my boolean sw_table started resetting to zeros.

/*************************************************************************************************
* LCD pin to Arduino Digital pin Connection Map (for HD44780 LCDs)
*
*  // LCD pin 1  to GND
*  // LCD pin 2  to +5V
*  // LCD pin 3  to Pot(10K) to GND (I just used a wire)
*  // LCD pin 4  (RS) to Arduino pin 4
*  // LCD pin 5  (RW) to GND (We don't need to read from screen)
*  // LCD pin 6  (enable) to Arduino pin 5
*  // LCD pin 7
*  // LCD pin 8
*  // LCD pin 9
*  // LCD pin 10
*  // LCD pin 11 (Data 4) to Arduino pin 6
*  // LCD pin 12 (Data 5) to Arduino pin 7
*  // LCD pin 13 (Data 6) to Arduino pin 8
*  // LCD pin 14 (Data 7) to Arduino pin 9
*  // LCD pin 15 to +5V (I didn't have a backlight so mine stops at 14pins)
*  // LCD pin 16 to GND (I didn't have a backlight so mine stops at 14pins)
************************************************************************************************/

#include <SPI.h>
#include <Client.h>
#include <Ethernet.h>
#include <Server.h>
#include <Udp.h>
#include <LiquidCrystal.h>

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

// Initialize lcd pins
// I used this layout because many of the other digital pins are used by ethernet
LiquidCrystal lcd(4, 5, 6, 7, 8, 9);

// table of states for ouw switches
boolean sw_table[] = // status flags
{   
  false,
  false,
  false,
  false};

// this is here because I'm lazy. Use int2str() ?
String str_table[] = 
{
  "sw0=1",
  "sw1=1",
  "sw2=1",
  "sw3=1"};

// table of output pins for our switches
uint8_t const pin_table[] =
{
  A0,
  A1,
  A2,
  A3};

String readString = String(30); //string for fetching data from address

// Strings stored in flash mem for the Html Header
prog_char HTML_0[] PROGMEM = "HTTP/1.1 200 OK";
prog_char HTML_1[] PROGMEM = "Content-Type: text/html; charset=UTF-8\nContent-Language: en";
prog_char HTML_2[] PROGMEM = "";
prog_char HTML_3[] PROGMEM = "<!DOCTYPE html>\n<html>\n <head>\n  <title>SwitchBox</title>";
prog_char HTML_4[] PROGMEM = "  <style type=\"text/css\">\n   .on{color:red; display:inline;}\n   .off{color:gray; display:inline;}\n  </style> </head>";
prog_char HTML_5[] PROGMEM = " <body>\n  <h1>Switch control</h1>\n  <form action=\"?\" method=get>";
prog_char HTML_6[] PROGMEM = "   <input type=submit value=submit>\n  </form>
\n </body>\n</html>";

const int footer = 6;

// A table of pointers to the flash memory strings for the header
PROGMEM const char *HTML_table[] =
{   
  HTML_0,
  HTML_1,
  HTML_2,
  HTML_3,
  HTML_4,
  HTML_5,
  HTML_6};

void statusLCD(){
  lcd.clear();
  lcd.setCursor(0,0);                 // set cursor to column 0, row 0 (the first row), and print
  lcd.print("SW0:");                  //SW0 status UperLeft
  if ( sw_table[0] ) lcd.print("On!"); 
  else lcd.print("Off");
  lcd.print("  ");
  lcd.print("SW1:");                  //SW1 status UperRight
  if ( sw_table[1] ) lcd.print("On!");
  else lcd.print("Off");
  lcd.setCursor(0,1);                 // set cursor to column 0, row 1 (the second row), and print
    lcd.print("SW2:");                //SW2 status LowerLeft
  if ( sw_table[2] ) lcd.print("On!");
  else lcd.print("Off");
  lcd.print("  ");
  lcd.print("SW3:");                  //SW3 status LowerRight
  if ( sw_table[3] ) lcd.print("On!");
  else lcd.print("Off");
}

void statusSerial(){
  for(int i=0;i<4;i++){
    Serial.print("Switch ");
    Serial.print(i);
    Serial.print(" is ");                  //SW0 status UperLeft
    if ( sw_table[i] ) Serial.println("On!"); 
    else Serial.println("Off.");
    Serial.println(sw_table[i]);
  }
}

void webserverloop(){
  // Create a client connection
  Client 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; //replaces readString.append(c);
        }
        //output chars to serial port
        Serial.print(c);
        //if HTTP request has ended
        if (c == '\n') {
          //dirty skip of "GET /favicon.ico HTTP/1.1"
          if (readString.indexOf("?") <0)
          {
            //skip everything
          }
          else
            //lets check if SWs should be on
            for(int i=0;i<4;i++) {
              if(readString.indexOf(str_table[i]) >0)//replaces if(readString.contains("sw0=1"))
              {
                //SW has to be turned ON
                digitalWrite(pin_table[i], HIGH);    // set the SW on
                sw_table[i] = true;
                Serial.print("Turning on sw");
                Serial.println(i);
              }
              else{
                //SW has to be turned OFF
                digitalWrite(pin_table[i], LOW);    // set the SW OFF
                sw_table[i] = false;
                Serial.print("Turning off sw");
                Serial.println(i);
              }
            }
          statusSerial();
          statusLCD();

          char buffer[90]; //A character array to hold the strings from the flash mem

          for(int i = 0; i < footer; i++) {   // Use a for loop to print the remaining lines
            strcpy_P(buffer, (char*)pgm_read_word(&(HTML_table[i])));
            client.println( buffer );
          }
          //address will look like http://192.168.1.110/?sw0=1 when submited


          for(int i=0;i<4;i++) {
            pinMode(sw_table[i], OUTPUT);
            client.print("   <input type=checkbox name=sw");
            client.print(i);
            client.print(" value=1 ");
            if (sw_table[i]) { 
              client.print("CHECKED "); 
            }
            client.print(">sw");
            client.print(i);
            client.print(" status: ");
            if (sw_table[i]) { 
              client.print("<div class=\"on\">ON!</div>"); 
            }
            else{ 
              client.print("<div class=\"off\">OFF</div>"); 
            }
            client.println("
");
          }
          strcpy_P(buffer, (char*)pgm_read_word(&(HTML_table[footer])));
          client.println( buffer );
          //clearing string for next read
          readString="";
          //stopping client
          client.stop();
        }
      }
    }
  }  
}

void setup(){
  //start Ethernet
  Ethernet.begin(mac, ip, gateway, subnet);

  //Set analog pins 0-3 to output and digital write low
  for(int i=0;i<4;i++) {
    pinMode(pin_table[i], OUTPUT);
    digitalWrite(pin_table[i], LOW);
  }

  //enable serial data print
  Serial.begin(9600);
  
  lcd.begin(16,2);  // columns, rows.  use 16,2 for a 16x2 LCD, etc.
  lcd.clear();      // start with a blank screen
  statusLCD();
  statusSerial();
}

void loop(){
  webserverloop();
}

Correct me if I'm wrong because I don't use the String library. But the line:

String readString = String(30); //string for fetching data from address

Will create a String whose contents is "30", not a thirty byte buffer to hold stuff. So the line

readString += c; //replaces readString.append(c);

if it returns an upper case 'H' will make readString become "30H"; at least until you reset it at the bottom of the loop. Is that what you intended? Also I couldn't find an example of an array of Strings; lots of examples of strings out there though. Could it be that there is a problem with the String table you are trying to do the index on?

I'm only jumping in since the experts on the String library haven't jumped in.

I don't think it's anything wrong with the strings. That all seems to be working fine. The switch state only gets set in one place in code. But I can see it being turned on then 1/2 sec later being turned off and I don;t know why.

OK, then how about the else after the check for favicon? Your indentation indicates that you expect everything under it to be inside the else but there is no opening brace following the else. This means the for loop is the only thing the else relates to so the statusSerial and statusLCD will execute.

I would check on how much ram you have free. Check the playground for ways to do this.

I see you have your strings in flash which is good but I think the ethernet stuff uses a fair bit of your memory.

draythomp: OK, then how about the else after the check for favicon? Your indentation indicates that you expect everything under it to be inside the else but there is no opening brace following the else. This means the for loop is the only thing the else relates to so the statusSerial and statusLCD will execute.

This is correct. The status functions only update the displays not changing values of the pins. The statusSerial is only used for debugging. Should be plenty of available RAM. I used http://www.scienceprog.com/getting-hands-on-arduino-ethernet-shield/ as an example and I'm using significantly less text and strings.

Should be plenty of available RAM

The symptoms could also be that of buffer over/underflow.

Ok, one last try. the String routines use malloc, calloc and free to manipulate strings. Some of them are pretty intense since the String you get back is not the String you sent. So, a memory problem can happen regardless of the size of your program if you manipulate things in some fashion. There are calls you can find in the playground that can be interspersed into the code at various spots to see how much memory you have left at any given point. For example, each time you add a character to your String to be parsed, you are likely to have a malloc, memcpy, free combination just to add a character at the end. If you are receiving a hundred characters, that's a hundred of those. Memory fragmentation happens and although the String routines have been heavily used, there could still be something that is messing with you.

Also, you can check in your loop or somewhere else appropriate to see if the variables get reset and print something. You can scatter serial prints around various things to see what is getting you to the point where it is cleared after it is set by your get. Heck, you can serial print the darn line numbers if it gets to that point. I know I have when nothing else seemed to work.

AWOL:

Should be plenty of available RAM

The symptoms could also be that of buffer over/underflow.

Nailed it! my char buffer for copying from flash was too small.