I am working on a project involving communications. I would like to be able to take a struct and typecast it into bytes in preparation for transmission. Unfortunately, endianness is not working out for me.
The standard that I'm working with has the following definition:
uint8_t address;
uint8_t function;
uint8_t startAddressHi;
uint8_t startAddressLo;
uint8_t numberOfRegistersHi;
uint8_t numberOfRegistersLo;
It would be nice to be able to type cast to uint8_t
and simply transmit the entire struct in one go, but the problem is that the Hi
bytes of the startAddress
and numberOfRegisters
is at a lower index. I am hoping that there is some little-known method of changing the byte order of the definition:
typedef union{
struct rturxfields{
/* header */
uint8_t address;
uint8_t function;
/* data */
uint16_t startAddress; // <= needs some special sauce
uint16_t numberOfRegisters;
}RtuRxFields;
struct rturxfieldbytes{
/* header */
uint8_t address;
uint8_t function;
/* data */
uint8_t startAddressHi;
uint8_t startAddressLo;
uint8_t numberOfRegistersHi;
uint8_t numberOfRegistersLo;
}RtuRxFieldBytes;
uint8_t array[RX_FRAME_LENGTH];
}RtuRxFrame;
Again, as defined, my union, the endianness is off.
I won't have access to htons()
and similar from the networking library. After doing more reading, I think I will simply get rid of the RtuRxFields
struct and create utility functions getStartAddress(RtuRxFrame* frame)
to retrieve the address cleanly.
One thing you can do is to use htons
and ntohs
to convert the 16 bit values between host byte order (machine dependent) and network byte order (big endian). When writing the 16 bit values, pass them through htons
to put the bytes in the right order.
myunion.RtuRxFields.numberOfRegisters = htons(5);
If you don't have access to these functions, you can use bit shifting to get the high and low bytes and write them individually in the relevant fields:
uint16_t registers = 5;
...
myunion.RtuRxFieldBytes.numberOfRegistersHi = (registers >> 8) & 0xff;
myunion.RtuRxFieldBytes.numberOfRegistersLo = registers & 0xff;
Sending a struct over a network can be problematic due to structure padding. Two different compilers on two different machines could make the same struct have different sizes on each. See this guide for more details.