4

Scenario: A remote machine (big endian) sends a message to a local machine (little endian) over RS422.

The local machine gets the message as a buffer, i.e. dataBuffer which is an array of 4 16-bit ints. This buffer data eventually be mapped to a MainType data somewhere in the program but this is not our concern. We need a function that swaps the bytes (change the endianness) using the swapData() method.

Question: Given the fact that MainType has exactly 4 data members each 16 bits AND dataBuffer is array of size 4 and each data is 16 bits, can we just swap the data in the buffer WITHOUT mapping it to MainType data structure (as below)?

Constraints:

  • The dataBuffer needs to be global in the program,
  • Swapping needs to be taken care of in swapData() function,
  • The data will be filled in some other method such as useData()

Here is the code:

... 

typedef unsigned short int USINT16;

typedef struct { 
    USINT16  a : 1; 
    USINT16  b : 1; 
    USINT16  c : 1;                         
    USINT16  d : 1;                              
    USINT16  e : 1;  
    USINT16  f : 1;  
    USINT16  g : 1; 
    USINT16  h : 2;                                
    USINT16  i : 3;
    USINT16  j : 4; 
} OtherType; // 16 bits

typedef struct {   
    USINT16   X;
    USINT16   Y;
    USINT16   Z;
    OtherType W;  
} MainType;

...

unsigned short dataBuffer[4]; // available in global scope

...

void swapData() {
    receiveData(&dataBuffer); // data buffer is filled

    int i;  
    for (i = 0; i < 4; i++) {
        dataBuffer[i] = __builtin_bswap16(dataBuffer);
    }
    // The data is little endian now ?
}

...

void useData() {
    MainType data; // map the swapped buffer to data

    // use the data etc.
    ....
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
erol yeniaras
  • 3,701
  • 2
  • 22
  • 40
  • 2
    There are endian-ness issues (big-little) that occur independently at the byte/word and bit level (`USINT16 a : 1; USINT16 b : 1;`). This code is not portable. – chux - Reinstate Monica Jan 21 '16 at 22:54
  • @chux: What if I create a local data of MainType => map the buffer to it => perform byte swapping => write the data back to buffer? – erol yeniaras Jan 21 '16 at 22:58
  • 1
    erol yeniaras, @Nominal Animal is on the right track. For portability, avoid bit_fields. Also consider [fixed width types](http://stackoverflow.com/q/30942107/2410359) like `uint16_t` instead of `USINT16`. – chux - Reinstate Monica Jan 21 '16 at 23:01
  • @chux: Thanks for your quick response. Unfortunately I am not authorized to decide the usage of bit_fields and fixed width types (although I totally agree with you on that), since I am a contributor to a big system where the data structures have already been defined. – erol yeniaras Jan 21 '16 at 23:08
  • @erolyeniaras: what about the serial protocol? can you specify it precisely? Is the device frozen, ie will the code in it ever change? – chqrlie Jan 22 '16 at 00:30
  • @chqrlie: the code will no change. Serial connection is RS422. – erol yeniaras Jan 22 '16 at 01:49

1 Answers1

1

If the remote machine behavior is frozen, you can investigate and determine what is the encoding of bit-fields on that platform and translate the buffer received on the local machine appropriately.

Byte swapping all 16 bit entries, including W, is a good initial step, you might have to change the struct definition for OtherType to fit the order in which it is defined by the compiler for the remote machine. You can determine that by transmitting samples from the remote machine where only 1 field is set to all bits one and the others stay 0 and print the 16 bit value received.

Byte-swapping W is advisable because W.h most likely falls on a byte boundary with 1 bit in each byte. For its bits to be adjacent in the local machine, the bytes in W should be swapped. If the bit order on the remote machine is a b c d e f g h1 h0 i2 i1 i0 j3 j2 j1 j0 for the whole 16 bit word in W, when stored in memory on the remote machine, it becomes <a b c d e f g h1> <h0 i2 i1 i0 j3 j2 j1 j0> and subsequently transmitted as bytes and loaded in a 16 bit register on the local machine, it would become h0 i2 i1 i0 j3 j2 j1 j0 a b c d e f g h1 if you dont swap the bytes, because the first byte is loaded in the low order bits of the register. Byte swapping prevents this but you still may have a problem with the bit-field order in the local machine as your current definition might be encoded as j3 j2 j1 j0 i2 i1 i0 h1 h0 g f e d c b a if the bit-fields are likely allocated from the lowest to the highest bit positions.

If you know some assembly language, generate the assembly for code that manipulate the bit-fields on both platforms and check if the fields are placed differently.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Nice answer! Unfortunately, I can't change the structs. Byte-swapping first 3x16 bytes from for mapping them to X, Y, Z respectively can be enough for them. However, I am confused with W since it has bitfields. Let`s assume that they are filled to buffer in the order they appear in the struct. In other words, buffer has the last 16 bytes of the buffer in this order: 'a b c d e f g h h i i i j j j j'. 16 bit swap will give 'h i i i j j j j a b c d e f g h' , which messes up the order of the data since on the local machine I am still expecting the data in the same order (Am I terribly wrong?) – erol yeniaras Jan 22 '16 at 04:46
  • 1
    I updated the answer, but you are mistaken, I am quite confident you need to both a byte swap and a different definition for `OtherType` in the local machine with the bitfields in reverse order. – chqrlie Jan 22 '16 at 09:06