Compare parts of byte array

Hi everyone,

I'm working on a project for my car. It's a little above my experience so I'm learning as I go.
Currently I'm facing the following issue:

The program I use compares incoming packets (from the car's canbus) to packets I defined in code.
This works great.

Here I have an example of a packet which is always the same:

const byte UNLOCK_PRESSED [6] PROGMEM = {
  0x00 , 0x04 , 0xBF , 0x72 , 0x22 , 0xEB
};	// Unlock Pressed

void packet_Handler(byte *packet) // callback function
{
  if (memcmp_P(packet, UNLOCK_PRESSED, 6) == 0){
    // Unlock was pressed. Do something
  }

However now I need the program to compare a specific value in a packet. This value changes as it shows the car's speed and RPM.
The packet looks like this:

0x80 0x05 0xBF 0x18 0x00 0x00 0xCK	0kmh 0 rpm
0x80 0x05 0xBF 0x18 0x01 0x01 0xCK	2kmh 100rpm
0x80 0x05 0xBF 0x18 0x02 0x02 0xCK	4kmh 200rpm
0x80 0x05 0xBF 0x18 0x03 0x03 0xCK	6kmh 300rpm
etc...

CK indicated the Checksum of course. So the problem is the last 3 bytes, speed, RPM and CK will be different as the car drives.

What would be a good approach to extract the speed and RPM?

I think the least thing I need to do is check the first 4 bytes. This way I can make sure that the packet IS the one indicating speed, RPM and CK.
So sender (1st byte), length (2nd byte), receiver (3rd byte), and 0x18 I assume indicates that this is the message that shows speed and RPM. If these 4 match then i could assume that the 5th byte indicates the speed and the sixth byte indicates RPM.

I found this: avr-libc: <avr/pgmspace.h>: Program Space Utilities
But as I said I'm afraid it's a bit too complicated for me to understand at this point.

What would be the easiest way to solve my problem?
Any help is very much appreciated!

Best regards,
Luck Hermsen

Just do another memcmp_P, but with the four header bytes that indicate the speed/rpm packet you're looking for. Then just treat the packet bytes as an array so you can extract the two interesting ones. Multiply by two and 100 respectively and you've got speed & rpm.

Hi wildbill, thanks for your reply.

I tried this:

  const byte SPEED_RPM [4] PROGMEM = {
    0x80 , 0x05 , 0xBF , 0x18
  };

  debugSerial.println(memcmp_P(packet, SPEED_RPM, 4));

  // First 4 bytes of IKE Speed & RPM Broadcast//
  if (memcmp_P(packet, SPEED_RPM, 4) == 3 ) {
    debugSerial.println(F("SPEED AND RPM MESSAGE DETECTED"));
    debugSerial.print(F("SPEED:"));
    debugSerial.println((packet[4] * 2));
    debugSerial.print(F("RPM:"));
    debugSerial.println((packet[5] * 100));
  }

I'm afraid I don't really get it yet...

If you are sure, that for all messages the first 4 Bytes will be some sort of identifier the easiest way would be to treat them as an unsigned integer:

const unsigned int SpeedRPMIdentifier = 0x18bf0580; // reverse order because of little endian

unsigned int packetIdentifier = 0;
memcpy(&packetIdentifier, packet, 4);
if(packetIdentifier == SpeedRPMIdentifier )
{
    // extract data
}

To extract the data, given that the packet length is always six bytes:

unsigned int speed = 2 * packet[4];
unsigned int rpm = 100 * packet[5];

To get the speed, you multiply by two (0x01 = 2kmh, 0x02 = 4kmh, ...) and to get the rpm you multiply by 100 (0x01 = 100rpm, 0x02 = 200rpm, ...).

Note that this is not tested.

This is close:

  if (memcmp_P(packet, SPEED_RPM, 4) == 3 ) {

But why did you compare the result to 3? Zero indicates a match. I'm guessing that your debug gave you three, which means that the packet you've got doesn't match.

Hi LightuC,

thanks for your reply!
This looks good, will test this soon.

So if I understand correctly, the reason to use the memcpy is to convert the packet, which is an array to the unsigned int you declared previously?

Yes, that is correct. You could also try

if( (*(unsigned int*)packet) == SpeedRPMIdentifier)
{
 [...]
}

Which should be a lot faster (no memory copy involved). However, using memcmp_P like wildbill suggested might be the fastest solution.

wildbill:
This is close:

  if (memcmp_P(packet, SPEED_RPM, 4) == 3 ) {

But why did you compare the result to 3? Zero indicates a match. I'm guessing that your debug gave you three, which means that the packet you've got doesn't match.

Debug prints 20 which is in decimal i believe.
If i change the code to == 0 nothing happens either...

Print out the bytes in the packet you're testing. It sounds like you're not getting what you expect

Some strange stuff is going on.

I tried LightuC code and got things working. I can extract the speed and RPM using the SpeedRPMIdentifier = 0x18bf0580

But now comes the weird part...
I wanted to do the same thing with the mileage, which is in this message:
80 0A BF 17 25 23 03 00 4C 72 CC D5

position [4] [5] and [6] are the mileage.
So I did the same thing as with the speed, I took the first 4 bytes and put them in an int.
unsigned int mileageIdentifier = 0x17bf0a80;

It does see the message and executes te code.
Problem is that it will do this for any message starting with 80 0A BF.

It doesn't care whether the fourth byte is 17 or something entirely different.

Am I missing something?