Author Topic: Converting struct in to array changing byte order  (Read 11283 times)

0 Members and 1 Guest are viewing this topic.

Offline sangarTopic starter

  • Regular Contributor
  • *
  • Posts: 125
  • Country: in
Converting struct in to array changing byte order
« on: July 04, 2017, 05:39:15 am »
Hello all,

I am working on PIC18 (XC8 compiler)  based Project which acquires 7 sensors values and send them to PC. Each sensor value is  2 bytes long basically 16-bit integer.so,totally 14 bytes.To frame all the sensor values in one packet, I use structure and convert it to array while send to PC.

Problem:
In the packet received at PC side, I am getting LSByte followed by MSByte instead MSByte followed by LSByte.

EX:

Actual value of Sensor_1  =  0x0155 ,  but in the RX side I am getting  0x5501.
Here is the code:

Code: [Select]
typedef struct
{
 
    uint16_t CR_sensor;   //sensor 1
    uint16_t MR_sensor;   //sensor 2
    uint16_t BC_sensor;   //sensor 3
    uint16_t AR_sensor;   //sensor 4
    uint16_t BP_sensor;   //sensor 5
    uint16_t LVDT_1;      //sensor 6
    uint16_t LVDT_2;      //sensor 7
   
}Packet_t;

extern Packet_t packet;


Uart_transmission:
Code: [Select]
UART_Write_Packet((uint8_t *)&packet,sizeof(Packet_t));
Compiler: XC8 V1.36

I read that this is the problem due to big endian format used by Compiler.
Please suggest a solution.


Thanks,
Sangar





 
 

Offline Mechatrommer

  • Super Contributor
  • ***
  • Posts: 11630
  • Country: my
  • reassessing directives...
Re: Converting struct in to array changing byte order
« Reply #1 on: July 04, 2017, 05:47:56 am »
correct the endianess in PC.. problem solved. or val = ((val & 255) << 8 ) + ((val >> 8 ) & 255) in mcu... edit: damned smiley code..
Nature: Evolution and the Illusion of Randomness (Stephen L. Talbott): Its now indisputable that... organisms “expertise” contextualizes its genome, and its nonsense to say that these powers are under the control of the genome being contextualized - Barbara McClintock
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 825
Re: Converting struct in to array changing byte order
« Reply #2 on: July 04, 2017, 06:26:06 am »
Quote
due to big endian format used by Compiler.
The data is actually stored in little endian - the lower address has the lower byte. A uint16_t is stored LL HH (LL in the lower address, HH in the higher address), which means if sending out as bytes the lower address goes out first.

If you want to send out HH LL, you have to reverse it somewhere.

for( uint8_t i = 0; i < sizeof(Packet_t); i += 2){
    UART_Write_Packet((uint8_t *)&packet[i+1],1);//HH
    UART_Write_Packet((uint8_t *)&packet,1);//LL
}

or rewrite function

UART_Write_Packet(uint16_t* pkt, uint8_t sz){
    for( uint8_t i = 0; i < sz; i++){
        UART_write_byte(pkt>>8 );//HH
        UART_write_byte(pkt);//LL
    }
}

or many other options
 

Offline agehall

  • Frequent Contributor
  • **
  • Posts: 383
  • Country: se
Re: Converting struct in to array changing byte order
« Reply #3 on: July 04, 2017, 06:27:20 am »
Always use htons() and ntohs() for things like this!
 

Offline AG6QR

  • Frequent Contributor
  • **
  • Posts: 857
  • Country: us
    • AG6QR Blog
Re: Converting struct in to array changing byte order
« Reply #4 on: July 04, 2017, 06:32:42 am »
correct the endianess in PC.. problem solved.

At first I misread this as, "correct the endianness of PC".  IOW, avoid using anything with an Intel architecture or one of the other little-endian machines.  I was going to shout out a big "Bravo!"

But then I realized you probably meant to write the PC software such that it would flip the byte order.  I suppose that's the most practical solution, and I will (somewhat reluctantly) endorse that.

But something about fixing the PC to be big-endian still appeals to me.
 
The following users thanked this post: phliar

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Converting struct in to array changing byte order
« Reply #5 on: July 04, 2017, 06:37:40 am »
I read that this is the problem due to big endian format used by Compiler.
XC8 user guide page 149:-

All integer values are represented in little endian format with the Least Significant Byte (LSB) at the lower address.

Quote
In the packet received at PC side, I am getting LSByte followed by MSByte
And that is a problem because?
 

Online IanB

  • Super Contributor
  • ***
  • Posts: 11876
  • Country: us
Re: Converting struct in to array changing byte order
« Reply #6 on: July 04, 2017, 07:28:55 am »
I read that this is the problem due to big endian format used by Compiler.
Please suggest a solution.

Either correct the byte order at the sending end or the receiving end. This question is a little bit like asking how to tie a shoelace, is it not?

Another solution is to send the data in hex format, by literally sending "0155" over the link. A good reason for sending human readable data over the wire is that you can more readily sniff the messages and see what is being sent and received for diagnostic purposes.
« Last Edit: July 04, 2017, 07:32:49 am by IanB »
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 2416
  • Country: us
Re: Converting struct in to array changing byte order
« Reply #7 on: July 04, 2017, 07:54:19 am »
For portable code, the ideal solution is to avoid endianness issues entirely. I've written a lot of portable code in my day.

One solution is to transmit data in text format. As a bonus, it's a human-readable data stream. If you're transmitting floating point data between unknown systems, I'd recommend this for generic situations. Native formats for floating point can be VERY different.

Otherwise, my recommendation is properly define your transmission packets at the BYTE level. Then you know EXACTLY what to pack and unpack on each end, and the enddianness of the platform is irrelevant and doesn't byte you (pun intended).

So instead of what you have, something like:
typedef struct
{
    uint8_t CR_sensor_msb;   //sensor 1
    uint8_t CR_sensor_lsb;   //sensor 1
    uint8_t MR_sensor_msb;   //sensor 2
    uint8_t MR_sensor_lsb;   //sensor 2
    uint8_t BC_sensor_msb;   //sensor 3
    uint8_t BC_sensor_lsb;   //sensor 3
// etc...you get the idea   
}Packet_t;
 

Offline alm

  • Super Contributor
  • ***
  • Posts: 2879
  • Country: 00
Re: Converting struct in to array changing byte order
« Reply #8 on: July 04, 2017, 12:49:37 pm »
While I agree that ASCII can be a good solution, I do not see the point of the latter suggestion. If you want to send binary integers > 8 bits, just define a byte order for the protocol and use something like htons() to convert. To split up the bytes in a struct still requires pretty much the same code as converting, and results in code that is harder to read.

How is:
Code: [Select]
packet->CR_sensor_msb = cr_sensor >> 8;
packet->CR_sensor_lsb = (uint8_t)cr_sensor;
[...]
UART_Write_Packet(packet, sizeof(packet));
[...]
cr_sensor = packet->CR_sensor_msb << 8 & packet->CR_sensor_lsb;

More readable than:
Code: [Select]
packet->CR_sensor = htons(cr_sensor);
[...]
UART_Write_Packet(packet, sizeof(packet));
[...]
cr_sensor = ntohs(packet->CR_sensor);

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Converting struct in to array changing byte order
« Reply #9 on: July 04, 2017, 01:27:27 pm »
How do you acquire data from sensors? The easiest way is  to store the acquired bytes in the correct order (opposite to what you do now).
 

Offline NivagSwerdna

  • Super Contributor
  • ***
  • Posts: 2495
  • Country: gb
Re: Converting struct in to array changing byte order
« Reply #10 on: July 04, 2017, 02:05:58 pm »
correct the endianess in PC
+1

These endian-ness issue crops up a lot when converting from internal representations to on-the-wire forms.  In particular you find it when writing network protocols (if that's what you spent some of your life doing many decades ago)!  The Berkley Socket functions htons (host to network short) functions were created to help out with this respect.  On the plus side having a well defined network order at least allows the recipients to convert to their own host order which in a heterogeneous environment may differ (certainly did in the environment I was working.... but that's a longer story).
 

Offline ealex

  • Frequent Contributor
  • **
  • Posts: 313
  • Country: ro
Re: Converting struct in to array changing byte order
« Reply #11 on: July 04, 2017, 02:12:09 pm »
Treating structure as byte arrays and sending them over between system with different endianes is a bad idea.
It will work if you structure is homogeneous - same data type and it will break and make you waste hours when you change something in the structure - different data types or just structure packing.

Specific case : 3 mcu's , different endianes, very little available resources ( 1K of RAM on one of them )
complex structures had to go from 1'st to 3'rd where the 2'nd acted as a router + data modifier.
The chain was : MCU 1 gets CAN frame, populates specific frame structure and sends it to MCU 2
MCU 2 shifts endianess, changes something, shifts endianess again and sends it to MCU3

now imagine what will happens if a compiler option changed on one of the mcu's to pack structures or when CAN structures change ...
=> hours and hours and hours of comparisons, hunting bugs, etc


=> the solution was to have common macros to shift / pack / unpack each structure to the serial buffer
added bonus : we could make a PC decoder and have some real-time debug
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Converting struct in to array changing byte order
« Reply #12 on: July 04, 2017, 02:17:11 pm »
Treating structure as byte arrays and sending them over between system with different endianes is a bad idea.

FYI: That is how Internet works :)
 

Offline sokoloff

  • Super Contributor
  • ***
  • Posts: 1799
  • Country: us
Re: Converting struct in to array changing byte order
« Reply #13 on: July 04, 2017, 02:22:54 pm »
Treating structure as byte arrays and sending them over between system with different endianes is a bad idea.
FYI: That is how Internet works :)
Not really. It treats structures as structures and uses hton and ntoh (host to network and network to host) convertors to put those structs into bytes on the network in network-byte-order.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Converting struct in to array changing byte order
« Reply #14 on: July 04, 2017, 02:43:40 pm »
Not really. It treats structures as structures and uses hton and ntoh (host to network and network to host) convertors to put those structs into bytes on the network in network-byte-order.

PHY operates on the byte level. Drivers treat the sequences of bytes as packets (structures). It is up to the user program to apply hton/ntoh functions as necessary. In the end, "it" does all the job for you.

When you're considering communications from MCU to PC through a serial line, you need to it all by yourself.
 

Offline sokoloff

  • Super Contributor
  • ***
  • Posts: 1799
  • Country: us
Re: Converting struct in to array changing byte order
« Reply #15 on: July 04, 2017, 02:56:11 pm »
PHY operates on the byte level. Drivers treat the sequences of bytes as packets (structures). It is up to the user program to apply hton/ntoh functions as necessary. In the end, "it" does all the job for you.
Agreed, but surely you don't consider PHY/layer 1 on a local LAN to be the same as "the Internet"
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Converting struct in to array changing byte order
« Reply #16 on: July 04, 2017, 02:59:55 pm »
PHY operates on the byte level. Drivers treat the sequences of bytes as packets (structures). It is up to the user program to apply hton/ntoh functions as necessary. In the end, "it" does all the job for you.
Agreed, but surely you don't consider PHY/layer 1 on a local LAN to be the same as "the Internet"

Of course not. Internet is all of the above and more ...
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Converting struct in to array changing byte order
« Reply #17 on: July 04, 2017, 03:17:39 pm »
Always use htons() and ntohs() for things like this!
But XC8 doesn't have those functions built in so you have to write them yourself, and you are back to square one because the implementation is platform-specific.

Luckily Microchip have a TCPIP library, which includes the following (in network.h):-
Code: [Select]
#define byteSwap16(a) ((((uint16_t)a & (uint16_t)0xFF00) >> 8) | (((uint16_t)a & (uint16_t)0x00FF) << 8))
#define byteReverse32(a) ((((uint32_t)a&(uint32_t)0xff000000) >> 24) | \
                          (((uint32_t)a&(uint32_t)0x00ff0000) >>  8) | \
                          (((uint32_t)a&(uint32_t)0x0000ff00) <<  8) | \
                          (((uint32_t)a&(uint32_t)0x000000ff) << 24) )

// host to network & network to host macros
#define htons(a) byteSwap16(a)
#define ntohs(a) byteSwap16(a)
#define htonl(a) byteReverse32(a)
#define ntohl(a) byteReverse32(a)



 
 

Offline Ian.M

  • Super Contributor
  • ***
  • Posts: 12855
Re: Converting struct in to array changing byte order
« Reply #18 on: July 04, 2017, 04:38:36 pm »
Ditch the struct and code it in pure 'vanilla' ANSI C with *NO* assumptions about the endianness of the underlying architecture or compiler implementation.

To do this store the sensor values in a uint16_t array so  the transmit routine can loop through them as uint16_t values without type punning.   Use an enum for the fixed index of each named sensor in the array - the sequence of the enumed names sets the sequence of the fields in the packet.  Make the transmit routine responsible for the TX byte order of each uint16_t value, extracting the bytes with shifts and masks.
« Last Edit: July 05, 2017, 10:15:38 am by Ian.M »
 

Offline madires

  • Super Contributor
  • ***
  • Posts: 7763
  • Country: de
  • A qualified hobbyist ;)
Re: Converting struct in to array changing byte order
« Reply #19 on: July 04, 2017, 04:48:31 pm »
As we got a network byte order define a byte order for your protocol and convert to/from based on the endianness of the MCU or PC. For performance reasons I'd choose the MCU's endianness as byte order for my protocol.
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 2416
  • Country: us
Re: Converting struct in to array changing byte order
« Reply #20 on: July 04, 2017, 06:42:45 pm »
As we got a network byte order define a byte order for your protocol and convert to/from based on the endianness of the MCU or PC. For performance reasons I'd choose the MCU's endianness as byte order for my protocol.

Which is fine between KNOWN systems that are explicitly aware of underlying assumptions. Which are hopefully boldly documented in the code. There are so many programmers that aren't even AWARE of what endieness the current processor is using.  It varies among micro families as well; it's not just a PC and intel-based Mac thing.

My point is that the problem came up in the first place because the transmission packet was poorly defined, to the point of being different depending on the platform it was executing on. My example above was for illustration of a simple case. There are many variations on the theme. And yes, using the network byte order macros is one of those. Much of my career predates the existance of that standard, nor are they a total solution.
 

Offline Mechatrommer

  • Super Contributor
  • ***
  • Posts: 11630
  • Country: my
  • reassessing directives...
Re: Converting struct in to array changing byte order
« Reply #21 on: July 05, 2017, 05:29:34 am »
correct the endianess in PC.. problem solved.
But something about fixing the PC to be big-endian still appeals to me.
we cannot say either big or small endian is right or wrong, its inherent in the design of the hardware... btw, in avr chip there is register setting to store 10/16bits adc value as right or left aligned in adc register, setting this appropriately, and you dont have to change your code a thing. i'm not sure about pic18... otoh sending in ascii (of hex ascii) format have some good points as mentioned, but also bad points that needs to be aware of, the transmitted data will double the size (create some issue in large data transmission, slower etc) and have translation processing (binary to ascii) penalty, so not suited if higher speed acquisition application is required. ymmv...
Nature: Evolution and the Illusion of Randomness (Stephen L. Talbott): Its now indisputable that... organisms “expertise” contextualizes its genome, and its nonsense to say that these powers are under the control of the genome being contextualized - Barbara McClintock
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Converting struct in to array changing byte order
« Reply #22 on: July 05, 2017, 09:43:12 am »
OT:

Code: [Select]
       uint32_t data=0x01234567;

       Little endian             Big endian
       +----+----+----+----+    +----+----+----+----+
       |0x67|0x45|0x23|0x01|    |0x01|0x23|0x45|0x67|
       +----+----+----+----+    +----+----+----+----+
        byte:    0    1    2    3         0    1    2    3

Little Endian (e.g. how it appears on x86) vs Big Endian (e.g. how it appears on m68k and PowerPC)

Recently a friend wanted to realize a 68K clone in Little Endian

Quote
Endianess is a little endian machine. The least significant bytes are stored at the lowest address. This differs from the 68k which a big endian machine.This impacts the order of data stored in the system and specification of immediate constants.

And people claimed that

Quote
Oh, WOW, a little-endian 68K?!! I love it!! So much more elegant and sensible.

more elegant? more sensible? more-UAT-W-h-a-t?

My mind goes back when people programmed directly in machine codes and their program-lists where just a tabs of hex numbers. Oh, it's so clear to me WHY Motorola and IBM have always enjoyed the BigEndian format: because it makes it natural, since for human beings, numbers usually start with the higher part on the left.

FSCKOFF Intel!!!

And their silly decision to "make it different", reinventing the wheel in Little Endian.

btw, now why on the why ARM wants to be LE(1)?!?!?
Business decision? Marketing? Intel alliance?
(as initially intel wanted to produce arm chips)

Probably technical decisions are like blowing in the wind, but for sure we are still (and we forever will be) annoyed by their choice  :palm: :palm: :palm: :palm:

edit:
(1) yes, ARM-chips have a trick somewhere in the chip-configuration which allows them to switch from LE to BE. Some MIPS modern chips (e.g. MIPS32/R2) have a similar trick as well as the old MIPS-R3K used by SONY for their PlayStation1. The chip is configured as LE/BE (firmware choice) as the first instruction executed when the power on. But it's not the point.
« Last Edit: July 05, 2017, 09:58:04 am by legacy »
 

Online nfmax

  • Super Contributor
  • ***
  • Posts: 1560
  • Country: gb
Re: Converting struct in to array changing byte order
« Reply #23 on: July 05, 2017, 10:02:31 am »
It seems people are missing the point here. The byte endian-ness is a property that must be specified in the communication protocol between the two systems, and the implementation of the protocol in each system must be responsible for converting to & from the native machine format. Just using 'text format' doesn't get round the problem - the native text encoding might be different in each system: 7 bit ASCII, UTF-8, UTF-16 or even EBCDIC! Even things like the bit order (for serial protocols) and polarity have to be specified.

No-one seems to have picked up that when sending structs, the member alignment also has to be specified by the protocol.
 
The following users thanked this post: agehall

Offline helius

  • Super Contributor
  • ***
  • Posts: 3640
  • Country: us
Re: Converting struct in to array changing byte order
« Reply #24 on: July 05, 2017, 10:09:41 am »
The reason probably has to do with little-endian I/O devices. Your processor can have the capability to switch between different endian modes for each I/O device and memory (every PPC since the 601 has had it), but it needs to be supported by software with the appropriate instructions. If device DMA goes straight to memory, you have additional problems.

There are some algorithmic differences between big and little-endian. Certain algorithms (for searching or parsing) prefer a particular byte order.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf