Trouble finding a substring in a char array. Reading 2 UART Streams.

MEGA 2560 R3 clone. I'm a retired longtime programmer and new Arduino and C++ user. Project is to read two different UART streams, save the data in a char array, and once I have a full set of values, parse it to display on a LCD char display. Both data streams contain no delimeters or starting and ending chars - they stream data continuously, repeating data over and over.

The simplest of the two streams contains just two variable values, and the other contains 25 entries. An example of the simpler stream: "0DT=IIA=0DT=IIA=". In this example, the value of "T" is "II" and "A" is "0D". I don't care about pairing up values so I have a matched set, I'm happy to take what I see.

This code doesn't contain any of the parsing or LCD functions, I'm still trying to get the data captured. I had this working with Strings, but wound up with data corruption - so I'm redoing it with char arrays.

I can't seem to be able to figure out to recognize when the char array contains a apecific substring - that would lead me to start or stop gathering data. I've tried three different ways to ID that the result contains "A=", but am having trouble.

I am attaching a screenshot of the serial monitor after a brief run. I tried to cut/paste the data, but it does contain un-printable chars and wouldn't paste. To make the test output easier to read, I output both the raw data as it comes in, and the assembled string - one on top of the other, in 80 byte chunks.

Thanks in advance for your help. Steve.

char TMc[250];
char AA[3] = "=A";

void setup()
  Serial.begin(9600); // speed to talk to the computer
  Serial2.begin(2400); // speed to read the TM

void loop() {
  static int n = 0;
  bool Got1 = false;

  if (Serial2.available() > 0)
    char a =;

    TMc[n]     = a;
    TMc[n + 1] = '\0';

    // Try 1
    if (n > 5
        & TMc[n - 3] == "="
        & TMc[n - 2] == "A"
    { Serial.println("*SS*");
      Got1 = true;
    } //EndIf

    // Try 2
    if (strstr(TMc, AA) > 0)
      Serial.println("*AA*"); //EndIf

    //Try 3
    if (strstr(TMc, "=A") > 0)
      Serial.println("*BB*"); //EndIf
//Chop test data into 80 char chunks to make it more readable on the Monitor.
//Output both the raw stream characters one at a time and the built char array one above the other.
//Raw data is displayed with a leading ":" and char data with a "|"
    if (n > 80 or Got1)
    { Serial.println();
      Serial.print(": ");
      for (int i = 0; i <= n; i++)

      Serial.print( "  Got1= ");
      Serial.print("|  ");
      n = 1;
      TMc[0] = "]";;
      TMc[1] = '\0';
      Got1 = false;
    } // end n>
  } // end Available
} // end loop

if (n > 5 & TMc[n - 3] == "=" & TMc[n - 2] == "A" )

When looking for specific characters, use single quotes as in '=' or 'A'.

The strstr() function may be of interest.

To analyze a incoming stream on the fly is no problem. We will help with the specific 'C' and 'C++' things and the Arduino functions.

First of all, what can you tell about the format of the data ?
Is it always one character before the '=' and always two characters behind the '=' ?
Are the two characters after the '=' normal bytes between 0 and 255 ?
Should the two bytes after the '=' be combined to get a integer ? What kind of integer ?

The returns an integer to be able to return -1 when there was not data.
If you are sure there is data, then you can do: byte inByte =;
That will strip the higher byte from the integer.
A 'char' is a signed 8-bit number from -128 to +127. You probably don't want a number from -128 to +127.
The 'byte' is not 'C++' but something from Arduino. It is of course a unsigned 8-bit variable.

I prefer that you use normal names. For example 'buffer' for a buffer instead of 'TMc' and 'index' instead of 'n'.

The condition of a if-statement uses 'and' or '&&' or 'or' or '||'.
&& - Arduino Reference.

if( Got1 && i == 12 && j == 13 && inByte == buffer[2])

if( Got1 and i == 12 and j == 13 and inByte == buffer[2])

This is a zero-terminated string of two bytes: "="
This is a single byte: '='

I have the impression that you are trying some kind of very flexible way to walk along the data and gather the right information. To be honest, I can not wrap my head around that and I can not put that in code. The format "?=??" has only 4 bytes. To combine that in code with a chunk of 80 bytes is not straightforward.
It can be done with a ringbuffer. Store the incoming data in the ringbuffer per byte and independently check if 4 bytes match the format and then remove them from the buffer. However, this has very little advantages.

An alternative way is to read the incoming data and store it in a buffer. Check if the second byte in the buffer is a '=' and the first byte is a 'A' or 'T', then process the data. After that, store new data at the beginning of the buffer. If the amount of bytes in the buffer is right (4 bytes), but the second byte is not a '=', then shift everything to the left and store new data at the end. If this is done correctly, then the buffer needs only to be 4 bytes in size.

Useful information: The ATmega2560 has only one byte buffer in hardware for the serial ports. The Arduino "Serial" library has a buffer of 64 bytes. As long as the interrupt are able to run, then the one byte hardware buffer is no problem.
To read a chunk of 80 bytes, the loop() should run fast enough to process the incoming data. I think that 64 bytes of 2400 baud takes about 0.27 seconds. That means you are not allowed to use a delay larger than 0.27 seconds, or else the buffer inside the Serial library is full. The best solution is not to use any delay() at all.

Thanks to all for your help!

Blackfin: I changed the "s on single characters to 's, and I'm still not getting a hit.

groundFungus: I'm attempting to use strstr as "Try 2" and "Try 3" in the code, but I'm doing something wrong and am finding no matches.

Koepel: Wow, in-depth response, thanks! The 80 byte logic is only there for test purposes. I am trying to load the "TMc" char array with one full set of data (In this case, it's at least one "A=" + two bytes. I'll expect one "T=" + two char, and one "A=" + two char. This is repeated continously. It is possible that additional data may show up. I'm interested only in the two bytes after the "A=" in this stream. I'm not sure exactly what I'll do with these 2 chars, I may neeed the integer value from one or both. This stream is not documented, I'll figure that out.

The other stream looks like this:
There can be other variable values shown now and then, so this sequence can be dynamic. I'm interested in 4 of these values right now, but that could change. This stream appears to be 100% ASCII values,and I can use these ASCII values without interpretation on the LCD output.

I like your "alternative" method of reading data into a buffer then analyzing it. I've already written the logic to parse the saved string of data, search for the variable I want, and assign a set of variables to these values.

I had a fully functionng sketch using Strings, including writing to the display. I am going back to rewrite it using char(s) - so I'm a bit married to the "build a string. then analyze it" logic.

On the Serial buffer- I don't need to capture 100% of the data, just a full set of values when I'm reading the stream. Since I've got two streams, I'll read the values from one of them, parse and save the values, then work on the other stream. If I clear the buffer with a "while (Serial1.available() > 0) {;}", before starting to capture data, will that start me out clean?

Is the other one 2400 baud as well ? Then you can read and parse them both at the same time.
When the Arduino Mega 2560 has to deal with 115200 baud, then the sketch needs to be optimized to do that. Therefor 2400 baud is very slow.

Clearing the input buffer (the software RX buffer inside the Serial library) is indeed done by the "while (Serial1.available() > 0) {;}". There is no separate "clear_the_rx_buffer()" function.
However, if you can keep up to read the incoming data, then there is no need to throw away data.

The other stream needs some work to capture it. It could have a moving dot. Perhaps these are possible:


The first part is not a fixed number of characters. I see for example "A" and "PW" and "DSE".

The easy part is the comma. Read the input until a comma is found, then store the next data in a buffer until a comma is found. Test the string before the '=' and read the float number with atof().
When you read the ASCII text and put the ASCII text on a display, then you do nothing with the value. What fun is that :smiley_cat:
When you want to know if a value is increasing or is hitting a limit, then you have to put it into a variable with atof().

If you print the two bytes of the first stream as hex data, then you might see if they are integers.

Thanks Koepel! I'm going to be away from this project for a few days, but I'll pick it back up and let you know where it goes.