BufferFiller.print resets my device

Hi!

I'm using the EtherCard library to display a simple website.
Now 've decided to not let the Arduino handle the site, but just provide some data for the site.
So i want the Arduino to send the data as json, but as soon as the string contains more then 9-10 json-items, my device just resets itself when calling BufferFiller.print

This is the code (just making a random json string for testing)

void listJson() {
   Serial.println("enter");
  String data = "{\"list\":[";
  int index = 1;

  while (index < 15) {
    if (index != 1) data = data + ",";
    int tempC = random(30);
    String hash = "Test"; //MD5::make_digest(MD5::make_hash( (char *) random(300)), 16);
    data = data + "{\"id\":\"";
    data = data + hash + "\",\"name\":\"Sensor ";
    data = data + index + "\",\"val\":";
    data = data + tempC;
    data = data + "}";
    
   // bfill.emit_p(PSTR("{\"id\":\"$H\",\"name\":\"Sensor $D\",\"val\":$T}")
   //   , hash , index, tempC);
    index++;
    Serial.println(freeRam());
  }
  data = data +  "]}";
  bfill.print(data);
  Serial.println("done");
}

As you can see, i'm checking the ram. It goes down to 4471 right before the device resets.

The device i'm using, is a Arduino Mega2560

When only producing 9-10 json-items, the result looks like this:

{"list":[{"id":"Test","name":"Sensor 1","val":7},{"id":"Test","name":"Sensor 2","val":19},{"id":"Test","name":"Sensor 3","val":23},{"id":"Test","name":"Sensor 4","val":8},{"id":"Test","name":"Sensor 5","val":10},{"id":"Test","name":"Sensor 6","val":2},{"id":"Test","name":"Sensor 7","val":24},{"id":"Test","name":"Sensor 8","val":8},{"id":"Test","name":"Sensor 9","val":23}]}

Hope someone could help me, would like to be able to produce ~25 json-items

Thanks in advance

Hope someone could help me

Get rid of all Strings.

Allocate a fixed length char array that will hold the longest string (lower case s) that you will send, and use the string functions to populate that array.

All that constructing and destructing you are doing is fragmenting the hell out of your memory. While you may have plenty of memory still available, it's in little tiny (unusable) pieces.

Okay. But can i just print the array like i do with the string ( bufferFiller.print(char[]) )?

And should i first run a loop to calculate how large the array needs to be?

Okay. But can i just print the array like i do with the string

You don't have a string. You have a String.

And, yes, if you had a string (a NULL terminated array of chars), you could print it just like a String.

Okay. So I've made the changes to the code.
The char array now contains the json encoded info.

I call bfill.print(data);
and then ether.httpServerReply(bfill.position());

But only 9 chars makes it.
So when I navigate to the Arduinos IP, I only get this

{"list":[

If i check the array right before priting it:

for (int i = 0; i < dataIndex; i++) {
    Serial.print(data[i]); 
    
   }

it will tell me that all the data are there (417 chars in this test code)

I don't get why this is happening..hm

I don't get why this is happening..hm

I'm sure that you can get help with your snippets at http://snippets-r-us.com. I know the owner of that site. Very helpful gentleman.

Not sure what you want me to do with that page.
But here's an update.

Found a simple json-library, things got better, but not good.

This is my current code:

#include <EtherCard.h>
#include <SPI.h>
#include <aJSON.h>

#define STATIC 0  // set to 1 to disable DHCP (adjust myip/gwip values below)

#if STATIC
// ethernet interface ip address
static byte myip[] = { 192,168,1,200 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
#endif

// ethernet mac address - must be unique on your network
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
static word contentStart;

byte Ethernet::buffer[500]; // tcp/ip send and receive buffer
BufferFiller bfill;

void setup(){
  //dissable the MFRC522 chip for now
  pinMode(48,OUTPUT);
  digitalWrite(48, HIGH);
  
  Serial.begin(57600);
  SPI.begin();
  if (ether.begin(sizeof Ethernet::buffer, mymac, 53) == 0) 
    Serial.println( "Failed to access Ethernet controller");
  #if STATIC
    ether.staticSetup(myip, gwip);
  #else
  
  if (!ether.dhcpSetup())
    Serial.println("DHCP failed");
  #endif

   ether.printIp("IP:  ", ether.myip);
  ether.printIp("GW:  ", ether.gwip);  
  ether.printIp("DNS: ", ether.dnsip);  
}

// write the content lenght value into the header placeholder (": 000\r\n")
void writeContentLengthValue(uint8_t* data, word length)
{
  // Find the place to write
  while (*data && !(*(data-4)==':' && *(data-3)==' ' && *(data-2)=='0' && *(data-1)=='0' && *data=='0' && *(data+1)=='\r' && *(data+2)=='\n')) data++;
  
  while (*data && *data == '0')
  {
    *data = (length%10 + '0');
    data--;
    length /= 10;
  }
}


// Use the content posision to calculate content length and write it
void writeContentLength(BufferFiller& buf)
{
  word length = buf.position() - contentStart;   
  writeContentLengthValue(buf.buffer(), length);
}


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

void listJson() {
  Serial.println("enter");
  int index = 1;
  //String* data;
  Serial.println(freeRam());
  aJsonObject* root = aJson.createArray();
  while (index < 15) {
    aJsonObject* ArrayItem = aJson.createObject();
    
    //aJson.addItemToObject(root, "list", ArrayItem);
    
    aJson.addStringToObject(ArrayItem, "id", "Test");
    
    aJson.addStringToObject(ArrayItem, "name","Sensor " + char(index));
    
    aJson.addNumberToObject(ArrayItem, "value", int(random(30)));
    
    aJson.addItemToArray(root, ArrayItem);
    
    Serial.println(index);
    index++;
  }
  
    bfill.print(F("HTTP/1.1 200 OK\r\n"
    "Cache-Control: no-cache\r\n"
    "Content-Length: 000\r\n"
    "Connection: close\r\n"
    "Content-Type: application/json\r\n\r\n"));
    contentStart = bfill.position();

  bfill.print(aJson.print(root));
  
  writeContentLength(bfill);
  
  Serial.println(aJson.print(root));
  Serial.println(freeRam());
  Serial.println("done");
}



void loop(){

   word len = ether.packetReceive();
  word pos = ether.packetLoop(len); 
  
  if (pos) {
    
    delay(1);   // necessary for my system
        bfill = ether.tcpOffset();
         char *data = (char *) Ethernet::buffer + pos;
         
         if (strncmp("GET /", data, 5) == 0) {
              data += 5;
              //We just want to load the data when we navigate to the IP, and not re-load it when arduino refreshes the page with the json-data
              if (data[0] == ' ') {
                listJson();
                Serial.println("Sending");
              }
         }
         


        ether.httpServerReply(bfill.position());    // send http response

        
  
    
    
        
    }

  }

but, in both the Serial console and the webpage i only get this:

[{"id":"Test","name":"ensor ","value":7},{"id":"Test","name":"nsor ","value":19},{"id":"Test","name":"sor ","value":23},{"id":"Test","name":"or ","value":8},{"id":"Test","name":"r ","value":10},{"id":"Test","name":" ","value":2},{"id":"Test","name":"","va

So it breaks the data in the middle of a json-object.
Also, the name value should be "Sensor X", but the integer is not printed and for each cycle of the loop, a letter from "Sensor" disappears( 1st: "ensor", 2nd: "nsor", 3nd: "sor" and so on)
The memory shows "4687" when the data is printed to the BufferFiller.

The json-library I'm using is aJson

Anyone got some ideas?