7

I'm trying to get my head around endianess and bit ordering.

EDIT: As pointed out in the comments, the endianess doesn't concern my problem, but I like to have it put up here just for completeness. At least no one contradicted my "definitions".

What I have learned so far: If a value (perhaps a word) is comprised of more than one byte (word: 2 bytes) there are two different ways to hold that value in a continuous block of memory. Let's say we have a value of decimal 43210 (0xA8CA, 1010100011001010)

  • BigEndian (first) saves the byte which would have a greater effect on the values magnitude at the lower address, a bit like we write normal arabic numbers.

    Memory address |  1000  |  1001  
    ---------------|--------|---------
    Bytes          |   A8   |   CA
    
  • LittleEndian (first) saves the byte which would have a smaller effect on the values magnitude at the lower address

    Memory address |  1000  |  1001  
    ---------------|--------|---------
    Bytes          |   CA   |   A8
    

Is this correct?

The second thing I have learned is, that there are two different ways to save bits of one byte in memory (sticking with 43210 and BigEndian):

  • Most significant bit (first/left) saves, analoguos BigEndian for bytes, the bits having the greatest impact on the values magnitude first in memory, again: as we write our arabic numbers.

    Memory address |  1000                         |  1001  
    Bit values     |128|64 |32 |16 |8  |4  |2  |1  |128|64 |32 |16 |8  |4  |2  |1  |
    --------------------------------------------------------------------------------
    Bits           | 1   0   1   0   1   0   0   0 | 1   1   0   0   1   0   1   0
    
  • Least significant bit (first/left) reverses the order of bits within a byte, so the bit differentiating between an even and uneven number comes first

    Memory address |  1000                         |  1001  
    Bit values     |1  |2  |4  |8  |16 |32 |64 |128|1  |2  |4  |8  |16 |32 |64 |128|
    --------------------------------------------------------------------------------
    Bits           | 0   0   0   1   0   1   0   1 | 0   1   0   1   0   0   1   1   
    

Is that also correct?

Here comes my scenario and Problem: I am receiving data over network. The protocol (Modbus) specifies a) data transfer as BigEndian and when bits have to be returned, wrapped up in bytes, the MSB is to the left and the LSB to the right. I am programming in C#, .Net 4.5.

On many an occasion I have made use of the BitConverter-class to check for the endianess of my system (BitConverter.IsLittleEndian) to correctly pass word-values through my NetSocket.

    public static byte[] CorrectEndianess(byte[] in_byteArray)
    {
        if (BitConverter.IsLittleEndian)
            return in_byteArray.Reverse().ToArray();
        else return in_byteArray;
    }

It all grinds to a halt when I receive a byte containing eight bits representing the state of eight coils (or inputs). By definition the Modbus protocol delivers the following (example):

    Coil No. (example) | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 |
    -------------------|---------------------------------------|
    Bits               |MSB                                 LSB|
    Example values     | 0  | 0  | 0  | 0  | 0  | 0  | 0  | 1  |

The byte containing this information is shown in the debugger to have the value "1", which is nice. I need, however, every single bit as boolean value. C# provides the BitArray, a class I can pass bytes, which returns a bool[], ideal for my purposes.

    BitArray ba = new BitArray(new byte[1] { my_byte_which_is_of_value_1 });

If I print the BitArrays array, ba[0] contains the value true, the rest false. So I figure that BitArray thinks that a single byte is LSB first. Which is odd, because it breaks the remaining handling of the bits, which expects (for the example) ba[7] to be true.

Long story short, here is my main question:

How can I check which bit ordering is assumed in BitArray or in byte, so I always know where my LSB and MSB are?

On a sidenote: Are numbers in right-to-left-notation-languages written BigEndian right?

lhiapgpeonk
  • 457
  • 1
  • 5
  • 18
  • 2
    Endianness doesn't affect a bit order inside single byte. BitArray works according to its definition: `The Least Significant Bit of each byte represents the lowest index value: " bytes [0] & 1" represents bit 0, " bytes [0] & 2" represents bit 1, " bytes [0] & 4" represents bit 2, and so on.` http://msdn.microsoft.com/en-us/library/x1xda43a%28v=vs.110%29.aspx – Alex F Aug 12 '14 at 10:05
  • So, it looks like your attempt to handle endianness, trying to read single byte from Modbus is kind of overkill. Just use these bytes as is, unless the protocol sends words or double words. – Alex F Aug 12 '14 at 10:07
  • Your first comment: Ah. I should have looked more closely. So it is: `ba[0]` is _always_ the LSB? Your second comment: Well, if I get just one byte of data returned (which is a valid use case) and have to access the bits of that one byte I wouldn't count that as overkill – lhiapgpeonk Aug 12 '14 at 10:47
  • I mean: endianness is not related, when you read a single byte.Only when you read words, double words and greater numbers, you need to think about endianness. Again, bits order inside a single byte is not affected (unless communication protocol uses reversed bits order, which should be mentioned in the documentation). To access the bits you can use BitArray or bitwise operations - this is your choice. – Alex F Aug 12 '14 at 11:14
  • OK, so I had the whole "Endian"-part just for completeness in the question, because there are 4 combinations of the two. You are right, endianess is not part of the one-byte problem – lhiapgpeonk Aug 12 '14 at 11:17

2 Answers2

0

Instead of concerning yourself with determining the endianness of the remote system, have you tried using IPAddress.HostToNetworkOrder on the host sending data and then IPAddress.NetworkToHostOrder on the receiving side? This way, you make your code agnostic to the effects of endianneas.

http://msdn.microsoft.com/en-us/library/system.net.ipaddress.hosttonetworkorder(v=vs.110).aspx

http://msdn.microsoft.com/en-us/library/system.net.ipaddress.networktohostorder(v=vs.110).aspx

Mike
  • 316
  • 1
  • 4
  • Well, I don't need to determine the endianess of the remote system, I know what endianess it wants and what it returns. Also the functions you provided are interesting to remember, but as I want to read single bits in the correct order from a byte, they are no use here, for they only work with ints. (word to long) – lhiapgpeonk Aug 12 '14 at 11:28
0

Now, after just a few comments I got the answer I was looking for. Had I been looking more closely I would have stumbled over it myself.

As pointed out by @Alex Farber the MSDN states that the LSB has the lowest index in a BitArray. I found this answer also here: https://stackoverflow.com/a/9066924/1968308

Community
  • 1
  • 1
lhiapgpeonk
  • 457
  • 1
  • 5
  • 18