0

I'm getting a bit tripped up on const char pointers lately.

I'm getting a message from a server that comes through as either a c style string, a standard library string, or a WString:

return types

underlying types

I'm sending down a buffer of 32bit values from my server that aren't ascii or utf text, they're just bit values I want to parse and read on the esp32 side:

example data from the server

I thought "oh, I'll just mask the bit values 32 bits at a time and right shift the data to get the message (in reverse order, but still I can work with that). The problem that I'm running into is that I can shift numbers but not strings or byte arrays.

I wrote out a function to allow me to grab a piece of the string 32 bits at a time and convert that into a number while using an offset:

uint_fast32_t get32BitInt(const char *data, int offset = 0)
{

  uint32_t payload = 0;
  for (uint8_t i = 0; i < 8; i++)
  {
    payload <<= 0;
    payload += data[i + offset];
  }
  return payload;
}

But when I try to grab the first couple of 32 bit chunks the data isn't what I expected:

void handleGameFrame(const char *data, uint32_t length)
{

  uint8_t phaseAndColission = get32BitInt(data, 32);
  uint8_t player = getByte(data, 32 * 2);

  Serial.print("data: ");
  Serial.println(data);
  Serial.print("phaseAndColission: ");
  Serial.println(phaseAndColission, DEC);
  Serial.print("player: ");
  Serial.println(player, DEC);

}

yields:

enter image description here

I know the Serial.println(data); isn't going to output anything b/c it's a c-string of non-printable values, but the other chunk grabbing isn't giving me the same output from my server. It's hard to verify everything without being able to see all of the bits in the overall data pointer and I think I tied myself in (another) knot.

Is there a good way to parse 32 bit values out of a const c-string?

Chris Schmitz
  • 357
  • 4
  • 13
  • "they're just bit values". You mean, they're just `uint32_t` that are being pointed at with a `const char *` ? – timemage Feb 22 '21 at 15:47
  • Oh, I just mean data (the `const char *`) holds bits in it that can't be `Serial.println`-ed because because even in 8 bit form they're not ascii/utf valid characters so nothing goes to the monitor. – Chris Schmitz Feb 22 '21 at 16:15
  • but yeah, data is a c-string of bytes and I know that I want to interpret it as 32 bit integers, I just can't figure out how to do it. – Chris Schmitz Feb 22 '21 at 16:16
  • Well, "c-string" basically means zero or more non-'\0' followed by '\0'. If any of your numbers happen to have a zero byte in them, that will terminate the "string" before the end of your actual data. E.g. 0xAA00BB. It's really just not a string at all. In terms of how you get the data out of it, if it's properly aligned for uint32_t, you can just `const uint32_t *ui32p = reinterpret_cast(mycharptr);` If it's not aligned, you would do something like `memcpy` it into an array or individual elements into a single `uint32_t` variable. There's nothing really "Arduino" here. – timemage Feb 22 '21 at 16:23
  • might have to hex encode the values to transmit them. – dandavis Feb 22 '21 at 17:03
  • it looks like a X->Y problem. "I'm getting a message from a server that comes through as either a c style string, a standard library string, or a WString" why? – Juraj Feb 22 '21 at 17:27
  • @Juraj those are the message formats that the library I'm using gives me. There's not an option for just a buffer of bytes. I would think that the c-string is the equivalent of the buffer, but there's the null terminator issue. – Chris Schmitz Feb 22 '21 at 17:31

1 Answers1

1

You wrote:

I wrote out a function to allow me to grab a piece of the string 32 bits at a time and convert that into a number while using an offset

This function is almost correct. Try this:

uint_fast32_t get32BitInt(const char *data, int offset = 0)
{

  uint32_t payload = 0;
  for (uint8_t i = 0; i < 4; i++)
  {
    payload <<= 8;
    payload |= data[i + offset];
  }
  return payload;
}

Compared to your version, the differences are:

  • It reads 4 bytes instead of 8, as 32 bits are four bytes.

  • For each byte being read, it shifts the payload by 8 bits (i.e. one byte) instead of zero. Shifting by zero has no effect.

  • It uses |= instead of +=: just a micro-optimization for the sake of 8-bit MCUs. It shouldn't make much if a difference on a 32-bit micro.

Edgar Bonet
  • 39,449
  • 4
  • 36
  • 72
  • Oh my god. I can't believe I missed that bit shift by zero :facepalm: I know the for loops conditional check is also wrong, but I can't believe I missed the shift error. Thanks for pointing those out and also the bitwise or optimization. I appreciate you taking the time to correct the function :bows: – Chris Schmitz Feb 23 '21 at 02:57