freeRam() causes freeze

I started a similar thread in Networking but I just figured out this has nothing to do with the network side of my code, rather than calling on freeRam() in conjunction with the network code.

using the example WiFi Web Server LED Blink I want someone to add this little code to it, and see if the free ram doesn't cause the arduino to crash in 7 minutes after the server code is called.

up top above setup add

unsigned long previousMillis=0;
int interval=30000;
unsigned long PrintCount=0;
unsigned long LoopCount=0;

next add this to loop()

void loop()
{
ListenForController();
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= interval) // print this every 2 seconds
{ previousMillis = currentMillis;
Serial.print(PrintCount);
Serial.print(F(" "));
Serial.print(LoopCount);
Serial.print(F(" "));
Serial.print(millis());
Serial.print(F(" "));
Serial.print(freeRam());
Serial.print(F(" "));
Serial.println(F("slave arduino // freezes"));
PrintCount++;
}
LoopCount++;
}

void ListenForController()
{

then at the bottom add this

int freeRam() {
extern int __heap_start,*__brkval;
int v;
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);
}

The results are if you never connect to the internet page, it will never freeze. However, if you connect to the internet page (if you only connect once) then it will freeze in 7 minutes after the connection due to some kind of cross code contamination witchery.

Heres the full code, with changes already made.

/*
  WiFi Web Server LED Blink

 A simple web server that lets you blink an LED via the web.
 This sketch will print the IP address of your WiFi Shield (once connected)
 to the Serial monitor. From there, you can open that address in a web browser
 to turn on and off the LED on pin 9.

 If the IP address of your shield is yourAddress:
 http://yourAddress/H turns the LED on
 http://yourAddress/L turns it off

 This example is written for a network using WPA encryption. For
 WEP or WPA, change the Wifi.begin() call accordingly.

 Circuit:
 * WiFi shield attached
 * LED attached to pin 9

 created 25 Nov 2012
 by Tom Igoe
 */
#include <SPI.h>
#include <WiFi.h>

char ssid[] = "";      //  your network SSID (name)
char pass[] = "";   // your network password
int keyIndex = 0;                 // your network key Index number (needed only for WEP)
unsigned long previousMillis=0;
int interval=30000;
unsigned long PrintCount=0;
unsigned long LoopCount=0;
int status = WL_IDLE_STATUS;
WiFiServer server(80);

void setup() {
  Serial.begin(9600);      // initialize serial communication
  pinMode(9, OUTPUT);      // set the LED pin mode

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    while (true);       // don't continue
  }

  String fv = WiFi.firmwareVersion();
  if ( fv != "1.1.0" )
    Serial.println("Please upgrade the firmware");

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to Network named: ");
    Serial.println(ssid);                   // print the network name (SSID);

    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
  }
  server.begin();                           // start the web server on port 80
  printWifiStatus();                        // you're connected now, so print out the status
}


void loop() 
{ 
  ListenForController();
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval) // print this every 2 seconds
  { previousMillis = currentMillis;   
    Serial.print(PrintCount);
    Serial.print(F("   "));
    Serial.print(LoopCount);
    Serial.print(F("   "));
    Serial.print(millis());
    Serial.print(F("   "));
    Serial.print(freeRam());
    Serial.print(F("   "));
    Serial.println(F("slave arduino // freezes"));
    PrintCount++;
  }
  LoopCount++;
}

void ListenForController()
{
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("new client");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // 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");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            client.print("Click <a href=\"/H\">here</a> turn the LED on pin 9 on
");
            client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off
");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          }
          else {      // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        }
        else if (c != '\r') {    // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(9, HIGH);               // GET /H turns the LED on
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(9, LOW);                // GET /L turns the LED off
        }
      }
    }
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  // print where to go in a browser:
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);
}
  int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval);  
}
    Serial.println("WiFi shield not present");
    Serial.println("Please upgrade the firmware");
    Serial.print("Attempting to connect to Network named: ");

A waste of perfectly serviceable SRAM.

If you are concerned about running out of SRAM, and you must be or you wouldn't be using freeRam(), quit pissing it away.

    String currentLine = "";                // make a String to hold incoming data from the client

That whooshing noise you hear is your memory being trashed.

A waste of perfectly serviceable SRAM.

In my orignal experiment I used the F macro as much as possible. However, once I simplifed the problem to calling on freeRam() in conjuction of using server code, I wanted to simplify the problem and use the experiment that came pre-loaded in the library for all newbs to learn from. I made minimal changes to the example, to show that it does freeze if you call on FreeRam.

This is the serial printout. see how after 6 minutes once server code is called, the program completely freezes.

To see this page in action, open a browser to http://192.168.0.157
new client
GET /H HTTP/1.1
Host: 192.168.0.157
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:41.0) Gecko/20100101 Firefox/41.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
DNT: 1
Referer: http://192.168.0.157/
Connection: keep-alive

client disonnected
0   23866   30000   1211   slave arduino // freezes
1   98416   60000   1211   slave arduino // freezes
2   172939   90000   1211   slave arduino // freezes
3   247452   120000   1211   slave arduino // freezes
4   322003   150000   1211   slave arduino // freezes
5   396545   180000   1211   slave arduino // freezes
6   471072   210000   1211   slave arduino // freezes
7   545602   240000   1211   slave arduino // freezes
8   620094   270000   1211   slave arduino // freezes
9   694595   300000   1211   slave arduino // freezes

In the debugging efforts, i used two separate arduino unos, and one mega, and used the 1.0.6 and 1.5.8 arduino IDE. No matter what i did, if froze every time once I ran the server code by using the web site it gave me. I can't find any logical reason to why this may be happening.

That can cause memory fragmentation and cause you to run out of SRAM fast and has been known for some time to freeze Arduino programs.

Two things to consider though, It would have to call on the same ListenForController() method listed on the example for the fragmentation to build up to the point it could crash the arduino though. If it did call on ListenForController() it would print "new client" again in the serial monitor. It only calls it once, though, so what else could cause the fragmentation?

The second is, how else can you effectively use a server based controller code without using the (if strings ends with GET/"something")

// Check to see if the client request was "GET /H" or "GET /L":
if (currentLine.endsWith("GET /H")) {
digitalWrite(9, HIGH); // GET /H turns the LED on
}

The second is, how else can you effectively use a server based controller code without using the (if strings ends with GET/"something")

Each time a client makes a request, it includes carriage returns and line feeds. When a set arrives, check the collected data. If it STARTS with "GET ", the stored data is the complete GET request.

Unless you plan on hosting a huge amount of data, like Ebay, the GET requests that a client makes should be relatively short. Allocate a char array of a reasonable size, and store the data in the array, adding a NULL terminator after every character addition.

https://forum.arduino.cc/index.php?topic=288234.0
Robin2's tutorial refers to serial data, but the process of collecting client data is EXACTLY the same.

but it printed "client disonnected" in the serial monitor. that means for the client to connect again it would have to go back through and that would print "new client" again. And if the client were still connected, it wouldn't be able to print the information it does in the main loop that happens every 30 seconds until the crash happens correct?

I still need the server side abilities, if strings are a bad idea, how else can I control the arduino using it as a server?

I even tried to limit the amount of possible fragmentation by doing this

else if (c != '\r')
{
if (currentLine.length()<80)
{
currentLine += c; // add it to the end of the currentLine
}
}

even that didn't work. if there is 1211 of freeRam available as the serial monitor says, I don't see how the string (max size of 80) can be the reason the program crashes. Wouldn't it just write over the previous space it occupied?

Some other function gets called and pushes its stuff onto the stack and the stack crashes into the heap and the program freezes.

but it runs over 600,000 more cycles after the client disconnects before it freezes. If you look at the code, which i simplified greatly for debugging, there is nothing in there that should cause any sort of unusual SRAM consumption, that isn't called every loop is there? Therefor something else is fragmenting the program correct? what else in the code could cause that sort of witchery?

Lets say i used Robins char example, can you do (if char ends with) like you can with strings?

========edit======
the mega has a lot more scram than the uno correct? Therefor, shouldn't it take the mega twice as long to crash? for some reason it doesn't.

Just to be sure, you took your ssid and password out before you posted and these really have something in them in your program right?

correct, i didn't want to post my network password for the world to see. i don't know what information you have to have to bypass a routers firewall, but I like to play it safe.

By the way.... now that I think about it, if you give a person the numbers 1-100 and tell them to figure out how many times they can make 100 the answer is 49, 1+99, 2+98, ect. then you only have one 50 left over.

The point that is bugging me greatly is that even if I include

else if (c != '\r')
{
if (currentLine.length()<80)
{
currentLine += c; // add it to the end of the currentLine
}
}

which makes the max string length 80, and we use our logic that says fragmentation can only happen 80 times at most, assuming the first string is 1char, then something is put on top of that, then the string is erased, then a second string is 2 chars something is put on top of that, then the string is erased, and it keeps happening, then most fragmentation that can happen is 80*40 which is 320, but the freeRam says I have 1211 freeRam to work with.... What else could be causing the fragmentation? It can't be the string in this case by itself because of the 80 cap.... correct?

Since String is just a class that's hiding a char array from you, you can rest assured that there is nothing you can do with String that they aren't doing behind the scenes with a char array.

To see if a char array ends with a particular letter, use strlen to get the length of the string and check the last letter is equal to something.

yes, but lets say the ends with is 3 letters, which you really need, otherwise that information it pulls from the

User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:41.0) Gecko/20100101 Firefox/41.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

is going to rock your world as it could use pretty much any letter in that info, the only way to safely code it to work it to have something that is 3 or more chars, in the server case, it uses GET/ as the safety. can you easily do that with cars without writing code that checks one at a time and if that char is match it checks the next char?

then most fragmentation that can happen is 80*40 which is 320

Your calculator batteries need replacing.

:frowning: minor zero

either way, because the string function is called within a function, it disappears when the function has completed its loop correct? Then that space is available for something else to be written to it, and because nothing else was written on top of the string in the heap, there can be no fragmentation correct?

Fragmentation can only happen when the string doesn't go away before something else is written above it in the heap, then when it is erased, that gap is fragmented correct?

Is there anything else that writes to the heap in the function that would write on top of the string so that it could become fragmented?

I'm not going to discuss the performance of the String class with someone who can't even be bothered to refer to it correctly.

I'm not going to discuss the performance of the String class with someone who can't even be bothered to refer to it correctly.

that's a bit harsh considering that I don't know what I said was incorrect... did I not use an upper case S or did I refer to it as a function?

Whatever I didn't bother doing, I apologize

did I not use an upper case S

No, you consistently do not, and do not seem to recognize that String is a class and that the methods of that class do things that are NOT in the best interest of memory management.

I re-wrote the code, to not use Strings, but instead to use char[] as Robin deminstrated in her examples. The program still froze!

I then went back to the second example I posted and took out each and every String without even using a char[] as a substitution for String. Still it froze after 10 loops once I called the server code.

Find one String in this code that isn't commented out.

/*
  WiFi Web Server LED Blink

 A simple web server that lets you blink an LED via the web.
 This sketch will print the IP address of your WiFi Shield (once connected)
 to the Serial monitor. From there, you can open that address in a web browser
 to turn on and off the LED on pin 9.

 If the IP address of your shield is yourAddress:
 http://yourAddress/H turns the LED on
 http://yourAddress/L turns it off

 This example is written for a network using WPA encryption. For
 WEP or WPA, change the Wifi.begin() call accordingly.

 Circuit:
 * WiFi shield attached
 * LED attached to pin 9

 created 25 Nov 2012
 by Tom Igoe
 */
#include <SPI.h>
#include <WiFi.h>

char ssid[] = "";      //  your network SSID (name)
char pass[] = "";   // your network password
int keyIndex = 0;                 // your network key Index number (needed only for WEP)
unsigned long previousMillis=0;
int interval=30000;
unsigned long PrintCount=0;
unsigned long LoopCount=0;
int status = WL_IDLE_STATUS;
WiFiServer server(80);

void setup() {
  Serial.begin(9600);      // initialize serial communication
  pinMode(9, OUTPUT);      // set the LED pin mode

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    while (true);       // don't continue
  }

  String fv = WiFi.firmwareVersion();
  if ( fv != "1.1.0" )
    Serial.println("Please upgrade the firmware");

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to Network named: ");
    Serial.println(ssid);                   // print the network name (SSID);

    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
  }
  server.begin();                           // start the web server on port 80
  printWifiStatus();                        // you're connected now, so print out the status
}


void loop()
{
  ListenForController();
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval) // print this every 2 seconds
  { previousMillis = currentMillis;   
    Serial.print(PrintCount);
    Serial.print(F("   "));
    Serial.print(LoopCount);
    Serial.print(F("   "));
    Serial.print(millis());
    Serial.print(F("   "));
    Serial.print(freeRam());
    Serial.print(F("   "));
    Serial.println(F("slave arduino // freezes"));
    PrintCount++;
  }
  LoopCount++;
}

void ListenForController()
{
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("new client");           // print a message out the serial port
    //String currentLine = "";                // make a String to hold incoming data from the client
    boolean lenght=1;
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (lenght == 0) {
            // 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");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            client.print("Click <a href=\"/H\">here</a> turn the LED on pin 9 on
");
            client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off
");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          }
          else {      // if you got a newline, then clear currentLine:
           // currentLine = "";
           lenght=0;
          }
        }
        else if (c != '\r') {    // if you got anything else but a carriage return character,
        //  currentLine += c;      // add it to the end of the currentLine
        lenght=1;
        }

        // Check to see if the client request was "GET /H" or "GET /L":
     /*   if (currentLine.endsWith("GET /H")) {
          digitalWrite(9, HIGH);               // GET /H turns the LED on
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(9, LOW);                // GET /L turns the LED off
        }*/
      }
    }
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  // print where to go in a browser:
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);
}
  int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval); 
}

Serial printout, it froze and has been like that for 10 minutes.

Attempting to connect to Network named: ProbablyYours
SSID: ProbablyYours
IP Address: 192.168.0.176
signal strength (RSSI):-57 dBm
To see this page in action, open a browser to http://192.168.0.176
0   19935   30000   6846   slave arduino // freezes
new client
GET /H HTTP/1.1
Host: 192.168.0.176
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:41.0) Gecko/20100101 Firefox/41.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
DNT: 1
Referer: http://192.168.0.176/
Connection: keep-alive

client disonnected
1   82426   60000   6846   slave arduino // freezes
2   145563   90000   6846   slave arduino // freezes
3   208691   120000   6846   slave arduino // freezes
4   271798   150000   6846   slave arduino // freezes
5   334930   180000   6846   slave arduino // freezes
6   398067   210000   6846   slave arduino // freezes
7   461199   240000   6846   slave arduino // freezes
8   524327   270000   6846   slave arduino // freezes
9   587460   300000   6846   slave arduino // freezes
10   650595   330000   6846   slave arduino // freezes

There is no wichery in computer code. They do exactly as they're told.

why then is it freezing? what am i doing wrong? I tried this with two unos, one mega, and two separate IDE's. No matter what, it freezes,

Rewrite the expression "currentMillis - previousMillis >= interval" as hell freezes over at 64K.

Cheers!

Rewrite the expression "currentMillis - previousMillis >= interval" as hell freezes over at 64K.

rewrite to

currentMillis - previousMillis > interval

or change their names? It doesn't freeze unless I call on the server code, if the server isn't used it goes on forever. The server somehow starts something that freezes the arduino after about 6 minutes.... Hell has frozen over!

Thomas499:
Find one String in this code that isn't commented out.

  String fv = WiFi.firmwareVersion();

Wouldn't using char[] like this do the same thing as a String in terms of poor memory management?

else if (c != '\r')                // you've gotten a character on the current line
        { if (TempNC<MaxLenghtOfchar)
          { 
            currentLine[TempNC]=c;
            if (PaulSsaysEndswithNotUsingStrings("GET /H"))
            Serial.println(F("LED ON"));
            else if (PaulSsaysEndswithNotUsingStrings("GET /L"))
            Serial.println(F("LED OFF"));
            TempNC++;
          }
        }

and this part is used to substitute Strings

boolean PaulSsaysEndswithNotUsingStrings(char holder[])
{
  int i = TempNC-strlen(holder);
  if (i>=0)
  {
    static byte TempNT = 0;
    TempNT=0;
    boolean ok =1;
    while (i<TempNC && ok!=0)
    {
      if (holder[TempNT]!=currentLine[i])
          ok=0;
          TempNT++;
          i++;
        }
        if (ok==1)
        return 1;
        else
        return 0;
      } else return 0;
}

I can't imagine the String protocol acting very different. It carries over the same, then a boolean, an int, and a static byte are created, then changed, then it returns and I assume clears out the memory it used.... but has anything stacked on top of it in the meanwhile?

oqibidipo, thank you for pointing out the one String that I forgot about. But I still don't think that's the cause of the freeze. I took it out, and am experiencing the same results. I would be interested to find out if anyone loads the example and has the same results.

Really? That setup is a worse case scenario. Of course that's going to cause problems!

I seem to remember reading when i first started programming that Strings took up space in groups of 20. For example String ("1") and String ("12345") and String ("12456789") would all take up the same amount of space as Char[20] ... or was it Char[22] because of the end that tells it that it has ended. Then if you go over 20, it adds another 20.

Was I mistaken on how that worked?

This still hasn't fixed my freezing problem, now that i've taken out all the Strings it still freezes. I don't know what else to do. Can someone load the program and try it out to see if they get the same results? Maybe it has something to do with my internet modem sending something 6 minutes after it talks to it that freezes it up?