I start working with HART (Highway Addressable Remote Transducer) Protocol and I found something, let's say different and I try to understand it, more precisely the uint24. I understand that this structure uses an UInt32 internally for storage and most other common expected integer functionality, so using a 24-bit integer will not save memory. But my question is how can I convert an UInt32 to this specific type, I found these lines of code in Javascript but I don't know what is the purpose of those left shifting.
var getUint24 = function(bytes)
{
return (DataView(bytes.buffer).getUint16(0) << 8) + DataView(bytes.buffer).getUint8(0 + 2);
}
Also, I found this function that convert a number to 4 bytes. I also don't know what is the purpose o these shifting, but maybe if I understand these I can create my own version of the function that convert a simple number ex: 4 to his uint24 version.
/**
*
* @function ToBytesInt32 "Convert number to 4 bytes (eg: ToBytesInt32(2) returns 00 00 00 02"
* @param {number} num The input value
* @return {byte array}
*/
function ToBytesInt32BigEndian(num) {
if (isNaN(num)) {
throw "ToBytesInt32 received Nan! Called from: " +
testUtils.StrReplace.caller.toString().split('\n')[0];
}
arr = [
(num & 0xff000000) >> 24,
(num & 0x00ff0000) >> 16,
(num & 0x0000ff00) >> 8,
(num & 0x000000ff)
];
return arr;
}
If anyone can help me to understand the pourpose of those shifting I would apreciate it, also the C/C++ version is very welcomed.
<<
shifting is a padding of significant bits with zeros for future conjunction into single value;>>
shifting is part of extracting of value's segment into smaller data type (goes after applying mask);Shift & sum is the way to pack/unpack values when reading/writing frame is less of value's length. Let's say we have 4 bit value: 1011
. And we able read it only by 2 bit frames: [10], [11]
.
Let's assume that we are reading stream from left to right.
# offset 0 bits
a = stream(0) # a = 10
a << 2 # a = 1000
b = stream (2) # b = 11
return a + b # 1000 + 11 = 1011
Also you should pay attention to BE/LE (Big/Little Endian). In different Endians value 1011
may be presented in stream as 10, 11
or 11, 10
.
In case of getUint24
example we have 24 bit value packed as sequence like [16 bit, 8 bit]
. Let's draw it as [XY, Z]
where single letter is 1 byte.
# offset 0 bytes
a = DataView(bytes.buffer).getUint16(0) # a = XY
a << 8 # a = XY0
# offset 2 bytes
b = DataView(bytes.buffer).getUint8(2) # b = Z
return a + b # XY0 + Z = XYZ
And again bytes.buffer
may keep value either as [XY, Z]
or [Z, XY]
. The getUintX(offset)
hides this details from us. But if you'd like to write own converter, you need investigate what format is in your case.
Here we see another concern of packing values - apply mask.
For say we have 32 bit value AB CD EF 12
. We can apply mask to extract needed segment of the value.
For example, if we have 3 bit value 011
and would like get value of second bit we need apply &-mask where subject bits evaluated against 1
keep original value while rest bits evaluated against 0
turn any value into 0
.
masked = 011 & 010 # 010
bit_value = masked >> 1 # 001
In the same way with our ABCDEF12
x = 0xABCDEF12 & 0xFF000000 # x = 0xAB000000
x >> 24 # x = 0x000000AB
...
This way we will get array [0xAB, 0xCD, 0xEF, 0x12]
. Without shifting we were get array [0xAB000000, 0x00CD0000, 0x0000EF00, 0x00000012]
which is not what we want.
User contributions licensed under CC BY-SA 3.0