Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 18 additions & 29 deletions hid_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,37 +85,21 @@ def _data_bit_shift(data: Sequence[int], offset: int, length: int) -> Sequence[i
if not length > 0:
raise ValueError(f'Invalid specified length: {length}')

left_extra = offset % 8
right_extra = 8 - (offset + length) % 8
start_offset = offset // 8
end_offset = (offset + length - 1) // 8
byte_length = (length - 1) // 8 + 1
byte_offset = offset // 8
byte_len = (length + 7) // 8
in_end = (length + offset + 7) // 8

if not end_offset < len(data):
raise ValueError(f'Invalid data length: {len(data)} (expecting {end_offset + 1})')
if in_end > len(data):
raise ValueError(f'Invalid data length: {len(data)} (expecting {in_end})')

shifted = [0] * byte_length

if right_extra == 8:
right_extra = 0

i = end_offset
shifted_offset = byte_length - 1
while shifted_offset >= 0:
shifted[shifted_offset] = data[i] >> right_extra

if i - start_offset >= 0:
shifted[shifted_offset] |= (data[i - 1] & (0xff >> (8 - right_extra))) << (8 - right_extra)

shifted_offset -= 1
i -= 1

shifted[0] &= 0xff >> ((left_extra + right_extra) % 8)

if not len(shifted) == byte_length:
raise ValueError('Invalid data')

return shifted
in_slice = data[byte_offset:in_end]
# Take advantage of long ints in Python >= 3
val = int.from_bytes(in_slice, byteorder='little')
# Shift leading LSBs
val >>= offset % 8
# Mask trailing MSBs
val &= (1 << length) - 1
return val.to_bytes(byte_len, byteorder='little')


class BitNumber(int):
Expand Down Expand Up @@ -333,6 +317,7 @@ def __init__(
self._logical_max = logical_max
self._physical_min = physical_min
self._physical_max = physical_max
self._signed = (logical_min < 0) or (logical_max < 0)
# TODO: unit

@property
Expand Down Expand Up @@ -428,6 +413,10 @@ def parse(self, data: Sequence[int]) -> UsageValue:
)
): # int
value = int.from_bytes(data, byteorder='little')
# Sign extend
if self._signed and (value >> (self.size - 1)) != 0:
# Subtracting twice the sign bit saves explicit clearing
value -= (1 << self.size)
elif (
hid_parser.data.UsageTypes.ON_OFF_CONTROL in self.usage.usage_types
and not self.preferred_state
Expand Down