Getting a phrase from a string with diff length

Good day!

I am looking for a phrase in a string which I don't know the position.
I just know that it has a "fixed" set of command.

It's coming from a serial gateway nrf from MySensors.
I'm using arduino mega for multiple serial.

This is the code:

char nrfData[200];
int a = 0;


void setup() {
  Serial.begin(9600);
  Serial2.begin(115200);
  
  Serial.println("NRF24L01 RX/TX");
}

void loop() {
  receive_nrf();
}

void receive_nrf() {
  while (Serial2.available()) {
    delay(3);  //delay to allow buffer to fill 
    if (Serial2.available() > 0) {
      char inChar = Serial2.read();
      //Serial.print(inChar);
      nrfData[a] = inChar;
      a++;
    }
  }
  
  String incomingString = String(nrfData);

  if (incomingString.length() > 0) {
    Serial.print("Data: ");
    Serial.println(incomingString);
    
    if (incomingString.startsWith("0;1;0;0;", 2)) {
      char* temp = strtok(nrfData, "3;0;1;0;0;");
      //temp = atof(data);
      Serial.print("Temp: ");
      Serial.println(temp);        
    }

    if (incomingString.substring(0,50) == "0;1;0;0;") {
      Serial.println("Found it!");
    }  
    
    clearSerial(nrfData);
    a = 0;
  }  
}

void clearSerial(char *data) {
  for( int i = 0; i < sizeof(data);  ++i )
    data[i] = (char)0;   
}

This is the output:

NRF24L01 RX/TX
Data: 3;255;0;0;17;1.4.1
3;255;3;0;6;0

Data: 3;0;0;0;6;1.4.1
.1
3;255;3;0;6;0

Data: 3;0;1;0;0;28.8

.1
3;255;3;0;6;0

Temp: 28.8

.
Data: 3;0;1;0;0;28.9

.
Temp: 28.9

.
Data: 3;0;1;0;0;28.8

.
Temp: 28.8

.
Data: 3;0;1;0;0;28.7

.
Temp: 28.7

.
Data: 3;0;1;0;0;28.6

.
Temp: 28.6

.

EDIT1: Added serial monitor output

I don't know where "0;1;0;0;" will show. Sometimes it's in the beginning and sometimes at the middle or end. I can't use string.indexOf(), string.substring() and string.startsWith()

In "3;0;1;0;0;28.8" I need to get the "3" which is the id of the sensor and "28.8" which is the temperature in Celsius.

Can you suggest a solution?

What is the expected output (like what is the format), are you looking for the first and last numbers or are you specifically looking for something containing "0;1;0;0;"?

      char* temp = strtok(nrfData, "3;0;1;0;0;");

You don't know what strtok() does, do you? It looks for ANY delimiter in the string supplied, NOT the whole string as a delimiter.

Once you've fucked around wrapping the string in a String, it makes no sense switching back and forth, trying to use string and String methods to parse the same data. Use ONE mechanism.

I suggest you google the function strstr( ), which will find an occurence of a particular "sub string" in a char array.

You might be able to use the below simple code to detect if there is some type of end of data marker included in the byte String captured. Received data that is on more than one line indicates that a carriage return and line feed is being sent in the byte stream.

//zoomkat 6-29-14 Simple serial echo test
//type or paste text in serial monitor and send

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("Simple serial echo test"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the String readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

  if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured String 
    readString="";
  } 
}

Good day!
I have solved my problem. Is there another way of doing this? one with shorter code?

Here is my code:

char nrfData[200];
int a = 0;
char pureData[200];
int e = 0;

void setup() {
  Serial.begin(9600);
  Serial2.begin(115200);
  
  Serial.println("NRF24L01 RX/TX");
}

void loop() {
  receive_nrf();
}

void receive_nrf() {
  while (Serial2.available()) {
    delay(3);  //delay to allow buffer to fill 
    if (Serial2.available() > 0) {
      char inChar = Serial2.read();
      //Serial.print(inChar);
      nrfData[a] = inChar;
      
      if (nrfData[a-2] == '0' && nrfData[a] == '1') {
        pureData[e] = nrfData[a-4];
        e++;
        pureData[e] = ';';
        e++;
        pureData[e] = nrfData[a-2];
        e++;
        pureData[e] = ';';
        e++;
        pureData[e] = nrfData[a];
        e++;
//        Serial.print("Message1: ");
//        Serial.println(pureData); 
      }
      if (nrfData[a-4] == '0' && nrfData[a-2] == '1' && nrfData[a] == '0') {
        pureData[e] = ';';
        e++;
        pureData[e] = nrfData[a];
        e++;
//        Serial.print("Message2: ");
//        Serial.println(pureData); 
      }
      if (nrfData[a-6] == '0' && nrfData[a-4] == '1' && nrfData[a-2] == '0' && nrfData[a] == '0') {
        pureData[e] = ';';
        e++;
        pureData[e] = nrfData[a];
        e++;
//        Serial.print("Message3: ");
//        Serial.println(pureData); 
      }
      if (nrfData[a-8] == '0' && nrfData[a-6] == '1' && nrfData[a-4] == '0' && nrfData[a-2] == '0') {      
        pureData[e] = ';';
        e++;
        pureData[e] = nrfData[a];
        e++;
//        Serial.print("Message4: ");
//        Serial.println(pureData);
      }      
      if (nrfData[a-9] == '0' && nrfData[a-7] == '1' && nrfData[a-5] == '0' && nrfData[a-3] == '0') {      
        pureData[e] = nrfData[a];
        e++;
//        Serial.print("Message5: ");
//        Serial.println(pureData);
      } 
      if (nrfData[a-11] == '0' && nrfData[a-9] == '1' && nrfData[a-7] == '0' && nrfData[a-5] == '0') {      
        pureData[e] = '.';
        e++;
        pureData[e] = nrfData[a];
        e++;
//        Serial.print("Message6: ");
//        Serial.println(pureData);
      } 
      
      a++;
    }
  }
  
  String incomingString = String(nrfData);

  if (incomingString.length() > 0) {
//    Serial.print("Data: ");
//    Serial.println(incomingString);
//    Serial.print("Message All: ");
//    Serial.println(pureData);
    
    char* id = strtok(pureData, ";");
    char* temp = strtok(NULL, "0;1;0;0;");
    int sensor_id = atoi(id);
    float sensor_temp = atof(temp);

    if (id > 0 && temp > 0) {
      Serial.print("ID: ");
      Serial.println(sensor_id);
      Serial.print("Temp: ");
      Serial.println(sensor_temp);    
    }
    
    clearSerial(nrfData);
    a = 0;
    clearSerial(pureData);
    e = 0;
  }  
}

void clearSerial(char *data) {
  for( int i = 0; i < sizeof(data);  ++i )
    data[i] = (char)0;   
}

This is the output:

NRF24L01 RX/TX
ID: 3
Temp: 32.90

EDIT: Added
This is the output if I uncommented data and message all:

NRF24L01 RX/TX
Data: 3;255;0;0;17;1.4.1
3;255;3;0;6;0

Message All: 0;0;1
Data: 3;0;0;0;6;1.4.1
.1
3;255;3;0;6;0

Message All: 
Data: 3;0;1;0;0;33.0

.1
3;255;3;0;6;0

Message All: 3;0;1;0;0;33.0
ID: 3
Temp: 33.00
if (nrfData[a-2] == '0'

What do you expect this to do, the first time you get a character ?

Is there another way of doing this? one with shorter code?

Any person who had the slightest clue what they were doing, would use about 1/3 of that code.

Any person who had the slightest clue what they were doing, would use about 1/3 of that code.

Instead of that asswipe comment, perhaps you can post the code of which you speak. :sunglasses:

michinyon:

if (nrfData[a-2] == '0'

What do you expect this to do, the first time you get a character ?

because I know 0;1;0;0; will appear in the middle of my desired values, I search for 0 and 1--not zero only because it often appears.

0 -> a-2
; -> a-1
1 -> a

I expect it to search for "0;1;0;0;"

arduinoTime:
because I know 0;1;0;0; will appear in the middle of my desired values, I search for 0 and 1--not zero only because it often appears.

0 -> a-2
; -> a-1
1 -> a

I expect it to search for "0;1;0;0;"

That is not the issue. I dont know what happens after, however, when that function is called the first time, a is 0 and "a - 2" is -2, you are trying to access nrfData[-2], which is an error...

You also have an "a - 4" in there

Great starting point.. or back in the day...
"GIGO"...

Doc

If the posters above who are using insulting remarks would desist, that would be much appreciated.

I just want to remind you that although some of us may have memorized most of the C standard library, the Arduino is aimed at beginners, and it would be courteous to just post a link or hint about the appropriate way of achieving the end result, without resorting to name-calling or expletives.

Ps991:
That is not the issue. I dont know what happens after, however, when that function is called the first time, a is 0 and "a - 2" is -2, you are trying to access nrfData[-2], which is an error...

You also have an "a - 4" in there

Oh, ok. I should do it like this?

char nrfData[200];
int a = 0;
char pureData[200];
int e = 0;

void setup() {
  Serial.begin(9600);
  Serial2.begin(115200);
  
  Serial.println("NRF24L01 RX/TX");
}

void loop() {
  receive_nrf();
}

void receive_nrf() {
  while (Serial2.available()) {
    delay(3);  //delay to allow buffer to fill 
    if (Serial2.available() > 0) {
      char inChar = Serial2.read();
      //Serial.print(inChar);
      nrfData[a] = inChar;
      
      if (a > 12) {       
        if (nrfData[a-11] == '0' && nrfData[a-9] == '1' && nrfData[a-7] == '0' && nrfData[a-5] == '0') {      
          for(int i = 13; i >= 0; i--) {
            pureData[e] = nrfData[a-i];
            e++;
          }
        } 
      }
      
      a++;
    }
  }
  
  String incomingString = String(nrfData);

  if (incomingString.length() > 0) {
    Serial.println("-----");
    Serial.print("nrfData: ");
    Serial.println(incomingString);
    Serial.print("pureData: ");
    Serial.println(pureData);
    
    char* id = strtok(pureData, ";");
    char* temp = strtok(NULL, "0;1;0;0;");
    int sensor_id = atoi(id);
    float sensor_temp = atof(temp);

    if (id > 0 && temp > 0) {
      Serial.print("ID: ");
      Serial.println(sensor_id);
      Serial.print("Temp: ");
      Serial.println(sensor_temp);    
    }
    
    clearSerial(nrfData);
    a = 0;
    clearSerial(pureData);
    e = 0;
  }  
}

void clearSerial(char *data) {
  for( int i = 0; i < sizeof(data);  ++i )
    data[i] = (char)0;   
}

If ever the "3;0;1;0;0;33.0" is in the beginning, I will not get any error or input in pureData, yes?

EDIT: Added
Output:

NRF24L01 RX/TX
-----
nrfData: 3;255;0;0;17;1.4.1
3;255;3;0;6;0

pureData: 
-----
nrfData: 3;0;0;0;6;1.4.1
.1
3;255;3;0;6;0

pureData: 
-----
nrfData: 3;0;1;0;0;32.8

.1
3;255;3;0;6;0

pureData: 3;0;1;0;0;32.8
ID: 3
Temp: 32.80

The only issue I see here is this part

if (nrfData[a-11] == '0' && nrfData[a-9] == '1' && nrfData[a-7] == '0' && nrfData[a-5] == '0')

If you are looking for an exact string, then you should compare for an exact string. For example, "0a1b0c0defgh" also satisfies that expression but it obviously is not what you are looking for. It will probably work most of the time, I just think you can improve your code to prevent all possible errors.

Ps991:
The only issue I see here is this part

if (nrfData[a-11] == '0' && nrfData[a-9] == '1' && nrfData[a-7] == '0' && nrfData[a-5] == '0')

If you are looking for an exact string, then you should compare for an exact string. For example, "0a1b0c0defgh" also satisfies that expression but it obviously is not what you are looking for. It will probably work most of the time, I just think you can improve your code to prevent all possible errors.

Changed it to this:

if (nrfData[a-11] == '0' && nrfData[a-10] == ';' && nrfData[a-9] == '1' && nrfData[a-8] == ';' && nrfData[a-7] == '0' && nrfData[a-6] == ';' && nrfData[a-5] == '0' && nrfData[a-4] == ';') {

I hope the temperature is always right :slight_smile: