doubt reading and handling of string

hello!

I have been reading about strings for several weeks because I can not solve a problem that I have, I am doing a project that receives a string constantly by the serial monitor but within that string the values change, someone could explain or help me to work with that string correctly to turn on and off leds?

in this image the numbers in red are the names of the variable
the numbers in blue are the values that are changing
and the green box is the complete string, as you see it is repeated in a loop

https://subefotos.com/ver/?b88090459abc8acff8b861c37ea5caa3o.png

thank you very much and greetings

Welcome to the forums. What have you tried to solve this? Please read the sticky posts at the top of the forum and post your code (using code tags) and any errors you have and people will help you debug the code.

As a starting point, in the Useful Links at the top of this Forum, there is a section titled Serial Basics. That would be a good place for you to start.

@OP

One transmission frame of your data could be taken as:
::2:0::3:0::5:0::6:0::7:0 yes/no?

or

variableTag(::)var1:value_of_var1, ..., variableTag(::)var5:value_of_var5

Few queries:
1. Is the identification code of a variable 1-digit (2, 3, 5, 6, 7)?
2. Is the value of a variable is 1-digit ( 0 to 9)?

blh64:
Welcome to the forums. What have you tried to solve this? Please read the sticky posts at the top of the forum and post your code (using code tags) and any errors you have and people will help you debug the code.

hello!

I have only read about the handling of strings and I tried some example of internet but it has not been what I was looking for to understand the operation of the type of string I have.

econjack:
As a starting point, in the Useful Links at the top of this Forum, there is a section titled Serial Basics. That would be a good place for you to start.

hello!

I'm going to look at them to see if I can understand more how the stirngs work

GolamMostafa:
@OP

One transmission frame of your data could be taken as:
::2:0::3:0::5:0::6:0::7:0 yes/no?

or

variableTag(::)var1:value_of_var1, ..., variableTag(::)var5:value_of_var5

Few queries:
1. Is the identification code of a variable 1-digit (2, 3, 5, 6, 7)?
2. Is the value of a variable is 1-digit ( 0 to 9)?

Hello!

Yes the transmission frame is

::2:0::3:0::5:0::6:0::7:0

but
it is a part of the transmission because it is very long, it was to show the format, after this
:: 2: 0 :: 3: 0 :: 5: 0 :: 6: 0 :: 7: 0
continue with
15: 0 :: 18: 0 :: 23: 0
up to 32

answering your questions.
1 the identification code of a variable is 1-digit and 2 digit

2 the value of a variable is 0 and 1 in most of the variables but in some the values ​​vary from 0 to 100 aporx

Serial Input Basics - simple reliable ways to receive data.

...R

How to

psalvador17:
Hello!

Yes the transmission frame is

::2:0::3:0::5:0::6:0::7:0

but
it is a part of the transmission because it is very long, it was to show the format, after this
:: 2: 0 :: 3: 0 :: 5: 0 :: 6: 0 :: 7: 0
continue with
15: 0 :: 18: 0 :: 23: 0
up to 32

answering your questions.
1 the identification code of a variable is 1-digit and 2 digit

2 the value of a variable is 0 and 1 in most of the variables but in some the values vary from 0 to 100 aporx

The exact format of the transmission frame still isn't clear.
The general format for each variable/value pair appears to be:

::<1 or 2 digits>:<1, 2, or 3 digits>

Are you only sending the variable/value for some of the 32 variables, or do you send all 32 in every transmission frame?
Is any other information being sent in the transmission frame?
Does the transmission frame terminated in a specific way, such as a newline or linefeed character, or does it just end with the last digit from a variable/value pair?

It is easy enough to detect the double colon as the beginning of a variable/value pair, and then use the single colon as the separator for the variable and value, but if there is no specific terminating character, determining if you have received the complete value gets a bit more difficult. Since the number of digits in value varies, you need some way to tell that you have received the entire number. The beginning colon from the next variable/value pair could be used, but only if you can guarantee that it will be sent within a reasonable amount of time, otherwise you may have to implement a timer to allow time for reception of up to 3 digits before deciding you have the complete number and acting upon it.

Robin2:
Serial Input Basics - simple reliable ways to receive data.

...R

Thanks!

i am reading all the post

david_2018:
How to
The exact format of the transmission frame still isn't clear.
The general format for each variable/value pair appears to be:

::<1 or 2 digits>:<1, 2, or 3 digits>

Are you only sending the variable/value for some of the 32 variables, or do you send all 32 in every transmission frame?
Is any other information being sent in the transmission frame?
Does the transmission frame terminated in a specific way, such as a newline or linefeed character, or does it just end with the last digit from a variable/value pair?

It is easy enough to detect the double colon as the beginning of a variable/value pair, and then use the single colon as the separator for the variable and value, but if there is no specific terminating character, determining if you have received the complete value gets a bit more difficult. Since the number of digits in value varies, you need some way to tell that you have received the entire number. The beginning colon from the next variable/value pair could be used, but only if you can guarantee that it will be sent within a reasonable amount of time, otherwise you may have to implement a timer to allow time for reception of up to 3 digits before deciding you have the complete number and acting upon it.

Hello!

The exact format of the transmission is this

2:0::3:0::5:0::15:0::19:0::20:0::37:0::38:0::40:0::42:0::51:0::58:0::59:0::

starts with the variable number but ends with double colon

the variable 37,38,40,42,51 have the value and decimals:

37:72.5::38:142.841::40:0::42:22.3695::51:2739.8::

the rest of the variables is 0 or 1

I am sending the variable / value for the 13 (I have reduced the list) in each transmission frame because it is receiving in loop

there is no other information sent in the transmission box only the variable value chain.

the transmission frame ends with
double colon ::
51:0::58:0:59:0::

greetings!

psalvador17:
The exact format of the transmission is this

2:0::3:0::5:0::15:0::19:0::20:0::37:0::38:0::40:0::42:0::51:0::58:0::59:0::

starts with the variable number but ends with double colon

If you have the option to change the sending program so as to replace the double colon with a different single character it will make the parsing much easier in the receiving program.

...R

Robin2:
If you have the option to change the sending program so as to replace the double colon with a different single character it will make the parsing much easier in the receiving program.

...R

unfortunately he could not edit the program that sends the data, its a server that receives information from a train simulator

psalvador17:
unfortunately he could not edit the program that sends the data, its a server that receives information from a train simulator

This is not the first time I have come across commercial systems that produce output in an inconvenient format. Makes me wonder what the developers were thinking about - or if they were thinking.

...R

Robin2:
This is not the first time I have come across commercial systems that produce output in an inconvenient format. Makes me wonder what the developers were thinking about - or if they were thinking.

...R

So is it more complicated to read the data?

psalvador17:
So is it more complicated to read the data?

I don't understand your question.

...R

Back of the napkin attempt -

Declare a result string
Point to first char of rcv string
Test char
If "\0" is end of string, exit loop
If not ":" is numeric, copy rcv char to result, increment result pointer and rcv pointer
else test next rcv char+1 (check for double colon)
if is colon move a "^" to result and advance two rcv characters
else is single colon, move ":" to result and advance rcv result pointer
etc.

2:0::3:0::5:0::15:0::19:0::20:0::37:0::38:0::40:0::42:0::51:0::58:0::59:0::

becomes

2:0^3:0^5:0^15:0^19:0^20:0^37:0^38:0^40:0^42:0^51:0^58:0^59:0^

Now process result string with strtok, etc.

dougp:
Now process result string with strtok, etc.

I agree with the objective but I'm not sure that your description is easy to understand.

I wonder if a simpler solution might be to iterate through the char array and if a colon is detected immediately after another colon change it to a 'x' so you get something like

2:0:x3:0:x5:0:x15:0:x19:0:x20:0:x37:0:x38:0:x40:0:x42:0:x51:0:x58:0:x59:0:x

and use strtok() to first parse it on the 'x's and subsequently on the colons

This would have the advantage that it would not change the length of the string

...R

Robin2:
I agree with the objective but I'm not sure that your description is easy to understand.

Well, it was only the back of a napkin! :wink:

If one knows how to do it, don't look at me, a regular expression might be even easier.

There was no indication that there was an end-of-line character, such as a newline, linefeed, carriage return, etc, only that the data ends with a double colon "::", and I forgot to ask if every transmission frame would contain all the variables, so testing for "59:x::" as an end-of-line indicator might not be reliable. I tried a slightly different tactic of considering each variable/value pair to be its own line of data. Without seeing the rest of the code its really difficult to know if this would be acceptable, but its easy enough to implement.

The following code will take the input line:

2:0::3:0::5:0::15:0::19:0::20:0::37:0::38:0::40:0::42:0::51:0::58:0::59:0::

and separate it into individual lines of input data in the format:

2:0:
3:0:
5:0:
15:0:
19:0:
20:0:
37:0:
38:0:
40:0:
42:0:
51:0:
58:0:
59:0:

From there it's easy to parse each line for the ":" and set the appropriate variable to its corresponding value.

const byte numChars = 32;
char receivedChars[numChars]; //array to store received data
char endMarker = ':'; //end of input data indicator <cr>
bool newData = false;

byte var2, var3, var5, var15, var19, var20, var58, var59;
float var37, var38, var40, var42, var51;

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println(F("startup"));
}

void loop() {
  ReceiveData();
  if (newData == true) {
    newData = false;
    Serial.println(receivedChars);
    parseData();
    //only printing when last data has been received
    //otherwise the receive buffer overruns because
    //of delay from printing too much text.
    //    if ((receivedChars[0] == '5') && (receivedChars[1] == '9')) {
    if (atoi(receivedChars) == 59) {
      displayData();
    }
  }
}

void ReceiveData() {
  static byte index = 0; //index into receive buffer
  static bool endPending = false; //flag to indicate potential double colon separator
  char RcvChar;

  while (Serial.available() > 0 && newData == false) {
    RcvChar = Serial.read();
    if ((RcvChar == endMarker) && (endPending == true)) { //if current and previous character was :
      receivedChars[index] = '\0'; // terminate the string
      index = 0; //reset index to beginning of buffer
      newData = true; //let program know new data is available
    } else {
      endPending = (RcvChar == endMarker) ? true : false; //set flag to indicate : has been received
      receivedChars[index] = RcvChar;
      index++;
      if (index >= numChars) { //check for receive buffer overflow
        index--;
      }

    }
  }
}

void displayData() {
  Serial.println();
  Serial.print(F("var2 = "));
  Serial.println(var2);
  Serial.print(F("var3 = "));
  Serial.println(var3);
  Serial.print(F("var5 = "));
  Serial.println(var5);
  Serial.print(F("var15 = "));
  Serial.println(var15);
  Serial.print(F("var19 = "));
  Serial.println(var19);
  Serial.print(F("var20 = "));
  Serial.println(var20);
  Serial.print(F("var37 = "));
  Serial.println(var37, 5);
  Serial.print(F("var38 = "));
  Serial.println(var38, 5);
  Serial.print(F("var40 = "));
  Serial.println(var40, 5);
  Serial.print(F("var42 = "));
  Serial.println(var42, 5);
  Serial.print(F("var51 = "));
  Serial.println(var51, 5);
  Serial.print(F("var58 = "));
  Serial.println(var58);
  Serial.print(F("var59 = "));
  Serial.println(var59);
  Serial.println();
}


void parseData() {
  // split the data into its parts
  char * strtokIndx; // this is used by strtok() as an index
  byte variable;
  char tempChars[numChars];
  strcpy(tempChars, receivedChars);
  strtokIndx = strtok(tempChars, ":");     // get the first part - the string
  if (strtokIndx != NULL) {
    variable = atoi(strtokIndx);
    strtokIndx = strtok(NULL, ":"); // this continues where the previous call left off
    if (strtokIndx != NULL) {
      switch (variable) {
        case 2:
          var2 = atoi(strtokIndx);
          break;
        case 3:
          var3 = atoi(strtokIndx);
          break;
        case 5:
          var5 = atoi(strtokIndx);
          break;
        case 15:
          var15 = atoi(strtokIndx);
          break;
        case 19:
          var19 = atoi(strtokIndx);
          break;
        case 20:
          var20 = atoi(strtokIndx);
          break;
        case 58:
          var58 = atoi(strtokIndx);
          break;
        case 59:
          var59 = atoi(strtokIndx);
          break;
        case 37:
          var37 = atof(strtokIndx);
          break;
        case 38:
          var38 = atof(strtokIndx);
          break;
        case 40:
          var40 = atof(strtokIndx);
          break;
        case 42:
          var42 = atof(strtokIndx);
          break;
        case 51:
          var51 = atof(strtokIndx);
          break;
        default:
          //error
          break;
      }
    }
  }
}