You can interpret the bytes as a two's complement signed integer using bitwise operations. For example, for a 16-bit number:
def s16(value):
return -(value & 0x8000) | (value & 0x7fff)
Therefore:
>>> s16(int('0xffd2', 16))
-46
>>> s16(int('0xffcb', 16))
-53
>>> s16(int('0xffcc', 16))
-52
>>> s16(int('0x10', 16))
16
>>> s16(int('0xd', 16))
13
>>> s16(int('0x0', 16))
0
>>> s16(int('0xfffe', 16))
-2
This can be extended to any bit-length string, by setting the masks so the first mask matches the most-significant bit (0x8000 == 1 << 15 == 0b1000000000000000
) and the second mask matches the all the remaining bits (0x7fff == (1 << 15) - 1 == 0b0111111111111111
).