Serial.readBytes if first byte is 0x50

Hy,
I would need arduino to read 6 bytes if first byte is 0x50, second is 0x04, third is 0x68, fourth is 0x3B and fifth is 0x06....
If those bytes are right I am interested in last byte.
As soon as one of those bytes are not correct I dont need return at all.

How could I implement this?

Thank you

A state machine.

i wrote some code a while back that read an Automess radiation meter that sends a binary string with a specific start char, STX, followed by a buffer including a checksum.

it doesn't start capturing data until it sees the STX. it then reads the complete msg specified by MSG_SIZE and processes the msg if it has a correct checksum

in your case you can check for the values following the start byte when processing the message and choose to ignore messages that don't match your criteria

Absolutely agree, understanding state machines and transition diagrams is pretty much essential for dealing with inputs, be it button press, incoming characters on Serial, or whatever.

In C the switch/case statement is quite handy for dispatch on the current state and you'll often see it used for this.

I think a proper state machine is an overkill.

Here is an example that reports the byte after a 'abcde' prefix.

uint8_t testIndex = 0;
uint8_t match[5] = { 'a', 'b', 'c', 'd', 'e' };
//uint8_t match[5] = { 0x50, 0x04, 0x68, 0x3B, 0x06 };

void setup() {
  Serial.begin(115200);
}
void loop() {
  if (Serial.available()) {
    uint8_t got = Serial.read();
    if (testIndex == 5) {
      Serial.print(F("extracted '"));
      Serial.write(got);
      Serial.print(F("' 0x"));
      if (got < 16) {
        Serial.write('0');
      }
      Serial.println(got, HEX);
      testIndex = 0;
    } else if (got == match[testIndex]) {
      testIndex++;
    } else {
      testIndex = 0;
    }
  }
}

Or a little nicer formatted to show the algorithm:

uint8_t testIndex = 0;
uint8_t match[5] = { 'a', 'b', 'c', 'd', 'e' }; // could be { 0x50, 0x04, 0x68, 0x3B, 0x06 };

void setup() {
  Serial.begin(115200);
}
void loop() {
  if (Serial.available()) {
    uint8_t got = Serial.read();
    if (testIndex == 5) {
      report(got);
      testIndex = 0;
    } else if (got == match[testIndex]) {
      testIndex++;
    } else {
      testIndex = 0;
    }
  }
}
void report(uint8_t what) {
  Serial.print(F("extracted '"));
  Serial.write(what);
  Serial.print(F("' 0x"));
  if (what< 16) {
    Serial.write('0');
  }
  Serial.println(what, HEX);
}

It can be so simple because all bytes of the pattern to match are different.

Is the string terminated with any character? a CR ?
Does the string occur in a stream of characters or just comes along by itself ?

The state machine is certainly a good way to go, or if the entire message is fairly short, you could accept the whole message, and compare the leading block of known characters… then pick off the ones you are looking for.

Another example, similar to that shown by @Whandall.

/*
 * Sketch:  sketch_oct16d.ino
 * Target:  Mega2560
 *
 */

#define DESIRED_VALUE       0x80    //actionable payload byte

typedef enum
{
    HEADER  = 0,
    PAYLOAD
    
}e_SerialStates;

const uint8_t grHdrPattern[] = { 0x50, 0x04, 0x68, 0x3B, 0x06 };

uint8_t
    hdrSize,
    ch,
    index = 0,
    stateSerial = HEADER;

void setup() 
{
    Serial.begin( 115200 );
    pinMode( LED_BUILTIN, OUTPUT );

    hdrSize = sizeof( grHdrPattern ) / sizeof( grHdrPattern[0] );

}//setup

void loop() 
{        
    if( Serial.available() > 0 )
    {
        while( Serial.available() > 0 )
        {
            ch = Serial.read();
            switch( stateSerial )
            {
                case    HEADER:
                    if( ch == grHdrPattern[index] )
                    {
                        index++;
                        if( index == hdrSize )
                        {
                            index = 0;                        
                            stateSerial = PAYLOAD;                        
                            
                        }//if
                    }//if
                    else
                        index = 0;
                break;

                case    PAYLOAD:
                    //if we only care about the byte after the header
                    //we can process this byte and then go back to the 
                    //HEADER state and wait for another message
                    switch( ch )
                    {
                        case    DESIRED_VALUE:
                            //turn on the LED when the desired byte is seen
                            digitalWrite( LED_BUILTIN, HIGH );
                            
                        break;

                        default:
                            //turn off the LED for anything else
                            digitalWrite( LED_BUILTIN, LOW );
                            
                        break;
                        
                    }//switch

                    stateSerial = HEADER;
                    
                break;
                
            }//switch
            
        }//while
        
    }//if

}//loop

I very much dislike this programming pattern.
The while just adds code and a level of indentation that serves no purpose.

1 Like

No one cares Whandall.

FWIW, I don't care for the the programming style that puts braces at the end of a line, saving a line of source but sacrificing readability. But I chose not to opine out your style because no one else would care.

In this case, the if is basically redundant and could be left out, the while is needed if there is more than a single character in the receiver buffer.

Nope, the while is superfluous, the if is the only statement in loop.

So loop + if = while. There is no need to repeat that.

I had not read the entire code example, normally this would be in a function for processing the serial receive, and there would be actions taken when the pattern the OP originally asked about was detected.

Serial is soooooo slow, there is no need for any while(Serial.available()) {

unless the loop() function is running fast enough to catch up with it on the next go round. Which is usually the case.

Hy, thank you all for anwsers. I came up with simple solution while I was on the go. Just came home and tryed it and it works perfectly.

 if (ibusPort.available() > 0) {
    if (ibusPort.read() == 0x50) {
      do {
        delay(1);
      } while (ibusPort.available() == 0);
      if (ibusPort.read() == 0x04) {
        do {
          delay(1);
        } while (ibusPort.available() == 0);
        if (ibusPort.read() == 0x68) {
          do {
            delay(1);
          } while (ibusPort.available() == 0);
          if (ibusPort.read() == 0x3B) {
            do {
              delay(1);
            } while (ibusPort.available() == 0);
            if (ibusPort.read() == 0x01) {
              do {
                delay(1);
              } while (ibusPort.available() == 0);
              if (ibusPort.read() == 0x06) {
                digitalWrite(13, HIGH);
              }
            }
          }
        }
      }
    }
  }

Im aware that use of delay while serial isn`t available can slow down my loop, but messages get send fast enough.

But, it seems to me, the delays aren't necessary...

Delays are useless, just slows down how often the condition of the while is checked. Worse problem is what happens if the communications stops and no characters are received.

From the point of view of the rest of the program that might need to do something else. :slight_smile:

It didnt work without delays, and my program was glitchy with them... This is what I came up with:

 if (ibusCommandCaptured == 1) {
    ibus1 = 0;
    ibus2 = 0;
    ibus3 = 0;
    ibusA = 0;
    ibusB = 0;
    ibusC = 0;
    ibusCommandCaptured = 0;

  }
  if (ibusPort.available() > 0 && ibus1 == 0) {
    ibus1 = ibusPort.read();
    if (ibus1 != 0x50) {
      ibus1 = 0;
    }
  }

  if (ibusPort.available() > 0 && ibus1 == 0x50 && ibus2 == 0) {
    ibus2 = ibusPort.read();
    if (ibus2 != 0x04) {
      ibus1 = 0;
      ibus2 = 0;
    }
  }

  if (ibusPort.available() > 0 && ibus2 == 0x04 && ibus3 == 0) {
    ibus3 = ibusPort.read();
    if (ibus3 != 0x68) {
      ibus1 = 0;
      ibus2 = 0;
      ibus3 = 0;
    }
  }

  if (ibusPort.available() > 0 && ibus3 == 0x68 && ibusA == 0) {
    ibusA = ibusPort.read();
  }

  if (ibusPort.available() > 0 && ibusA != 0 && ibusB == 0) {
    ibusB = ibusPort.read();
  }

  if (ibusPort.available() > 0 && ibusB != 0 && ibusC == 0) {
    ibusC = ibusPort.read();
  }

  if (ibusC != 0)
  {
    ibusCommandCaptured = 1;
  }



  //NEXT PRESSED
  if (ibusA == 0x3B && ibusB == 0X01 && ibusC == 0X06) {
   //do stuff
  }
  //PREV PRESSED
  if (ibusA == 0x3B && ibusB == 0x08 && ibusC == 0x0F) {
    //do stuff
  }
  //VOL UP PRESSED
  if (ibusA == 0x32 && ibusB == 0x11 && ibusC == 0x1F) {
    //do stuff
  }
  //VOL DOWN PRESSED
  if (ibusA == 0x32 && ibusB == 0x10 && ibusC == 0x1E) {
    //do stuff
  }

What way it can go thru the loop without waiting and capture next byte in next loop.

consider following which simulates reading a sequence of bytes containing 2 messages

output

 0x50 0x04 0x68 0x3b 0x06 0x12
 0x50 0x04 0x68 0x3b 0x06 0x98

typedef unsigned char byte;

int bufIdx;
byte buf [] = {
    0x34, 0xde, 0xad, 0xbe, 0xef,
    0x50, 0x04, 0x68, 0x3b, 0x06, 0x12,
    0x12, 
    0x50, 0x04, 0x68, 0x3b, 0x06, 0x98,
    0x34, 0xde, 0xad, 0xbe, 0xef,
};
const int BufSize = sizeof(buf);

struct MySerial {
    int  available (void)  { return BufSize - bufIdx; }
    byte read      (void)  { return buf [bufIdx++]; }
};

MySerial ibusPort;

byte msg [20];
int  idx;

char s [20];

// -----------------------------------------------------------------------------
int
monitor (void)
{
    int res = 0;

    if (! ibusPort.available ())
        return 0;

    char c = ibusPort.read ();  
    if (0x50 == c)
        idx = 0;

    msg [idx++] = c;

    if (2 < idx && (msg [1] + 2) == idx)  {
        res = idx;
        idx = 0;
    }

    return res;
}

// -----------------------------------------------------------------------------
void
loop ()
{
    int n = monitor ();

    if (n)  {
        for (int i = 0; i < n; i++)  {
            sprintf (s, " 0x%02x", msg [i]);
            Serial.print (s);
        }
        Serial.println ();
    }
}

// -----------------------------------------------------------------------------
void
setup ()
{
    Serial.begin (9600);
}