Try using the struct module:
import struct
# read 2 bytes from hardware as a string
s = hardware.readbytes(2)
# h means signed short
# < means "little-endian, standard size (16 bit)"
# > means "big-endian, standard size (16 bit)"
value = struct.unpack("<h", s) # hardware returns little-endian
value = struct.unpack(">h", s) # hardware returns big-endian
Answer from ASk on Stack OverflowI have a 32 bit number A = A3A2A1A0 that has been given to me in the form of A = B1B0 where B1 = A3A2 and B0 = A1A0. B1 and B0 are each 16 bit numbers. I now want to use B1 and B0 to get A in an unsigned integer format.
I tried using the 2's complement representation of B1 and B0 but am still not clear as to how I would "add" those two binary numbers.
I also tried using the bin(integer) function in Python to get the binary representation of both B1 and B0 in a list format and then concatenated the two lists to give me A. However, that didn't seem to work if either of B1 or B0 were negative.
I'm not quite understanding how B1 is getting affected when B0 goes into the overflow, i.e crosses 32768 to give a negative number.
If anyone could give me few examples taking B1 and B0 to be positive and negative both, with the final answer A as well that would be great. Any hints and suggestions would be appreciated. Thank you.
SOLVED: 3 Solutions:
-
using Numpy : np.uint16()
-
Using CTypes : ctypes.c_uint16()
-
Using Bitwise : & 0xFFFF
Hi, I'm trying to convert this code to Python from Go / C. It involves declaring a UInt16 variable and run a bit shift operation. However cant seem to create a variable with this specific type. Need some advise here.
Go Code:
package main
import "fmt"
func main() {
var dx uint16 = 38629
var dy uint16 = dx << 8
fmt.Println(dy) //58624 -> Correct value
}
Python Code:
dx = 38629 dy = (dx << 8) print(dy) # 9889024 -> not the expected value print(type(dx)) # <class 'int'> print(type(dy)) # <class 'int'>
I cant seem to figure out a way to cast or similar function to get this into an Unsigned Int 16.\
Please help.
Let's define a conversion function:
>>> def f(x):
... r = int(x, 16)
... return r if r < 2**15 else r - 2**16
...
Now, let's test the function against the values that the datahsheet provided:
>>> f('1FFE')
8190
>>> f('E002')
-8190
The usual convention for signed numbers is that a number is negative if the high bit is set and positive if it isn't. Following this convention, '0000' is zero and 'FFFF' is -1. The issue is that int assumes that a number is positive and we have to correct for that:
For any number equal to or less than
0x7FFF, then high bit is unset and the number is positive. Thus we returnr=int(x,16)if r<2**15.For any number
r-int(x,16)that is equal to or greater than0x8000, we returnr - 2**16.While your sensor may only produce 14-bin data, the manufacturer is following the standard convention for 16-bit integers.
Alternative
Instead of converting x to r and testing the value of r, we can directly test whether the high bit in x is set:
>>> def g(x):
... return int(x, 16) if x[0] in '01234567' else int(x, 16) - 2**16
...
>>> g('1FFE')
8190
>>> g('E002')
-8190
Ignoring the upper bits
Let's suppose that the manufacturer is not following standard conventions and that the upper 2-bits are unreliable. In this case, we can use modulo, %, to remove them and, after adjusting the other constants as appropriate for 14-bit integers, we have:
>>> def h(x):
... r = int(x, 16) % 2**14
... return r if r < 2**13 else r - 2**14
...
>>> h('1FFE')
8190
>>> h('E002')
-8190
There is a general algorithm for sign-extending a two's-complement integer value val whose number of bits is nbits (so that the top-most of those bits is the sign bit).
That algorithm is:
- treat the value as a non-negative number, and if needed, mask off additional bits
- invert the sign bit, still treating the result as a non-negative number
- subtract the numeric value of the sign bit considered as a non-negative number, producing as a result, a signed number.
Expressing this algorithm in Python produces:
from __future__ import print_function
def sext(val, nbits):
assert nbits > 0
signbit = 1 << (nbits - 1)
mask = (1 << nbits) - 1
return ((val & mask) ^ signbit) - signbit
if __name__ == '__main__':
print('sext(0xe002, 14) =', sext(0xe002, 14))
print('sext(0x1ffe, 14) =', sext(0x1ffe, 14))
which when run shows the desired results:
sext(0xe002, 14) = -8190
sext(0x1ffe, 14) = 8190
Here is a solution with structs since I do not know how python represents negative numbers binarily.
import struct
struct.unpack('H', struct.pack('h', number))
It packs it as a short (2 bytes) and unpacks it as an unsigned short.
>>> import numpy as np
>>> np.array([-20357],dtype="uint16")
array([45179], dtype=uint16)
in your case when you are done looping over everything and you have it in a list
just call np.array(my_list,dtype="uint16")
I'm trying to take a number (such as -200) and send it to a robot. The number must be converted to big-endian and sent in two bytes. WolframAlpha does this (the result I need to send is 38ff) but I haven't found a way to do this in python.
Check out hex() and, more importantly struct:
http://docs.python.org/2/library/struct.html
This lets you convert a decimal into binary data. I've used it to read binary files, so it might be what you are looking for. I'm weak on theory so I tend to just bang on stuff until I get it right, but I would start with:
>>> import struct
>>> struct.pack('>h', -200)
b'\xff8'
And see what the machine makes of it, and adjust accordingly.
u/1328 was close with struct, the code you are looking for is:
import struct
print struct.pack('>i', your_int)
>I is the indicator for Big Endian as according to struct.
Python Struct Documentation
EDIT: I just tested this code, and got the same result as u/1328. I'm looking into this more.
EDIT 2: OK. Wolfram's representation of the number -200 in hexadecimal is as an unsigned 16 bit integer. THey make a note that this number overflowed, and the reason is that -200 is, inherently, a signed number.
Are you sure you need to send the number is ff38, and not xff8?
If so, then you need to do some hackery to get this working. Something like:
import struct
def toBigEndian(number):
if number < 0:
number = 65536 + number
return struct.pack('>i',number)