"Filtering" Char Array

Hello All,
I would assume that is has been covered several times before but I have been searching the forum and can't find what I'm looking for. I assume I'm just not searching for the right terminology. By the way I have been programming Arduino all of 2 weeks now so thank you for all your help thus far.

I have a command set that I am sending via UDP to the arduino from a c#.net program I created. Everything is working fin on that front. Now I am trying to split a character array into multiple char arrays based on a prefix. For example the command may be L500R500 . I can identify the prefix characters from the using the code below but then I get stuck. How do I get the next 3 characters after "L" and set them to a new array?

// packetSize is the size of the UDP char array and packetBuffer is the UDP char array

for(int x =0; x < packetSize +1; x ++){
 
 if(packetBuffer[x] == 'L') {

//get the next 3 characters and set them to Lspeed[4] char array

Lmotor = atoi(Lspeed); //convert to Lspeed array to integer for use in motor speed set command
}

avr-libc: <string.h>: Strings See strncpy function

Thanks I'll give that a shot. But can you use atoi() to convert a string to an integer?

brian2sos:
Thanks I'll give that a shot. But can you use atoi() to convert a string to an integer?

The whole purpose of atoi() is to convert a char string to an integer.

brian2sos:
Hello All,
I would assume that is has been covered several times before but I have been searching the forum and can't find what I'm looking for. I assume I'm just not searching for the right terminology. By the way I have been programming Arduino all of 2 weeks now so thank you for all your help thus far.

I have a command set that I am sending via UDP to the arduino from a c#.net program I created. Everything is working fin on that front. Now I am trying to split a character array into multiple char arrays based on a prefix. For example the command may be L500R500 . I can identify the prefix characters from the using the code below but then I get stuck. How do I get the next 3 characters after "L" and set them to a new array?

// packetSize is the size of the UDP char array and packetBuffer is the UDP char array

for(int x =0; x < packetSize +1; x ++){

if(packetBuffer[x] == 'L') {

//get the next 3 characters and set them to Lspeed[4] char array

Lmotor = atoi(Lspeed); //convert to Lspeed array to integer for use in motor speed set command
}

You could change that for loop into a while( x < packetSize ) { } block. Inside that you'd have an if() block to check for 'L' and the else to check for 'R' or maybe a switch-case for many possible letter codes.
Then inside each of those another block to check the next characters as numbers, being sure to increment through x as your iterator. If I see '1', '2', '3' then I can make a variable first = 1 and then multiply that by 10 and add the 2, then multiply that by 10 and add the 3 (you know that '3' - '0' = 3?).
But what a pain if I don't get the expected 3 digits in a row, I'd need to use peek() to check the next serial character without removing it --- all that structure built and more if the patterns are not the same....

or

You could write a state engine and get away with far less brackets and indents and have code that can react at the speed of loop(). In a case like yours I wouldn't need to buffer any serial input at all.

The whole idea is keep track of what is going on and use different blocks of code to react according to that. State is "what is going on" turned into numbers. This lets you run through loop() time after time only doing what is needed and not having to build structures to read and evaluate in one pass. It frees you from buffering and needing to do much string manipulation except in cases where you have to save something for later which can easily be less than half the time.
It also lets you do other tasks unrelated to your serial i/o in between capturing serial bytes. If you keep the code for each time through loop() very small then your code can react to events in much less than a millisecond, likely on the order of 100x per millisecond.
Adding states is as easy as adding blocks of code. It is a great way to avoid making spaghetti code.

In your case it might go like this;

State 0 would be the initial state, state 1 would be for having found an 'L' and state 2 would be for having found an 'R'. Errors, anything out-of-place or incomplete would be negative numbers or high numbers (here, numbers over 100 so you have space to add more than 'L' and 'R') making each error able to have it's own state as in identifier for error handling/messages. Don't leave out error handling especially if i/o is involved, serial transmission has no guarantee. If there's a human at the other end then just assume that Murphy Was An Optimist. If it ain't right, it's an error!

Inside loop() I would have a switch-case on the value of state.
Case 0 would look for an 'L' or an 'R' and if 'L' then change the state to 1, if 'R' then state=2, if something else then state=101.
Case 1 and case 2 would look for digits and evaluate (or flag error by changing the state). If case 1 or 2 runs into another letter then stop, call whatever function is appropriate to your case. Case 1 with value 500 is "L500". What other letter you got, set case to match that. If you make the case 0 code into a function (that case 0 calls) then you can use that. If you reach the end of the packet then set state to 0 and the next packet will start looking for a code letter.
The default case can catch all the error codes. I write more about error handling below.

Evaluating digits should probably be done by a function that takes the stored value (which was set to zero back when case 0 found an 'L' or 'R'), multiply by 10 and add the new digit then return the result, it is your new stored value. A 3 digit number will pass through this function 3 times. In between, if anything unexpected changes then this function won't keep your sketch from detecting that.

Error handling... what can I say? Usually empty the buffer. Whether you keep going or not depends on something at the other end being able to deal with an error report or even needing to but generally you want your input to match some pattern if your code it to act upon it.

You can write your code so it does everything top to bottom like you might on a PC or you can use the fact that with loop() you will get there in a matter of steps. The first way requires usually a geometric increase in code structure with increase in task complexity. The second way does not.
It's your choice.

How do I get the next 3 characters after "L" and set them to a new array?

You can use memcpy:

for(int x =0; x < packetSize +1; x ++){
 
   if(packetBuffer[x] == 'L') {
     //get the next 3 characters and set them to Lspeed[4] char array
    char Lspeed[4];
    void *pos = (void *) &(packetBuffer[++x]); // address of the next char after 'L'
    memcpy((void *)Lspeed, pos, 3); // copy three chars
    Lspeed[3] = 0; // terminate the string
    x += 3;  // update the index
 
   Lmotor = atoi(Lspeed); //convert to Lspeed array to integer for use in motor speed set command
  }
}

Is "L500R500" the same format every time? If so you can split the string in 1 line of code, no memcpy() etc needed.


Rob