Hello,
Context
I have an arduino which is hooked up to a few devices (a DC motor board and a sensor board using SPI). The arduino is controlled via usb serial and communicates with a GUI by sending/receiving encoded byte packets. The process works well but I am stuck at unifying the data types received from the other boards
The following (mockup) code lets me get data from the source of my choice (sensor, other chip, etc). The problem is that depending on the source the data will have different types (from uint8_t to uint32_t, arrays & structs composed of uint?_t).
I am trying to find a simple and flexible way to cast these data to uint8_t array , since all of the operations happening after this function will be performed byte by byte.
I have tried using a union in the example below. It works but I do not find it very flexible since each case would have to be added to the union, especially if structs are involved
union DataUnion{
uint32_t b32[4];
uint16_t b16[8];
uint8_t b8[16];
};
void get_data_from_source(uint8_t cmd, uint8_t data_out[], size_t *data_len){
DataUnion tempdat;
switch(cmd){
case 0x00:
{
tempdat.b16[0] = get_16bit_data(); // source 1, returns uint16_t
*data_len = 2;
break;
}
case 0x10:
{
tempdat.b32[0] = get_32bit_data(); // source 2, returns uint32_t
*data_len = 4;
break;
}
case 0x20:
{
uint32_t data3[4];
get_4x32bit_data(data3); // source 3, returns uint32_t[4]
for(int i=0; i < 4; i++){
tempdata.b32[i] = data3[i];
}
*data_len = 16;
break;
}
}
for (k=0; k<*data_len; k++){
data_out[i] = tempdata.b8[i];
}
}
I was wondering if there is a more elegant solution to replace the union, maybe using pointers, however I have not been able to cast any of the results correctly.
Any idea?
You are needing to add a descriptor (Metadata) to assist in decoding the data-type... a single unsigned byte will give you 255 types to assist in picking the correct decoding methodology. This is a multibyte approach.
I do not recommend the Union ...
p.s. a Union is a specialized "struct"
I break down a unit32 into uint8.
if (!PassTwo)
{
rx_frame.FIR.B.FF = CAN_frame_std;
rx_frame.MsgID = 1;
rx_frame.FIR.B.DLC = 8;
rx_frame.data.u8[0] = *item & 0xFF;
rx_frame.data.u8[1] = (*item >> 8) & 0xFF;
rx_frame.data.u8[2] = (*item >> 16) & 0xFF;
rx_frame.data.u8[3] = (*item >> 24) & 0xFF;
PassTwo = true;
} else {
rx_frame.data.u8[4] = *item & 0xFF;;
rx_frame.data.u8[5] = (*item >> 8) & 0xFF;
rx_frame.data.u8[6] = (*item >> 16) & 0xFF;
rx_frame.data.u8[7] = (*item >> 24) & 0xFF;
ESP32Can.CANWriteFrame(&rx_frame); // send items over CAN buss
PassTwo = false;
}
If it was me, I would just use memcpy and sizeof instead; something like this maybe:
#define ARR_SIZE 8
void setup() {
Serial.begin(115200);
uint32_t v1 = 0x11223344;
uint16_t v2 = 0x5566;
uint8_t v3 = 0x77;
uint8_t arr_len, data_arr[ARR_SIZE];
Serial.print("v1 = ");
arr_len = (sizeof(v1) > ARR_SIZE) ? ARR_SIZE : sizeof(v1); //use variable datatype size IF not greater than size of array
memcpy(data_arr, &v1, arr_len);
for (uint8_t i = 0; i < arr_len; ++i) {
Serial.print(data_arr[i], HEX);
}
Serial.print("\nv2 = ");
arr_len = (sizeof(v2) > ARR_SIZE) ? ARR_SIZE : sizeof(v2);
memcpy(data_arr, &v2, arr_len);
for (uint8_t i = 0; i < arr_len; ++i) {
Serial.print(data_arr[i], HEX);
}
Serial.print("\nv3 = ");
arr_len = (sizeof(v3) > ARR_SIZE) ? ARR_SIZE : sizeof(v3);
memcpy(data_arr, &v3, arr_len);
for (uint8_t i = 0; i < arr_len; ++i) {
Serial.print(data_arr[i], HEX);
}
}
void loop() {
// put your main code here, to run repeatedly:
}
v1 = 44332211
v2 = 6655
v3 = 77
hope that helps...
(ps: variable LSByte copied to data_arr[0] which is printed out first, hence why the the bytes appear reversed!
)
I think that's it! I was just thinking of writing a helper function that wrote the content of my variables cast as a uint8_t[ ] to data_out[ ] but I completely forgot about memcopy!
Thanks, I'll give it a try as soon as I can!
If I understood correctly, the uint8_t cmd already serves as a descriptor of sorts since all the different commands sent to the daughter boards return a known data type.
I was thinking of using memcpy as sherzaad suggested. As long as the data is in contiguous memory adresses I should be able to directly copy byte for byte the return values to an array of uint8_t.