Go Down

Topic: String vs string vs char + Arrays? Correct approach? (Read 25 times) previous topic - next topic

xl97

Hey gang-

I'm hoping someone can educate me here where I am little unclear on how to go about/approach this.

I know/understand that we SHOULD NOT (ever) use the "S"tring clas (capital "S" here)...  and should use string or char.

Its a shame the String class causes those stack/heap (whatever) errors... as it easier to understand/work with
*IMHO at least.. but what do I know.. I'm a spoiled web developer, so taking in to account memory/space issues is foreign to me.. and I'm having some difficulty wrapping my brain about how one goes doing the following.


Summary: 
* I want to take some incoming serial data...
* It has start & ending packet (characters) to signify the start and end of the incoming data
* The data 'between' the SOP/EOP characters is varying length.

What I'd like to do (in a perfect world).. would be to take this incoming serial data, and chop the data between the SOP/EOP characters by the comma delimiter... and put each of these 'chunks' of data into an Array.

Here is where I get a little unclear on how to do things.

Strings are bad... so using an array of strings is also bad.....right?
If we use char arrays...  each 'character' is an item/index in the array..... right?

So how do we 'store' several characters together as one 'index' in an array?
I have read serial basics...etc..  but I dont think that applies to what I am asking here.. I'm not asking how to collect the incoming serial data to some variable.

I'm not asking how to break it up by some delimiter  (well sorta!..lol)...

I'm specifically asking about breaking it up and having those groups of values be stored 'together' in an array index?


Here is some code to perhaps help illustrate things.

//serial format examples
//<b=1:1,b=2:1,m=6:200>
//<b=1:1,b=2:1,b=5:2,m=6:100,m=2:300>

There is no telling how many 'snippets/chunks' there will be between the < & > characters..
There could be 2 or 3.. or up to maybe 10?

I would say that each 'chunk' would NOT be more than 8-10 chars (tops...probably not more than 8)..
But for the same of planning..lets say 10 'chunks' of no more than 10 characters each.. so 100 character (max) on any incoming serial 'command'.

I'd like to get each:
b=1:1,
b=2:1,
b=5:2,
m=6:100,
m=2:300

into an array... so I can just loop through the array and parse each 'action'..  and when the array is done.. there are no more 'actions/steps' to be performed...etc..

fake example:
parse...parse

Code: [Select]
actionArray[counter] = (add delimited chunk here,,blah blah); 

*(but this would need to be a String array...right?  (which we do not want?)

in the end left with something like:

Code: [Select]
actionArray['b=1:1','b=2:1','b=5:2','m=6:100','m=2:300'];

*(but this would need to be a String array...right?  (which we do not want?)


Then loop through the above array:

Code: [Select]
for(int z=0; z<30; z++) {
        if(actions[z] != "0") {
          parseAction(actions[z]);
        }
}



So the above (for now) is my intended goal... but understanding how to go about WITHOUT using the String class has me a bit stumped.


In the code example below..

The parsing part is still assuming an older format....  (but even that was just to practice breaking up the string at specific delimiter)....  the same question holds true.. how can I get each snippet into an array to be parsed (acted upon) later on?

//example recipie format  (old format)
//<b=1:1><b=2:1><m=6:200> = bottle#1/1 shot, bottle#2/1 shot, mixer#6/200ms

//example recipie format  (new format)
//<b=1:1,b=2:1,m=6:200> = bottle#1/1 shot, bottle#2/1 shot, mixer#6/200ms


Code: [Select]
#define SOP '<'
#define EOP '>'
bool hasStarted = false;
bool hasEnded = false;

char incomingSerialData[100];
byte index;

int positionValue = 0;
int amountValue = 0;

void setup() {
  //serial monitor output
  Serial.begin(9600);
}

//example recipie format  (old format)
//<b=1:1><b=2:1><m=6:200> = bottle#1/1 shot, bottle#2/1 shot, mixer#6/200ms

//example recipie format  (new format)
//<b=1:1,b=2:1,m=6:200> = bottle#1/1 shot, bottle#2/1 shot, mixer#6/200ms



void loop(){

  // Read all serial data available, as fast as possible
  while(Serial.available() > 0){
    char incomingCharacter = Serial.read();
    //Serial.println(incomingCharacter);
    if(incomingCharacter == SOP){
      index = 0;
      incomingSerialData[index] = '\0';
      hasStarted = true;
      hasEnded = false;
    }else if (incomingCharacter == EOP){
      hasEnded = true;
      break;
    }else{
      if (index < 100) {
        incomingSerialData[index] = incomingCharacter;
        index++;
        incomingSerialData[index] = '\0';
      }
    }
  }

 // Packet data done...parse/evaluate data
  if(hasStarted && hasEnded){

    Serial.print("TOTAL COMMAND PACKET (CP) CHECK: ");
    Serial.println(incomingSerialData);
    char *actionToken = strtok(incomingSerialData, "="); //split action value from location/amount values
    if(actionToken){
      Serial.print("ACTION COMMAND: ");
      Serial.println(actionToken);  
          
      //check if bottle 'action' data coming over
      if(strcmp(actionToken, "b") == 0){      
        //grab position value    
        char *positionToken = strtok(NULL, ":");
        if(positionToken){
          Serial.print("BOTTLE #: ");
          Serial.println(positionToken);
          positionValue = atoi(positionToken);

          //now grab 'amount' value
          char *amountToken = strtok(NULL, "\0");
          if(amountToken){
            Serial.print("SHOT COUNT: ");
            Serial.println(amountToken);
            amountValue = atoi(amountToken);
          }
        }
      }

      //check if mixer action data coming over
      if(strcmp(actionToken, "m") == 0){
        char *positionToken = strtok(NULL, ":");
        if(positionToken){
          Serial.print("VALVE #: ");
          Serial.println(positionToken);
          positionValue = atoi(positionToken);
          //now grab 'amount' value
          char *amountToken = strtok(NULL, "\0");
          if(amountToken){
            Serial.print("OPEN TIME: ");
            Serial.println(amountToken);
            amountValue = atoi(amountToken);
          }
        }
      }
    }
    Serial.println("");
    // Reset for the next packet
    hasStarted = false;
    hasEnded = false;
    index = 0;
    incomingSerialData[index] = '\0';
  }





So for now..  we can ignore the innards of the:

Code: [Select]
if(hasStarted && hasEnded){}

conditional... and just use that break things up into an array.

Or at least that is my goal here.

Maybe there is a different better approach to be had for this scenario?

I know the serial 'format' could be changed to make it easier to parse..etc..  and when I get further along and I'll regroup and refactor that..but for now.. I am just concerned/curious about how to get those comma delimited values (strings?) into an array?  

Especially if we a NOT supposed to be using the String class?  Maybe its my thinking/understanding of the char arrays that is flawed?

Maybe this is a situation where the String class may be acceptable?  (although that incoming serial data >> array will happen over and over and over and over)

Basically a touch screen 'menu' will be sending this command/action (serial string) over, anytime someone uses the touch screen menu.


So to re-cap:

How can I parse incoming serial data by a comma delimiter and store those values into an array.. if we are NOT supposed to use the String class?

Thanks.

Perehama

You want an array of c style strings, which is an array of chars... In other words, a multi-dimensional array of chars.
Code: [Select]
char scientists[4][10] = {"Newton",
                          "Maxwell",
                          "Einstein",
                          "Feynman"};


The only caveat is that you have to have some max length for the field.
F=C/V=(A*s)/V=J/V^2=(W*s)/V^2=(N*m)/V^2=C^2/J=C^2/(N*m)=(s^2*C^2)/(m^2*Kg)=s/Ω=1/(Ω*Hz)=s^2/H

Go Up