Can this working code be shortened (processing byte array)

Hi,

Is there perhaps a cleaner and easier way to achieve what this code effectively does please? Code isn't pretty, but it works, I would just like to make it shorter perhaps if possible.

The serial print lines are purely for debugging. I presume I cannot use mathematic formulae in a print command as the output on the last two prints results in 0 as opposed to the correct math output.

Many thanks for any help offered.

  int32_t uas_long_combined = 0;
  uint8_t uas_long_byte3 = beaconPacket[83];
  uint8_t uas_long_byte2 = beaconPacket[82];
  uint8_t uas_long_byte1 = beaconPacket[81];
  uint8_t uas_long_byte0 = beaconPacket[80];

  int32_t uas_lat_combined = 0;
  uint8_t uas_lat_byte3 = beaconPacket[87];
  uint8_t uas_lat_byte2 = beaconPacket[86];
  uint8_t uas_lat_byte1 = beaconPacket[85];
  uint8_t uas_lat_byte0 = beaconPacket[84];
  
  uas_long_combined = uas_long_byte3;
  uas_long_combined = (uas_long_combined << 8) | uas_long_byte2;
  uas_long_combined = (uas_long_combined << 8) | uas_long_byte1;
  uas_long_combined = (uas_long_combined << 8) | uas_long_byte0;

  uas_lat_combined = uas_lat_byte3;
  uas_lat_combined = (uas_lat_combined << 8) | uas_lat_byte2;
  uas_lat_combined = (uas_lat_combined << 8) | uas_lat_byte1;
  uas_lat_combined = (uas_lat_combined << 8) | uas_lat_byte0;

  Serial.println(uas_long_combined, HEX);
  Serial.println(uas_lat_combined, HEX);

  Serial.println(uas_long_combined, DEC);
  Serial.println(uas_lat_combined, DEC);
  
  Serial.println(((uas_long_combined, DEC)* 4068) / 710000000);
  Serial.println(((uas_lat_combined, DEC)* 4068) / 710000000);```

seems your data is ordered in little endian format

Just use memcpy()

int32_t uas_long_combined, uas_lat_combined;
memcpy(&uas_long_combined, &(beaconPacket[80]), 4);
memcpy(&uas_lat_combined,  &(beaconPacket[84]), 4);

What's the DEC doing there?

Besides, I'm always leery of shift operations on signed integers types.

As alluded to by @ TheMemberFormerlyKnownAsAWOL, getting rid of the Comma Operator will go a long way towards fixing that.

Thanks all, those comments are really helpful :+1:

This is what I have working well...

  int32_t uas_long_combined, uas_lat_combined;
  memcpy(&uas_long_combined, &(beaconPacket[80]), 4);
  memcpy(&uas_lat_combined,  &(beaconPacket[84]), 4);

  char            uas_long[16], uas_lat[16];

  double calc_uas_lat = (((uas_lat_combined * 180) / PI) / 10000000);
  double calc_uas_long = (((uas_long_combined * 180) / PI) / 10000000);
  
  dtostrf(calc_uas_lat,10,7,uas_lat);
  dtostrf(calc_uas_long,10,7,uas_long);

  tft.drawString((char *) uas_lat, 100, 95, 2);
  tft.drawString((char *) uas_long, 100, 110, 2);

As part of the data array (beaconPacket), I have 20 bytes which I would like to form into a string. The bytes are in HEX, however each byte represents an ASCII character.

For example.....

uint8_t beaconPacket[21] = {0x06, 0x31, 0x39, 0x35, 0x37, 0x34, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

The first byte (00) identifies the length of the identifier (0x06). How would I convert the above so it reads 195741 from bytes 01 - 06 please?

I think I have made a little progress with byte swapping etc, however at the moment it does produce the hex values in the correct order (31393537343100), but I would like to ignore the trailing 0's and turn that value into ASCII (195741).

  int64_t uuid_combined;
  memcpy(&uuid_combined, &(beaconPacket[126]), 20);
  uuid_combined = __builtin_bswap64(uuid_combined);

Many thanks all :slight_smile:

There's lots of ways. Here are a few. Take your pick.

void setup() {
  Serial.begin(115200);
  delay(1000);

  uint8_t beaconPacket[] = {0x06, 0x31, 0x39, 0x35, 0x37, 0x34, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  char beaconString[10];
  uint32_t beaconInt;

  Serial.println((char *)(beaconPacket + 1));
  
  strcpy(beaconString, (char *)(beaconPacket + 1));
  Serial.println(beaconString);

  beaconInt = strtoul((char *)(beaconPacket + 1), nullptr, 10);
  Serial.println(beaconInt);
}

void loop() {
}

Hi @gfvalvo and thank you for your quick reply.

I have tried the code on its own and it works great, however it doesn't produce the same results inside my main code. My byte array is actually 145 bytes and its bytes 126 - 145 which I would like to capture and decode to ASCII (whilst ignoring any trailing 0x00).

I went for this option and replacing + 1 with +125, serial prints '0'. Not really understanding the segment you have provided, what does the nullptr command do and what is the purpose of the last '10' please?

  beaconInt = strtoul((char *)(beaconPacket + 125), nullptr, 10);
  Serial.println(beaconInt);

Thank you for your kind help.

Steve

you can use memcpy() again and a variable length array (which is a C++ extension that our compiler supports)

  char textString[beaconPacket[0]+1];
  memcpy(textString, &(beaconPacket[1]), beaconPacket[0]);
  textString[beaconPacket[0]] = '\0';

or just have a large enough buffer

  const byte maxLength = 10;
  char textString[maxSize+1]; // +1 for trailing null char
  if (beaconPacket[0] <= maxLength) {
    memcpy(textString, &(beaconPacket[1]), beaconPacket[0]);
    textString[beaconPacket[0]] = '\0';
  } else {
    // handle case where buffer is too small
  }

then you have a cString you can play with in textString

I proposed strcpy() since it detects the null terminator in the original string and copies it to the destination. As noted, the destination array needs to be large enough. To be extra-safe, use strncpy() and explicitly set the array's last element to '\0'.

@ Tissy was unclear as to what is actually required. If all you want to do is print the string, then there's no need to copy it , use the first method in Reply #11.

Makes sense.

I was unsure if the payload would always include this trailing null. hence the memcpy() and hardwired null termination

Yup. It was a poorly-specified requirement to begin with. Hence, many different ways to do it ... not all of which will be valid once the complete requirement is defined.