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 | CALittleEndian (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 0Least 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?
2 Answers 2
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
1 Comment
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
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.msdn.microsoft.com/en-us/library/x1xda43a%28v=vs.110%29.aspxba[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