mirror of
https://github.com/mjg59/python-broadlink.git
synced 2024-11-21 14:43:30 +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:
parent
1a8ee21a34
commit
86b5d0727c
@ -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
|
||||
):
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user