Serial filtering program issues - running out of memory.

Hi All,

I’m using a Mega 2560 to recieve data on the Serial1 port and filter the data, then send it back out the Serial2 port to a radio transmitter. I need to use 2d arrays to hold boolean’s and int’s after certian data is received. I’m also comparing Strings in the program, and using the FLASH/PROGMEM library Flash | Arduiniana to store arrays of text for comparison and string output.

The problem so far is that once i scale the application up, the memory drops, and the mega crashes. Is there a better, more memory efficient way of doing what i need to do? My program crashes at 90 rooms (defined in my code) with 505 bytes available, but i need to step it up to 500-1000 rooms. Do i need to use external storage? Please guide me to a better way of accomplishing this…

Example data sent into Serial1 : “07/04/13 14:44:05 100 NORMAL CALL PLACED”

#include <Flash.h>
#include <Streaming.h>
#include <SimpleTimer.h>
#include <TextFinder.h>
#include <SD.h>


#define ROOM_COUNT 90  //MULTIPLIER THAT GROWS ARRAYS SIZE
#define LEVELS_COUNT 13
#define TRIGGERS_COUNT 2


File myFile;
TextFinder finder( myFile );






int ShiftType = 1;
int Level0 = 0;
int Level1 = 20;
int Level2 = 40;
unsigned int CallTimeout = 50; //defualt = 10800


SimpleTimer timer;





int PagerArray0[ROOM_COUNT][3] = {
  {0}  
};

int PagerArray1[ROOM_COUNT][3] = {
  {0}  
};

int PagerArray2[ROOM_COUNT][3] = {
  {0}  
};

int PagerArray3[ROOM_COUNT][3] = {
  {0}  
};



int CurrentShift = 0;
boolean SDCardReady = false;
String SDstring = "";
boolean SDstringComplete = false;


boolean CallArray[ROOM_COUNT][LEVELS_COUNT];
int TimeArray[ROOM_COUNT][LEVELS_COUNT];



String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;

void setup()
{


  // Open serial communications and wait for port to open:
  Serial.begin(9600); // debug port.
  Serial1.begin(9600);
  Serial2.begin(9600);
  inputString.reserve(200);


   InitializeSD();
  LoadSettingsFromSD();
  DebugSettings();
  
  LoadPagerArray0();



  Serial << F("System Ready.") << "\r\n";


  for (int i=0; i<ROOM_COUNT; i++) {
    for (int x=0; x<LEVELS_COUNT; x++) { 
      CallArray[i][x] = false;
      }
  }

  timer.setInterval(1000, ScanAndUpdateArrays);

  Serial.print("Available Memory: ");
  Serial.print(availableMemory());
  Serial.println(" bytes");  

}

void loop()
{
  serialEvent();
  serialEvent1();
  timer.run();
}









void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read(); 
    inputString += inChar;

    if (inChar == '\r') {
      stringComplete = true;
    } 

    if (stringComplete) {
      inputString.trim();
      
      Finder_Engine(inputString);

      inputString = "";
      stringComplete = false;

      Serial.print("Available Memory: ");
      Serial.print(availableMemory());
      Serial.println(" bytes");
    }
  } 
}

void serialEvent1() {
  while (Serial1.available()) {
    char inChar = (char)Serial1.read(); 
    inputString += inChar;

    if (inChar == '\r') {
      stringComplete = true;
    } 

    if (stringComplete) {
      inputString.trim();
      
      Finder_Engine(inputString);

      inputString = "";
      stringComplete = false;

      Serial.print("Available Memory: ");
      Serial.print(availableMemory());
      Serial.println(" bytes");
    }
  } 
}

int availableMemory() 
{
  int size = 8000;
  byte *buf;
  while ((buf = (byte *) malloc(--size)) == NULL);
  free(buf);
  return size;
}



void Finder_Engine(String s){
  String ArchAddress;
  int RoomIndex = -1;
  String CallText;
  int CallIndex = -1;
  int TriggerIndex = -1;
  boolean CallBool;

  ArchAddress = s.substring(19, 30);
  ArchAddress.trim();

  char Arch[ROOM_COUNT][8]= {
    "101", "102", "103", "104", "105",
    "106", "107", "108", "109", "110",
    "111", "112", "113", "114", "115",
    "116", "117", "118", "119", "120"
  };





  for (int i=0; i<ROOM_COUNT; i++) {
    if (ArchAddress.indexOf(Arch[i]) >=0){
      RoomIndex = i;
    }     
  }


  CallText = s.substring(30);

  FLASH_STRING_ARRAY(CallLevels, 
  PSTR("CODE PINK"), PSTR("CODE BLUE"), PSTR("FIRE"), PSTR("STAFF EMER"), PSTR("PRIORITY"), PSTR("BATH"), PSTR("ALARM"),
  PSTR("CORDOUT"), PSTR("PERS ATTN"), PSTR("STAFF"), PSTR("NORMAL"), PSTR("NURSE NEEDED"), PSTR("AIDE NEEDED"));

  for (int i=0; i<CallLevels.count(); i++) { 

    char CallLevelsTmp[12];
    CallLevels[i].copy(CallLevelsTmp);
    if (CallText.indexOf(CallLevelsTmp) >=0){  //Call in Call Level Array (Call is Filtered)

      CallIndex = i;
    } 
  }


  FLASH_STRING_ARRAY(CallTriggers, 
  PSTR("CALL CANCELLED"), PSTR("CALL PLACED")); 


  for (int i=0; i<CallTriggers.count(); i++) {

    char CallTriggersTmp[12];
    CallTriggers[i].copy(CallTriggersTmp);   
    if (s.indexOf(CallTriggersTmp) >=0){  //Call in Call Level Array (Call is Filtered)

      TriggerIndex = i;
    }
  }



  if((RoomIndex >=0 ) && (CallIndex >= 0)){ // Values not zero

    if(TriggerIndex == 1){  //if Call Placed

      if(ReturnArray(RoomIndex,CallIndex) == false){    // call not placed Yet
        UpdateArray(RoomIndex,CallIndex,TriggerIndex);  // Place call and page for the first time.
      } 
      else {                                          // Call already placed
        UpdateArray(RoomIndex,CallIndex,TriggerIndex);  
      }
    } 
    else if(TriggerIndex == 0){  //Call cancelled
      UpdateArray(RoomIndex,CallIndex,TriggerIndex);
    }    
  } 
  else {              
    Serial << F("Bad/Ignored Data: ") << s << "\r\n";
  }
}

void UpdateArray(int room,int level, boolean b){
  CallArray[room][level] = b;

  Serial << F("Updating Array: ")<< room  << F(" and Level ") << level << F(" To : ") << b << "\r\n";

}

boolean ReturnArray(int room,int level){
  return CallArray[room][level];
}


void ScanAndUpdateArrays(){
  for (int i=0; i<ROOM_COUNT; i++) {
    for (int x=0; x<LEVELS_COUNT; x++) {

      if(CallArray[i][x] == 1){       

        if(TimeArray[i][x] == Level0){
          BuildPage(0, i,x); 
        }

        if(TimeArray[i][x] == Level1){
          BuildPage(1, i,x); 
        }

        if(TimeArray[i][x] == Level2){
          BuildPage(2, i,x); 
        }

        if(TimeArray[i][x] == CallTimeout){
          
          CallArray[i][x] = 0;
          Serial << F("Boolean Array Timeout Code: ");
          Serial.print(i);
          Serial << F("-");
          Serial.println(x);
            
        }
        ++TimeArray[i][x]; 
      } 
      else {
        TimeArray[i][x] = 0; 
      }  
    }
  }
}

void BuildPage(int CodeLevel, int room, int text){
  
FLASH_STRING_ARRAY(ReplacementArch,
  PSTR("Room 101"),PSTR("Room 102"),PSTR("Room 103"),PSTR("Room 104"),PSTR("Room 105"),
  PSTR("Room 106"),PSTR("Room 107"),PSTR("Room 108"),PSTR("Room 109"),PSTR("Room 110"),
  PSTR("Room 111"),PSTR("Room 112"),PSTR("Room 113"),PSTR("Room 114"),PSTR("Room 115"),
  PSTR("Room 116"),PSTR("Room 117"),PSTR("Room 118"),PSTR("Room 119"),PSTR("Room 120")  
  );
  

  char RoomTmp[20];
  ReplacementArch[room].copy(RoomTmp);

  FLASH_STRING_ARRAY(ReplacementCallLevels,
  PSTR("CODE PINK"), PSTR("CODE BLUE"), PSTR("FIRE"), PSTR("STAFF EMER"), PSTR("PRIORITY"), PSTR("Bathroom Assistance Needed."),
  PSTR("ALARM"), PSTR("CORDOUT"), PSTR("PERS ATTN"), PSTR("STAFF"), PSTR("NORMAL"), PSTR("NURSE NEEDED"), PSTR("AIDE NEEDED"));

  char MessageTmp[60];
  ReplacementCallLevels[text].copy(MessageTmp);



  Serial << F("Sending Page # ");
  Serial.print(CodeLevel+1);
   Serial << F(" to: ");
  if(CurrentShift == 0){Serial.print(PagerArray0[room][CodeLevel]);}
  if(CurrentShift == 1){Serial.print(PagerArray1[room][CodeLevel]);}
  if(CurrentShift == 2){Serial.print(PagerArray2[room][CodeLevel]);}
  if(CurrentShift == 3){Serial.print(PagerArray3[room][CodeLevel]);}
  Serial << F(" With Message( ");
  Serial.print(RoomTmp);
  Serial << F(" : ");
  Serial.print(MessageTmp);
  Serial << F(" )");
  Serial.write(13);
  Serial.write(10); 
  
  Serial2.write(1);
  Serial2 << F("A5");
  if(CurrentShift == 0){Serial2.print(PagerArray0[room][CodeLevel]);}
  if(CurrentShift == 1){Serial2.print(PagerArray1[room][CodeLevel]);}
  if(CurrentShift == 2){Serial2.print(PagerArray2[room][CodeLevel]);}
  if(CurrentShift == 3){Serial2.print(PagerArray3[room][CodeLevel]);}
  Serial2.write(2);
  Serial2.print(RoomTmp);
  Serial2 << F(" : ");
  Serial2.print(MessageTmp);
  Serial2.write(3);
  Serial2.write(4);
  Serial2.write(13);
  Serial2.write(10); 
  

}

Additional functions.

void InitializeSD(){

  Serial << F("Initializing SD card...");

  if (!SD.begin(4)) {
    Serial << F("initialization failed!");
    Serial.println();
    return;
  }
  Serial << F("initialization done.");
  SDCardReady = true;
  Serial.println();




}







void LoadSettingsFromSD(){

  if(SDCardReady){

    myFile = SD.open("SETTINGS.txt");
    Serial << F("Loading Settings.");
    if (myFile) {




      while (myFile.available()) {
        Serial << F(".");


        ShiftType = (int) finder.getValue();
        Serial << F("."); 
        Level0 = (int) finder.getValue();
        Serial << F("."); 
        Level1 = (int) finder.getValue();
        Serial << F("."); 
        Level2 = (int) finder.getValue();
        Serial << F("."); 
        CallTimeout = (int) finder.getValue();
        Serial << F(".");        
        myFile.read();
        Serial << F(".");
      }
      // close the file:
      myFile.close();

      Serial << F(" Loaded 100%");
      Serial.println();
    } 
    else {
      // if the file didn't open, print an error:
      Serial << F("ERROR - Cannot open! ");
      Serial.println();
    }

  }


}

void DebugSettings(){




  Serial << F("Shift Type = ");
  Serial.println(ShiftType);
  Serial << F("Level 0 = ");
  Serial.println(Level0);
  Serial << F("Level 1 = ");
  Serial.println(Level1);
  Serial << F("Level 2 = ");
  Serial.println(Level2);      
  Serial << F("CallTimeout = ");
  Serial.println(CallTimeout);
  Serial.println();
}



void LoadPagerArray0(){

  if(SDCardReady){
    myFile = SD.open("Shift0.txt");
    if (myFile) {
      Serial << F("Reading ");
      Serial.println("Shift0.txt");

     
      while (myFile.available()) {


        for(int i = 0;i<ROOM_COUNT;i++){
          int Level0 = (int) finder.getValue(); 
          int Level1 = (int) finder.getValue(); 
          int Level2 = (int) finder.getValue();

          Serial << F("Line ");
          Serial.print(i+1);
          Serial << F(" : ");
          Serial.print(Level0);
          Serial << F(", ");
          Serial.print(Level1);
          Serial << F(", ");
          Serial.print(Level2);

          PagerArray0[i][0] = Level0;
          PagerArray0[i][1] = Level1;
          PagerArray0[i][2] = Level2;

          Serial << F(" -> PagerArray0[");
          Serial.print(i);
          Serial << F("] = ");
          Serial.print(PagerArray0[i][0]);
          Serial << F(", ");
          Serial.print(PagerArray0[i][1]);
          Serial << F(", ");
          Serial.println(PagerArray0[i][2]);
        }

        myFile.read();
      }
      // close the file:
      myFile.close();
      Serial << F("done.");
      Serial.println();
    } 
    else {
      // if the file didn't open, print an error:
      Serial << F("error opening ");
      Serial.println("Shift0.txt");
    }
  }
}

void LoadPagerArray1(){

  if(SDCardReady){


    myFile = SD.open("Shift1.txt");
    if (myFile) {
      Serial << F("Reading ");
      Serial.println("Shift1.txt");

 
      while (myFile.available()) {


        for(int i = 0;i<ROOM_COUNT;i++){
          int Level0 = (int) finder.getValue(); 
          int Level1 = (int) finder.getValue(); 
          int Level2 = (int) finder.getValue();

       
          PagerArray0[i][0] = Level0;
          PagerArray0[i][1] = Level1;
          PagerArray0[i][2] = Level2;

         
        }

        myFile.read();
      }
      // close the file:
      myFile.close();
      Serial << F("done.");
      Serial.println();
    } 
    else {
      // if the file didn't open, print an error:
      Serial << F("error opening ");
      Serial.println("Shift1.txt");
    }

  }
}


void LoadPagerArray2(){

  if(SDCardReady){

    myFile = SD.open("Shift2.txt");
    if (myFile) {
      Serial << F("Reading ");
      Serial.println("Shift2.txt");

      // read from the file until there's nothing else in it:
      while (myFile.available()) {


        for(int i = 0;i<ROOM_COUNT;i++){
          int Level0 = (int) finder.getValue(); 
          int Level1 = (int) finder.getValue(); 
          int Level2 = (int) finder.getValue();

          
          PagerArray0[i][0] = Level0;
          PagerArray0[i][1] = Level1;
          PagerArray0[i][2] = Level2;

     
        }

        myFile.read();
      }
      // close the file:
      myFile.close();
      Serial << F("done.");
      Serial.println();
    } 
    else {
      // if the file didn't open, print an error:
      Serial << F("error opening ");
      Serial.println("Shift2.txt");
    }
  }
}



void LoadPagerArray3(){

  if(SDCardReady){

    myFile = SD.open("Shift3.txt");
    if (myFile) {
      Serial << F("Reading ");
      Serial.println("Shift3.txt");

      // read from the file until there's nothing else in it:
      while (myFile.available()) {


        for(int i = 0;i<ROOM_COUNT;i++){
          int Level0 = (int) finder.getValue(); 
          int Level1 = (int) finder.getValue(); 
          int Level2 = (int) finder.getValue();


          PagerArray0[i][0] = Level0;
          PagerArray0[i][1] = Level1;
          PagerArray0[i][2] = Level2;


        }

        myFile.read();
      }
      // close the file:
      myFile.close();
      Serial << F("done.");
      Serial.println();
    } 
    else {
      // if the file didn't open, print an error:
      Serial << F("error opening ");
      Serial.println("Shift3.txt");
    }
  }
}

NB: You do not need to call serialEvent() or serialEvent1() (currently in your loop() function) - they are called automatically for you.

'1284P, 16K SRAM.
Need more than that? Add external.

Please note that in versions of the IDE up to and including 1.0.3, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.), as described here for example.

Alternatively, install the fix described here: Fixing String Crashes

Preferably upgrade your IDE to version 1.0.4 or above at: http://arduino.cc/en/Main/Software

Consider that storing your booleans

boolean CallArray[ROOM_COUNT][LEVELS_COUNT];

requires ROOM_COUNT x LEVELS_COUNT bytes (90 x 13 = 1170 bytes) even though in effect you only require 1170 bits (~147 bytes) to do this effectively.

Also, consider you are storing values between 0 and 40 in your pagerArrays, but they are int arrays, requiring 2 bytes per array element. If the values being stored in the pagerarray are <= 255, you can get away with usng byte/char arrays.

So 4 x 90 x 3 x 2 = 2160 bytes, can be halved to 1080 bytes.

If you can use these 2 optimisations, you could save around (1080 + 1023) = 2100 bytes.

When I see things like this (even without understanding the code fully):

FLASH_STRING_ARRAY(ReplacementArch,
  PSTR("Room 101"),PSTR("Room 102"),PSTR("Room 103"),PSTR("Room 104"),PSTR("Room 105"),
  PSTR("Room 106"),PSTR("Room 107"),PSTR("Room 108"),PSTR("Room 109"),PSTR("Room 110"),
  PSTR("Room 111"),PSTR("Room 112"),PSTR("Room 113"),PSTR("Room 114"),PSTR("Room 115"),
  PSTR("Room 116"),PSTR("Room 117"),PSTR("Room 118"),PSTR("Room 119"),PSTR("Room 120")  
  );

my immediate thought is:

  1. take the "Room" out as a constant
  2. reduce the room number (currently 3 bytes) to a byte (1 byte).
  3. if 1xx is the floor number, take the floor number out as a constant also, and then rooms can definitely be stored in a byte.

This trades off processing time for space, and requires a little more programming (as do my other suggestions).

It's not going to say you memory, but any reason for not doing

int PagerArray[SOME_CONSTANT][ROOM_COUNT][3] = {
  {0}  
};

?

technochris1:

  FLASH_STRING_ARRAY(CallLevels, 

PSTR(“CODE PINK”), PSTR(“CODE BLUE”), PSTR(“FIRE”), PSTR(“STAFF EMER”), PSTR(“PRIORITY”), PSTR(“BATH”), PSTR(“ALARM”),
 PSTR(“CORDOUT”), PSTR(“PERS ATTN”), PSTR(“STAFF”), PSTR(“NORMAL”), PSTR(“NURSE NEEDED”), PSTR(“AIDE NEEDED”));

FLASH_STRING_ARRAY(ReplacementCallLevels,
 PSTR(“CODE PINK”), PSTR(“CODE BLUE”), PSTR(“FIRE”), PSTR(“STAFF EMER”), PSTR(“PRIORITY”), PSTR(“Bathroom Assistance Needed.”),
 PSTR(“ALARM”), PSTR(“CORDOUT”), PSTR(“PERS ATTN”), PSTR(“STAFF”), PSTR(“NORMAL”), PSTR(“NURSE NEEDED”), PSTR(“AIDE NEEDED”));

There’s a lot of double up between these two. It seems you could replace the second array with an if for the one entry that does change (BATH) and save some more memory here.

I’m currently running 1.0.5 and 1.5.

aarondc:
Consider that storing your booleans

boolean CallArray[ROOM_COUNT][LEVELS_COUNT];

requires ROOM_COUNT x LEVELS_COUNT bytes (90 x 13 = 1170 bytes) even though in effect you only require 1170 bits (~147 bytes) to do this effectively.

Also, consider you are storing values between 0 and 40 in your pagerArrays, but they are int arrays, requiring 2 bytes per array element. If the values being stored in the pagerarray are <= 255, you can get away with usng byte/char arrays.

So 4 x 90 x 3 x 2 = 2160 bytes, can be halved to 1080 bytes.

If you can use these 2 optimisations, you could save around (1080 + 1023) = 2100 bytes.

Thanks for explaining it too me, ill try these optimizations first.

aarondc:
When I see things like this (even without understanding the code fully):

FLASH_STRING_ARRAY(ReplacementArch,

PSTR(“Room 101”),PSTR(“Room 102”),PSTR(“Room 103”),PSTR(“Room 104”),PSTR(“Room 105”),
  PSTR(“Room 106”),PSTR(“Room 107”),PSTR(“Room 108”),PSTR(“Room 109”),PSTR(“Room 110”),
  PSTR(“Room 111”),PSTR(“Room 112”),PSTR(“Room 113”),PSTR(“Room 114”),PSTR(“Room 115”),
  PSTR(“Room 116”),PSTR(“Room 117”),PSTR(“Room 118”),PSTR(“Room 119”),PSTR(“Room 120”) 
  );




my immediate thought is:
1. take the "Room" out as a constant
2. reduce the room number (currently 3 bytes) to a byte (1 byte).
3. if 1xx is the floor number, take the floor number out as a constant also, and then rooms can definitely be stored in a byte.

This trades off processing time for space, and requires a little more programming (as do my other suggestions).

The reason for this is that in the end each room wont be labeled the same, while most will say “Room” first , 20% or so will be entirely different. “Public Restroom”, “Staff Lounge”…

aarondc:
It’s not going to say you memory, but any reason for not doing

int PagerArray[SOME_CONSTANT][ROOM_COUNT][3] = {

{0} 
};




?

I assumed anything deeper than 2D was a no-no. Isn’t that a 3D array?

aarondc:

technochris1:

  FLASH_STRING_ARRAY(CallLevels, 

PSTR(“CODE PINK”), PSTR(“CODE BLUE”), PSTR(“FIRE”), PSTR(“STAFF EMER”), PSTR(“PRIORITY”), PSTR(“BATH”), PSTR(“ALARM”),
  PSTR(“CORDOUT”), PSTR(“PERS ATTN”), PSTR(“STAFF”), PSTR(“NORMAL”), PSTR(“NURSE NEEDED”), PSTR(“AIDE NEEDED”));

FLASH_STRING_ARRAY(ReplacementCallLevels,
  PSTR(“CODE PINK”), PSTR(“CODE BLUE”), PSTR(“FIRE”), PSTR(“STAFF EMER”), PSTR(“PRIORITY”), PSTR(“Bathroom Assistance Needed.”),
  PSTR(“ALARM”), PSTR(“CORDOUT”), PSTR(“PERS ATTN”), PSTR(“STAFF”), PSTR(“NORMAL”), PSTR(“NURSE NEEDED”), PSTR(“AIDE NEEDED”));

There’s a lot of double up between these two. It seems you could replace the second array with an if for the one entry that does change (BATH) and save some more memory here.

The reason for this is that the incoming data contains text that is matched in CallLevels. Once it is found, the index that is found at is used on the ReplacementCallLevels to build the last message with new text. In the end there will be no duplicates between these two arrays. Example would be the relationship between “BATH” in CallLevels & “Bathroom assistance needed”. “BATH” needs to be changed to “Bathroom assistance needed” when it leaves the arduino.

Even with optimization, does it even seem that the arduino Mega will handle this at 500-1000 rooms? I have the 32bit Due to try it on as a last resort.

assumed anything deeper than 2D was a no-no. Isn't that a 3D array?

Yes it is a 3D array and yes you can use them.

1000 rooms allows you to store ~ 8 bytes per room.
But then you have no stack space for calling functions, etc.

It would be helpful to understand a brief overview of your project. If you can throw the biggest memory board at it, that might solve your problem for free.

One flaw in your design, however, is that you are unnecessarily setting aside static memory for an unlikely scenario.

ie I am guessing you are setting up some sort of hospital / care facility response system, where patients (or staff) press buttons requesting certain services to be performed and this has to be logged and then a timer tracking response times.

My point being: it is unlikely that you will have 1000 rooms simultaneously requesting assistance. Even if you had half the rooms requesting it, as soon as a response has been handled, you don't need that data any more, and could reuse the memory it occupies fairly simply.

If you can create a basic data structure along the lines of (this is not code, it will not compile, extraneous brackets may be present):

struct requestType {
    byte room_name_pointer; // pointer to an array of room names
    byte room_floor;    // floor this room appears on
    byte room_number; /// guess ;-)
    byte service_requested; // pointer to an array of possible services
    int request_start_time;  // when we requested the service
(etc)
}

and then a circular buffer similar to what Serial library implements, based on the maximum concurrent requests expected to be current at any one time, +20% to +100%:

requestType request_buffer[200];

As an example, the Serial library can handle megabytes of input, as long as you process it in a timely fashion, despite the fact that the default Serial buffer is only 64 bytes in size.

If you are expecting 120 requests / hour (2 / minute) max, and the longest request response time is 1 hour (just as an example), then you'd only need to store 120 such requests, and for the majority of the time, you'd have less than that in the buffer waiting to be completed.

Example would be the relationship between "BATH" in CallLevels & "Bathroom assistance needed". "BATH" needs to be changed to "Bathroom assistance needed" when it leaves the arduino.

Even with optimization, does it even seem that the arduino Mega will handle this at 500-1000 rooms? I have the 32bit Due to try it on as a last resort.

That example has about 33 bytes in it if you count the trailing null bytes. So you are asking if you can fit (about) 33K into 256K of program memory, yes you can.

once i scale the application up, the memory drops

What memory? SRAM or program memory? SRAM shouldn't go up if you are putting strings into PROGMEM.

Another approach would be to keep the strings on an SD card and simply read it each time, if you could afford to spare a second or two.

  Serial.print("Available Memory: ");
  Serial.print(availableMemory());
  Serial.println(" bytes");

How about telling us what that is telling you?

The room count has nothing to do with the names of the rooms, and more to do with the arrays he is declaring at the top x 4:

int PagerArray0[ROOM_COUNT][3] = {

That would be 4 x 1000 x 3 array elements of ints (x 2) == 24,000 bytes just for those 4 arrays.

I wasn't considering his code as such, just whether there was enough memory to hold the requirements, if written properly.

For me, this sort of code yells "memory fragmentation" at me:

 while (Serial.available()) {
    char inChar = (char)Serial.read(); 
    inputString += inChar;

technochris1:
I'm using a Mega 2560 to recieve data on the Serial1 port and filter the data, then send it back out the Serial2 port to a radio transmitter

Given that you seem to be dealing with a significant amount of real-world data that would need to be configured and maintained, and perhaps dealing with messages that are important (must be delivered accurately and reliably), I wonder whether an Arduino-based solution is the best approach. It would be easy to implement the whole solution on a PC with a couple of USB-to-TTL-serial adapters, which gives you effectively unlimited memory and processing power, vastly improved support for storing and managing your configuration data, logging and so on. The sketch you already have would run on a PC as a console application more or less as it is as a starting point, just replacing the Arduino Serial API with the corresponding PC OS serial API.

aarondc:
1000 rooms allows you to store ~ 8 bytes per room.
But then you have no stack space for calling functions, etc.

It would be helpful to understand a brief overview of your project. If you can throw the biggest memory board at it, that might solve your problem for free.

One flaw in your design, however, is that you are unnecessarily setting aside static memory for an unlikely scenario.

ie I am guessing you are setting up some sort of hospital / care facility response system, where patients (or staff) press buttons requesting certain services to be performed and this has to be logged and then a timer tracking response times.

My point being: it is unlikely that you will have 1000 rooms simultaneously requesting assistance. Even if you had half the rooms requesting it, as soon as a response has been handled, you don't need that data any more, and could reuse the memory it occupies fairly simply.

If you can create a basic data structure along the lines of (this is not code, it will not compile, extraneous brackets may be present):

struct requestType {

byte room_name_pointer; // pointer to an array of room names
    byte room_floor;    // floor this room appears on
    byte room_number; /// guess :wink:
    byte service_requested; // pointer to an array of possible services
    int request_start_time;  // when we requested the service
(etc)
}




and then a circular buffer similar to what Serial library implements, based on the maximum concurrent requests expected to be current at any one time, +20% to +100%:

requestType request_buffer[200];

As an example, the Serial library can handle megabytes of input, as long as you process it in a timely fashion, despite the fact that the default Serial buffer is only 64 bytes in size.

If you are expecting 120 requests / hour (2 / minute) max, and the longest request response time is 1 hour (just as an example), then you'd only need to store 120 such requests, and for the majority of the time, you'd have less than that in the buffer waiting to be completed.

I seen that on the Arduino forum, but i have no idea how to utilize it. Your guess was almost dead on, it recieves the calls and send them to a paging transmitter . The arrays and timer arent used for checking on the response time, instead its used to re-page the call to different people. 120 calls an hour is actually a light load. Please explain to me or guide me where I can learn about this data structure.

PeterH:

technochris1:
I'm using a Mega 2560 to recieve data on the Serial1 port and filter the data, then send it back out the Serial2 port to a radio transmitter

Given that you seem to be dealing with a significant amount of real-world data that would need to be configured and maintained, and perhaps dealing with messages that are important (must be delivered accurately and reliably), I wonder whether an Arduino-based solution is the best approach. It would be easy to implement the whole solution on a PC with a couple of USB-to-TTL-serial adapters, which gives you effectively unlimited memory and processing power, vastly improved support for storing and managing your configuration data, logging and so on. The sketch you already have would run on a PC as a console application more or less as it is as a starting point, just replacing the Arduino Serial API with the corresponding PC OS serial API.

I actually did this already, and for several reasons including cost/reliability i didnt like the solution. I was considering a raspberry Pi. The arduino is hard to stop, where OS's on raspberry pi or a full Pc arent as stable/reliable. Right now logging isnt a must. Ive tested the current setup with great success, i think the arduino or similar chip would work great.

Is there an example for implementing a ring/circlular buffer on a struct data type, with incoming data from a serial port?

I think there’s one in HardwareSerial.cpp.
Apart from the “struct” part.