I have a devious little problem to which I think I've come up with a solution far more difficult than needs to be.
The problem is that I have two bytes. The first two bits of the first byte are to be removed (as the value is little endian, these bits are effectively in the middle of the 16 bit value). Then the least significant two bits of the second byte are to be moved to the most significant bit locations of the first byte, in place of the removed bits.
My solution is as follows:
byte firstByte = (byte)stream.ReadByte(); // 01000100
byte secondByte = (byte)stream.ReadByte(); // 00010010
// the first and second byte equal the decimal 4676 in this little endian example
byte remainderOfFirstByte = (byte)(firstByte & 63); // 01000100 & 00111111 = 00000100
byte transferredBits = (byte)(secondByte << 6); // 00010010 << 6 = 10000000
byte remainderOfSecondByte = (byte)(secondByte >> 2); // 00010010 >> 2 = 00000100
byte newFirstByte = (byte)(transferredBits | remainderOfFirstByte); // 10000000 | 00000100 = 10000100
int result = BitConverter.ToInt32(new byte[]{newFirstByte, remainderOfSecondByte, 0, 0}, 0); //10000100 00010000 (the result is decimal 1156)
Is there an easier way* to achieve this?
*less verbose, perhaps an inbuilt function or trick I'm missing? (with the exception of doing both the & and << on the same line)
You don't have to mask out bits that a shift would throw away anyway. And you don't have to transfer those bits manually. So it becomes this: (not tested)
int result = (secondByte << 6) | (firstByte & 0x3F);
Related
I have an integer u=101057541.
Binary, this is equal to: 00000110 00000110 00000100 00000101
Now, I regard each byte as a seperate decimal (so 6, 6, 4, 5 in this case).
I want to subtract -1 from the first byte, resulting in 6-1=5.
I try to do this as follows:
int West = u | (((u>>24) - 1) << 24);
However, the result is the same as when I ADD 1 to this byte. Can someone explain why and tell me how to subtract -1 from this byte?
UPDATE:
Thus, the result I want is the following binary number:
00000101 00000110 00000100 00000101
Because you're "or"-ing that byte back in:
u | (((u>>24) - 1) << 24);
should be
(u & mask) | (((u>>24) - 1) << 24);
where mask is everything except the byte you're playing with.
You might find unsafe code easier:
int i = 101057541;
byte* b = (byte*)&i;
b[3]--; // note CPU endianness is important here
Console.WriteLine(i);
You can do the same thing without unsafe using "spans" if you're using all the latest bits;
int i = 101057541;
var bytes = MemoryMarshal.Cast<int, byte>(MemoryMarshal.CreateSpan(ref i, 1));
bytes[3]--; // note CPU endianness is important here
Console.WriteLine(i);
or you could use a "union" via a struct with explicit layout - so 4 bytes overlapping 1 int:
var x = new Int32Bytes();
x.Value = 101057541;
x.Byte3--; // note CPU endianness is important here
Console.WriteLine(x.Value);
with:
[StructLayout(LayoutKind.Explicit)]
struct Int32Bytes
{
[FieldOffset(0)]
public int Value;
[FieldOffset(0)]
public byte Byte0;
[FieldOffset(1)]
public byte Byte1;
[FieldOffset(2)]
public byte Byte2;
[FieldOffset(3)]
public byte Byte3;
}
When you subtract 1 from 00000110 the result is 00000101. You OR this with the original value and you get 0000111, which is like if you added 1.
As a one-liner to your problem, you should mask out the region of the bits you are manipulating.:
int West = (u & 0x00FFFFFF) | ((((u & 0xFF000000)>>24) - 1) << 24);
I'm currently struggling with modbus tcp and ran into a problem with interpreting the response of a module. The response contains two values that are encoded in the bits of an array of three UInt16 values, where the first 8 bits of r[0] have to be ignored.
Let's say the UInt16 array is called r and the "final" values I want to get are val1 and val2, then I would have to do the following:
In the above example the desired output values are val1 (=3) and val2 (=6) for the input values r[0]=768, r[1]=1536 and r[2]=0, all values as UInt16.
I already tried to (logically) bit-rightshift r[0] by 8, but then the upper bits get lost because they are stored in the first 8 bits of r[1]. Do I have to concatenate all r-values first and bit-shift after that? How can I do that? Thanks in advance!
I already tried to (logically) bit-rightshift r[0] by 8, but then the upper bits get lost because they are stored in the first 8 bits of r[1].
Well they're not "lost" - they're just in r[1].
It may be simplest to break it down step by step:
byte val1LowBits = (byte) (r[0] >> 8);
byte val1HighBits = (byte) (r[1] & 0xff);
byte val2LowBits = (byte) (r[1] >> 8);
byte val2HighBits = (byte) (r[2] & 0xff);
uint val1 = (uint) ((val1HighBits << 8) | val1LowBits);
uint val2 = (uint) ((val2HighBits << 8) | val2LowBits);
I want to take the first 4 bits of one byte and all bits of another bit and append them to eachother.
This is the result I need to achieve:
This is what I have now:
private void ParseLocation(int UpperLogicalLocation, int UnderLogicalLocation)
{
int LogicalLocation = UpperLogicalLocation & 0x0F; // Take bit 0-3
LogicalLocation += UnderLogicalLocation;
}
But this is not giving the right results.
int UpperLogicalLocation_Offset = 0x51;
int UnderLogicalLocation = 0x23;
int LogicalLocation = UpperLogicalLocation & 0x0F; // Take bit 0-3
LogicalLocation += UnderLogicalLocation;
Console.Write(LogicalLocation);
This should give 0x51(01010001) + 0x23 (00100011),
So the result I want to achieve is 0001 + 00100011 = 000100100011 (0x123)
You will need to left-shift the UpperLogicalLocation bits by 8 before combining the bits:
int UpperLogicalLocation = 0x51;
int UnderLogicalLocation = 0x23;
int LogicalLocation = (UpperLogicalLocation & 0x0F) << 8; // Take bit 0-3 and shift
LogicalLocation |= UnderLogicalLocation;
Console.WriteLine(LogicalLocation.ToString("x"));
Note that I also changed += to |= to better express what is happening.
The problem is that you're storing the upper bits into bits 0-3 of LogicalLocation instead of bits 8-11. You need to shift the bits into the right place. The following change should fix the problem:
int LogicalLocation = (UpperLogicalLocation & 0x0F) << 8;
Also note that the bits are more idiomatically combined using the logical-or operator. So your second line becomes:
LogicalLocation |= UnderLogicalLocation;
You can do this:
int LogicalLocation = (UpperLogicalLocation & 0x0F) << 8; // Take bit 0-3
LogicalLocation |= (UnderLogicalLocation & 0xFF);
...but be careful about endianness! Your documentation says UpperLogicalLocation should be stored in Byte 3, the next 8 bits in Byte 4. Do achieve this, the resulting int LogicalLocation needs to be split into these two bytes correctly.
I have a very basic understanding of bitwise operators. I am at a loss to understand how the value is assigned however. If someone can point me in the right direction I would be very grateful.
My Hex Address: 0xE0074000
The Decimal value: 3758571520
The Binary Value: 11100000000001110100000000000000
I am trying to program a simple Micro Controller and use the Register access Class in the Microsoft .Net Micro Framework to make the Controller do what I want it to do.
Register T2IR = new Register(0xE0074000);
T2IR.Write(1 << 22);
In my above example, how are the bits in the Binary representation moved? I don’t understand how the management of bits is assigned to the address in Binary form.
If someone can point me in the right direction I would be very greatfull.
Forget about decimals for a start. You'll get back to that later.
First you need to see the logic between HEX and BINARY.
Okay, for a byte you have 8 bits (#7-0)
#7 = 0x80 = %1000 0000
#6 = 0x40 = %0100 0000
#5 = 0x20 = %0010 0000
#4 = 0x10 = %0001 0000
#3 = 0x08 = %0000 1000
#2 = 0x04 = %0000 0100
#1 = 0x02 = %0000 0010
#0 = 0x01 = %0000 0001
When you read that in binary, in a byte, like this one %00001000
Then the bit set, is the 4th from right aka bit #3 which has a value of 08 hex (in fact also decimal, but still forget about decimal while you figure out hex/binary)
Now if we have the binary number %10000000
This is the #7 bit which is on. That has a hex value of 0x80
So all you have to do is to sum them up in "nibbles" (each part of the hex byte is called a nibble by some geeks)
the maximum you can get in a nibble is (decimal) 15 or F as 0x10 + 0x20 + 0x40 + 0x80 = 0xF0 = binary %11110000
so all lights on (4 bits) in a nibble = F in hex (15 decimal)
same goes for the lower nibble.
Do you see the pattern?
Refer to #BerggreenDK's answer for what a shift is. Here's some info about what it's like in hex (same thing, just different representation):
Shifting is a very simple concept to understand. The register is of a fixed size, and whatever bits that won't fit falls off the end. So, take this example:
int num = 0xffff << 16;
Your variable in hex would now be 0xffff0000. Note how the the right end is filled with zeros. Now, let's shift it again.
num = num << 8;
num = num >> 8;
num is now 0x00ff0000. You don't get your old bits back. The same applies to right shifts as well.
Trick: Left shifting by 1 is like multiplying the number by 2, and right shifting by 1 is like integer dividing everything by 2.
I'm confused as to why this isn't working, can someone please provide some insight?
I have a function who is taking in an integer value, but would like to store the upper two bits of the hex value into a byte array element.
Let's say if Distance is (24,135)10 or (5E47)16
public ConfigureReportOptionsMessageData(int Distance, int DistanceCheckTime)
{
...
this._data = new byte[9];
this._data[0] = (byte)(Distance & 0x00FF); // shows 47
this._data[1] = (byte)(Distance & 0xFF00); // shows 00
this._data[2] = (byte)(DistanceCheckTime & 0xFF);
...
}
this._data[1] = (byte)(Distance >> 8);
?
This seems like you should be using BitConverter.GetBytes - it will provide a much simpler option.
The reason you get 0 for _data[1] is that the upper 3 bytes are lost when you cast to byte.
Your intermediate result looks like this:
Distance && 0xff00 = 0x00005e00;
When this is converted to a byte, you only retain the low order byte:
(byte)0x00005e00 = 0x00;
You need to shift by 8 bits:
0x00005e00 >> 8 = 0x0000005e;
before you cast to byte and assign to _data[1]