Strtok with different delimiters

ohh I see, so the difference between strcpy and strlcpy is that addition of sizeof data, right? It is automatically detecting the size of the data?

it's the maximum capacity allowed to be copied into your variable. So this way you won't overflow if there was more to copy.

Overflowing would basically start writing in the memory of other variables and probably ends up crashing your code. It's a good practice to ensure you never overflow.

1 Like

so if there might have route3, do I just add in as well?

if the number of routes can be variable, then I would write some smarter code.

seems the number of hops is the last data point, is that corresponding to the number of routes ?

yup.. it is related with the number of routes
do you mind to explain more on this...?

related or exactly the number of routes ? ie can we grab that number and know before hand how many routes we will need to parse ?

because if I would to assign for the maximum possible routes, it will be five, which is unnecessary occupying the space even if there are only two routes..

it is unknown until receive it, I know it will be easy if the number of routes are known before hand.

it is unknown until receive it

sure but once you get the payload, you could start parsing this and then you know how many to expect and thus use that information to drive the parser.

what's your arduino ?

how many of those "lines" do you need to keep in memory at a given time? (I remember the other discussion with the structure and you were keeping 5 of those?)

Allocating them dynamically is possible but will make the code more complex, if you reuse the slots you'll have a risk of heap fragmentation and you need to plan anyway for the maximum case and still have the code running.. So there is little harm allocating them statically.

the maximum will be five..

exactly.. :upside_down_face:

so if you go for static allocation you get 5 records of 5 arrays of 3 bytes = 75 bytes...
can you afford it ? what type of Arduino will you be running this on?

I am using Arduino Mega 2560

you have 8 Kbyte of SRAM. that's not a lot but might be enough.. depends what the rest of the code needs..

I would go for

struct t_message {
  char messageType;
  char sID[3];
  char dID[3];
  char routes[5][3];
  byte hops;
};

ie keep the messageType just as 1 char and convert the number of hops into a byte number rather than keeping it's ASCII string.

ya but since I am using strlcpy .. then I need to convert it the hops from char to bytes first before calling the struct

can you confirm that hops is the exact number of entries with the pipe separator - that is what you'l receive will ALWAYS be something like this

P,WE,PO,YI,1
P,WE,PO,YI|UY,2
P,WE,PO,YI|UY|XZ,3
P,WE,PO,YI|UY|XZ|AB,4
P,WE,PO,YI|UY|XZ|AB|CD,5

and that no other case is possible? (or is 0 possible?)

yup, the hop number increases along with number of routes accordingly..

not possible..

assuming there is no error possible in what is sent, then I'll do it this way:

const char * paylaods[] = {
  "P,WE,PO,R1,1",
  "P,WE,PO,R1|R2,2",
  "P,WE,PO,R1|R2|R3,3",
  "P,WE,PO,R1|R2|R3|R4,4",
  "P,WE,PO,R1|R2|R3|R4|R5,5"
};

struct t_message {
  char messageType;
  char sID[3];
  char dID[3];
  char routes[5][3];
  byte hops;
} messages[5];

void parseBuffer(const char * payload, t_message& message) {
  char tempChars[100];
  char * strtokIndx;

  Serial.print(F("\nParsing: "));  Serial.println(payload);
  strlcpy (tempChars, payload, sizeof tempChars);

  char * lastComa = strrchr(tempChars, ',');
  message.hops = *(lastComa + 1) - '0'; // will always be '1' to '5'
  Serial.print(F("\tHops: ")); Serial.println(message.hops);

  strtokIndx = strtok (tempChars, ",");
  message.messageType = (*strtokIndx);
  Serial.print(F("\tType: ")); Serial.println(message.messageType);

  strtokIndx = strtok (NULL, ",");
  strlcpy (message.sID, strtokIndx, sizeof message.sID);
  Serial.print(F("\tsID: ")); Serial.println(message.sID);

  strtokIndx = strtok (NULL, ",");
  strlcpy (message.dID, strtokIndx, sizeof message.dID);
  Serial.print(F("\tdID: ")); Serial.println(message.dID);

  for (char i = 0; i < message.hops - 1; i++) {
    strtokIndx = strtok(NULL, "|" );
    strlcpy(message.routes[i], strtokIndx, sizeof message.routes[0]);
    Serial.print(F("\tRoute #"));
    Serial.print((byte) i + 1);
    Serial.print(F(" : "));
    Serial.println(message.routes[i]);
  }

  strtokIndx = strtok(NULL, "," );
  strlcpy(message.routes[message.hops - 1], strtokIndx, sizeof  message.routes[0]);
  Serial.print(F("\tRoute #"));
  Serial.print(message.hops);
  Serial.print(F(" : "));
  Serial.println(message.routes[message.hops - 1]);
}

void setup() {
  Serial.begin(115200);
  // test the 5 types
  for (byte i = 0; i < 5; i++)   parseBuffer(paylaods[i], messages[i]);
}

void loop() 

the serial monitor will show you

Parsing: P,WE,PO,R1,1
	Hops: 1
	Type: P
	sID: WE
	dID: PO
	Route #1 : R1

Parsing: P,WE,PO,R1|R2,2
	Hops: 2
	Type: P
	sID: WE
	dID: PO
	Route #1 : R1
	Route #2 : R2

Parsing: P,WE,PO,R1|R2|R3,3
	Hops: 3
	Type: P
	sID: WE
	dID: PO
	Route #1 : R1
	Route #2 : R2
	Route #3 : R3

Parsing: P,WE,PO,R1|R2|R3|R4,4
	Hops: 4
	Type: P
	sID: WE
	dID: PO
	Route #1 : R1
	Route #2 : R2
	Route #3 : R3
	Route #4 : R4

Parsing: P,WE,PO,R1|R2|R3|R4|R5,5
	Hops: 5
	Type: P
	sID: WE
	dID: PO
	Route #1 : R1
	Route #2 : R2
	Route #3 : R3
	Route #4 : R4
	Route #5 : R5
1 Like

thanks! I guess struct is still the best method to go with..

yes, that's the appropriate container for your structured data :slight_smile:

1 Like

a bit off topic, then is it possible to add two char array in struct together? I mean addition operation.. can't seem to find the answer from other posts..

or can I assign pointers to them and then add them up?