Converting array of floats and array of ints into one concatenated byte array

Hey all

I'm running into a problem that's a bit deeper than I know how to go. I'm working with the Nano 33 BLE, and passing IMU data over bluetooth. Bluetooth requires that data be passed as a bytes, and so far I have code that passes an array of floats as a byte array, as shown below:

float data[3];
  data[0] = heading;
  data[1] = pitch;
  data[2] = roll;

  int gyro[3];
  gyro[3] = (int) gx*1000;
  gyro[4] = (int) gy*1000;
  gyro[5] = (int) gz*1000;

  imuCharacteristic.setValue((byte *) &data, 12);

The code currently passes the floats. The ints are where I'm stuck. The rub in all of this is that bluetooth will only let me pass 20 bytes at a time, and to not worry about latency / packet loss I'd like to pass all 18 bytes (3 floats and 3 ints) at once with setValue. Also, gx, gy, and gz are floats. I'm converting them to ints to keep the whole things under 20 bytes

What I don't know how to do is combine the float array and int array into one array / byte array and pass over bluetooth. I have code on the other end in Python to handle conversion back to floats / ints. I'm reading up on pointers more, but any guidance in the meantime would be welcome.

Any thoughts are very much appreciated.

Put them all in a struct. Pass a pointer to the struct cast as a uint8_t *.

something like this is typical

struct myData {
  float heading;
  float pitch;
  float roll;
  int gx;
  int gy;
  int gz;
};

struct myData dataPacket;

dataPacket.heading = heading;
dataPacket.pitch = pitch;
dataPacket.roll = roll;
dataPacket.gx = (int) gx * 1000;
dataPacket.gy = (int) gy * 1000;
dataPacket.gz = (int) gz * 1000;

imuCharacteristic.setValue((byte *) &dataPacket, sizeof(dataPacket));

Thank you very much!

Quick post on my lunch break - I got some time to try out @blh64 code and it works well, except the struct keeps interpreting the ints as 4-byte instead of two. Why is this? The sizeof(dataPacket) is 24 bytes, but I would think it should be 18 (3 4-byte floats and 3 2-byte ints). sizeof dataPacket.gx is 4 however. Any ideas?

What processor does your board use?

What is the size of an int on that processor?

Why don't you explicitly specify the integer size you want?

Also, even if you specify the integer size, the struct on a 32-bit processor may still have a size that's a multiple of 4 bytes.

Are you sure an int is 2 bytes on that processor? You can tell the compiler that you want things packed as tight as possible, even if it means slower access to the elements of the struct. Probably also a good idea from @gfvalvo to explicitly make the 16 bit ints

struct __attribute__ ((__packed__)) myData {
  float heading;
  float pitch;
  float roll;
  int16_t gx;
  int16_t gy;
  int16_t gz;
}

You will have to experiment to check the sizes

The compiler is free to add padding bytes between struct members. You can use non-standard compiler extensions such as __attribute__((packed))

Pieter

theamazingdrew:
except the struct keeps interpreting the ints as 4-byte instead of two. Why is this?

Because the Nano 33 BLE has a 32-bit processor/ALU. If you do not specify the int length, it will default to the natural processor word length.