-
Backwards uint16_t?
Hello
I have a function that takes a strut and turns it into a uint8_t array. This code is running on an embedded device and works well. I have recently copied this code to a linux development environment to try to get it to work there as well.
Everything works as it should, however the 16bit variables in my struct are produced backwards:
Code:
typedef struct {
uint8_t deviceType;
uint8_t RSSI;
uint16_t batteryVoltage;
uint16_t errors;
} AppAuxSLANPacket_t;
So when I want to convert my struct into a byte array (buffer) I do this:
Code:
{
transcribePacket((uint8_t*)&AuxSLANPacket, 6);
}...
void transcribePacket(uint8_t message[], uint8_t length) {
int x, y = 0;
for (x = 0; x < length; x++) {
buffer[x] = message[x];
} // for
} // transcribe
This works fine on the embedded device and I get a byte array with all of the data of the structs in it. If I do the same in the linux dev environment the 16bit variables are written to the byte array backwards:
embedded device example byte array: (correct)
0x10 | 0x20 | 0x01 | 0xFF | 0xDA | 0x33
Linux dev environment example for same data:
0x10 | 0x20 | 0xFF | 0x01 | 0x33 | 0xDA
Here the 16 bit values have been entered into the byte array, but put in backwards.
It is exactly the same code doing this on each platform which leads me to think there is a compiler options somewhere I need to change.
Has anyone got any ideas?
may thanks indeed
David
-
-
> It is exactly the same code doing this on each platform which leads me to think there is a compiler options somewhere I need to change.
No, there's something in your code which needs to change.
Endianness - Wikipedia, the free encyclopedia
There is no compiler flag which can magic away endian problems for you.
Up to now, you've just been lucky that the endian of your processors has matched the endian of your data stream. So you could get away with basically memcpy
If you want it to be truly portable, then you need to deal with each byte yourself, eg
Code:
void transcribePacket(AppAuxSLANPacket_t *result, uint8_t message[], uint8_t length) {
result->deviceType = message[0];
result->RSSI = message[1];
result->batteryVoltage = message[2] | ( message[3] << 8 );
result->errors = message[4] | ( message[5] << 8 );
}
You might have to mess about with which byte gets the <<8 treatment.
Yes it sucks if you have lots of messages, but there's no getting round it if you want portable code.
-
ahh ic, yes that has worked - annoying but hey - if it works...
Just to make sure I understand what I had been reading: the Linux system is a Little endian based system and my embedded system is a big endian based system?
cheers
David
-
Linux on x86 is little endian because x86 is little endian. There can be architectures running Linux that may not be little endian.
The Internet Protocol defines internet endianness as big endian. So Linux provides ntohs() and htons() (htonl.. ntohl too) to switch endianness in a data stream from one to the other.
On big endian systems those functions do nothing because the endianness is already correct.
-
-
Thank you every one for your help, I have been playing with the htons and ntohs functions to try to get the order to reverse:
Code:
uint16_t var1 = 0x1234;
printf("htons: %04X | \n", htons(var1));
printf("ntohs: %04X | \n\n", ntohs(var1));
But neither of them seem to do anything to do the data? Am I doing something wrong?
cheers
David :)
-
ntohs() etc are wired into your machine to do the "right thing" for messages which have been created using htons()
You can use the idea, but I think you need to create your own functions to match the endian-ess of your actual data.
The implementation of ntons() et al WILL change if the underlying architecture Linux is running on. If you get them to work on Linux 'A', then it's back to being broken again on Linux 'B'