diff --git a/broadlink/climate.py b/broadlink/climate.py index 9f64949..982f105 100644 --- a/broadlink/climate.py +++ b/broadlink/climate.py @@ -3,7 +3,7 @@ from typing import List from . import exceptions as e from .device import device -from .helpers import calculate_crc16 +from .helpers import crc16 class hysen(device): @@ -19,7 +19,7 @@ class hysen(device): def send_request(self, input_payload: bytes) -> bytes: """Send a request to the device.""" - crc = calculate_crc16(input_payload) + crc = crc16(input_payload) # first byte is length, +2 for CRC16 request_payload = bytearray([len(input_payload) + 2, 0x00]) @@ -40,7 +40,7 @@ class hysen(device): raise ValueError( "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 ( response_payload[response_payload_len + 1] == (crc >> 8) & 0xFF ): diff --git a/broadlink/helpers.py b/broadlink/helpers.py index 404fead..d5d7e80 100644 --- a/broadlink/helpers.py +++ b/broadlink/helpers.py @@ -1,26 +1,32 @@ """Helper functions.""" -from ctypes import c_ushort +import typing as t + +_crc16_cache = {} -def calculate_crc16(input_data: bytes) -> int: - """Calculate the CRC-16 of a byte string.""" - crc16_tab = [] - crc16_constant = 0xA001 +def crc16( + sequence: t.Sequence[int], + polynomial: int = 0xA001, # Default: Modbus CRC-16. + init_value: int = 0xFFFF, +) -> int: + """Calculate the CRC-16 of a sequence of integers.""" + global _crc16_cache - for i in range(0, 256): - crc = c_ushort(i).value - for j in range(0, 8): - if crc & 0x0001: - crc = c_ushort(crc >> 1).value ^ crc16_constant - else: - crc = c_ushort(crc >> 1).value - crc16_tab.append(hex(crc)) + try: + crc_table = _crc16_cache[polynomial] + except KeyError: + crc_table = [] + for dividend in range(0, 256): + remainder = dividend + for _ in range(0, 8): + if remainder & 1: + remainder = remainder >> 1 ^ polynomial + else: + remainder = remainder >> 1 + crc_table.append(remainder) + _crc16_cache[polynomial] = crc_table - crcValue = 0xFFFF - - for c in input_data: - tmp = crcValue ^ c - rotated = c_ushort(crcValue >> 8).value - crcValue = rotated ^ int(crc16_tab[(tmp & 0x00FF)], 0) - - return crcValue + crc = init_value + for item in sequence: + crc = crc >> 8 ^ crc_table[(crc ^ item) & 0xFF] + return crc