1
0
mirror of https://github.com/mjg59/python-broadlink.git synced 2024-11-22 07:00:12 +01:00

Improve CRC-16 function (#565)

* Rename calculate_crc16 to crc16

* Apply PEP-8 naming conventions

* Remove unnecessary import

* Accept any sequence type

* Remove unnecessary conversions

* Expose polynomial and initial value as kwargs

* Remove unnecessary bitwise operations

* Store the CRC-16 table for performance

* Add missing type hints

* Update docstring

* General improvements
This commit is contained in:
Felipe Martins Diel 2021-04-01 12:19:16 -03:00 committed by Felipe Martins Diel
parent 1a8ee21a34
commit 86b5d0727c
2 changed files with 30 additions and 24 deletions

View File

@ -3,7 +3,7 @@ from typing import List
from . import exceptions as e from . import exceptions as e
from .device import device from .device import device
from .helpers import calculate_crc16 from .helpers import crc16
class hysen(device): class hysen(device):
@ -19,7 +19,7 @@ class hysen(device):
def send_request(self, input_payload: bytes) -> bytes: def send_request(self, input_payload: bytes) -> bytes:
"""Send a request to the device.""" """Send a request to the device."""
crc = calculate_crc16(input_payload) crc = crc16(input_payload)
# first byte is length, +2 for CRC16 # first byte is length, +2 for CRC16
request_payload = bytearray([len(input_payload) + 2, 0x00]) request_payload = bytearray([len(input_payload) + 2, 0x00])
@ -40,7 +40,7 @@ class hysen(device):
raise ValueError( raise ValueError(
"hysen_response_error", "first byte of response is not length" "hysen_response_error", "first byte of response is not length"
) )
crc = calculate_crc16(response_payload[2:response_payload_len]) crc = crc16(response_payload[2:response_payload_len])
if (response_payload[response_payload_len] == crc & 0xFF) and ( if (response_payload[response_payload_len] == crc & 0xFF) and (
response_payload[response_payload_len + 1] == (crc >> 8) & 0xFF response_payload[response_payload_len + 1] == (crc >> 8) & 0xFF
): ):

View File

@ -1,26 +1,32 @@
"""Helper functions.""" """Helper functions."""
from ctypes import c_ushort import typing as t
_crc16_cache = {}
def calculate_crc16(input_data: bytes) -> int: def crc16(
"""Calculate the CRC-16 of a byte string.""" sequence: t.Sequence[int],
crc16_tab = [] polynomial: int = 0xA001, # Default: Modbus CRC-16.
crc16_constant = 0xA001 init_value: int = 0xFFFF,
) -> int:
"""Calculate the CRC-16 of a sequence of integers."""
global _crc16_cache
for i in range(0, 256): try:
crc = c_ushort(i).value crc_table = _crc16_cache[polynomial]
for j in range(0, 8): except KeyError:
if crc & 0x0001: crc_table = []
crc = c_ushort(crc >> 1).value ^ crc16_constant for dividend in range(0, 256):
else: remainder = dividend
crc = c_ushort(crc >> 1).value for _ in range(0, 8):
crc16_tab.append(hex(crc)) if remainder & 1:
remainder = remainder >> 1 ^ polynomial
else:
remainder = remainder >> 1
crc_table.append(remainder)
_crc16_cache[polynomial] = crc_table
crcValue = 0xFFFF crc = init_value
for item in sequence:
for c in input_data: crc = crc >> 8 ^ crc_table[(crc ^ item) & 0xFF]
tmp = crcValue ^ c return crc
rotated = c_ushort(crcValue >> 8).value
crcValue = rotated ^ int(crc16_tab[(tmp & 0x00FF)], 0)
return crcValue