Help with dynamically adding elements to an array

Hi All,

I need some help dynamically assigning elements to an Array. Let me explain part of the project:

  1. PC will send a series of "commands" to the Arduino
  2. The Arduino will store these commands in an array
  3. The Arduino will then loop through the array and process each command

As an example, the PC might send the following commands "pin1high", "pin2high", "pin1low", "pin2low", etc...

As each command is received, it needs to be stored in an array. If I were to hard code the array with the commands it would look like this:

char* commands[]={"pin1high","pin2high","pin1low","pin2low"};

However, I need it to be dynamic and the array filled up with whatever I send to it.

The Arduino would then loop through the array and based on my code logic do certain things based on the command.

Here is my code:

#include <WString.h>

String serialBuffer = String(500); 
String sendcmd=String(50);

long previousMillis = 0;


char* chaseBufferA[50]={};
int bufferSequence=0;

void setup() {
  Serial.begin(9600);
  serialBuffer="";
}

void loop() {
  if (Serial.available() > 0) {
    char inChar = Serial.read();
    if (inChar!='^') {
      serialBuffer.append(inChar);
    } else {
      processBuffer(serialBuffer);
      serialBuffer=""; 
    } 
  }
}

void processBuffer(String processCommand) {
      if (processCommand.equals("test")) {
            Serial.println("testok^");
      } else if (processCommand.equals("forcestart")) {
            Serial.println("getbuffer^");
      } else if (processCommand.equals("init")) {
            Serial.println("initok^");
      } else if (processCommand.equals("getbuffer")) {       
            for (int i=1; i<=10; i++) {  
              Serial.println(chaseBufferA[i]);
              delay(200);
            }
      } else {
            bufferSequence++;
            sendcmd="Unrecognised Command: ";
            sendcmd.append(processCommand);
            sendcmd.append("^");
            chaseBufferA[bufferSequence]=sendcmd;
            Serial.println(chaseBufferA[bufferSequence]);        

      }
}

Essentially what this code does is when it receives the command "getbuffer" it will dump the contents of the array - otherwise it adds the command to the array and dumps what it just added.

In the section that adds it to the array, it echoes it back correctly. However when I loop through the array to show everything stored in it, each element of the array seems to be the last command it received.

So for example, if i send "pin1high","pin2high","pin1low","pin2low" - chaseBufferA[0] should equal "pin1high", chaseBufferA[1] should equal "pin2high", etc... But when I loop through the array, every element is the last command received, in this case "pin2low"

Does this make sense...? Help please.

Hi,

one way to do this is to set up an array of fixed size, for example

char myarray[256];

Then define a read index and a write index and set both to 0;
Every received char is written to myarray[writeindex++],
Every time readindex is != writeindex you can read a char from from myarray[writeindex++] and process it like you do now in your loop with Serial.read();

If you use an array of 256 char and make readindex and writeindex of size int8 this works without any further processing, otherwise you must check if readindex or writeindex exceed the array limit and reset it to zero if so.

You can also implement an overrun check: after you have written a character to the array, check if readindex == writeindex, then the array is full, set a flag "arrayfull" and do not write any further received character until arrayfull is reset. Reset arrayfull every time you read a character from the array.

This implements a circular buffer. If you really want dynamic storage you have to use pointers and implement a list of strings for example on the heap.

Mike

There's a couple things you can do.

You could setup a simple protocol, something like
3command1command2command3

is ascii 0x02, is ascii 0x0d, and is 0x04.

STX will indicate the beginning of the command list which will be separated by CR characters and end with the EOT character. The first value will be how many commands to be received - make it a single byte. This would allow you to allocate the appropriate amount of memory. I would make the commands one byte - the left most bit will be 1 or 0 for high or low. The rest of the bits to specify the pin. ACtually, if you kept everything to one byte sizes you wouldn't need the . You know the first byte after a STX is the number of bytes to read to get all of the commands. The EOT wouldn't really be needed then either. However, it would help you determine if the correct amount of commands were sent.

There are dynamic array classes for C++ out there, but I would think a simple protocol with memory management would be more efficient.

Edit: my bad - you wouldn't want the start and end bytes to be STX and EOT. They could get confused with commands w=since STX = 0x02 and EOT is 0x04 - which could be confused with the commands to turn off pins 2 and 4. So make the bytes something like 0x80 and 0x81.

My C is rusty so the syntax may not be 100% accurate, but you should get the idea.

To encode a command it would be like

byte encodeCommand(byte state, byte pin)
{
      //example: byte command = encodeCommand(HIGH, 2); 
      //will mean pin 2 high
      //wiring.h for the arduino defines HIGH as 0x1 and LOW as 0x0
      //So shift that value to set it as the left more bit or the return but
      //then and it with the pin.
      //Pin 2 on high should give you the byte 10000010
      return ((state << 7) & pin);
}

void decodeCommand(byte command, byte &state, byte %pin)
{
      state = (command >> 7);
      pin = (command & B01111111);
}

If you really want to save on memory you can replace the decodeCommand with a doCommand(byte command) that contains one line of code: digitalWrite((command & B01111111), (command >> 7);

After you read the byte that defines the number of commands to be send you can use realloc to reallocate the array to the approiate size. You will also need to keep track of the array size. Once you create the array if you make a processCommands() function the parameters would be (byte *commands, byte size).

Word of warning. Read up on how to use realloc, malloc, calloc, and free properly so you don't run into memory leaks.