[tools] Move functions to utilities, add universal CRC16 class
This commit is contained in:
133
tools/util/crc16.py
Normal file
133
tools/util/crc16.py
Normal file
@@ -0,0 +1,133 @@
|
||||
# Copyright (c) Kuba Szczodrzyński 2022-06-02.
|
||||
|
||||
from enum import Enum
|
||||
from typing import List
|
||||
|
||||
|
||||
class CRC16(Enum):
|
||||
# based on https://crccalc.com/ and https://reveng.sourceforge.io/crc-catalogue/16.htm
|
||||
ANSI = dict(poly=0x8005, init=0x0000, ref=False, out=0x0000)
|
||||
ARC = dict(poly=0x8005, init=0x0000, ref=True, out=0x0000)
|
||||
AUG_CCITT = dict(poly=0x1021, init=0x1D0F, ref=False, out=0x0000)
|
||||
AUTOSAR = dict(poly=0x1021, init=0xFFFF, ref=False, out=0x0000)
|
||||
BUYPASS = dict(poly=0x8005, init=0x0000, ref=False, out=0x0000)
|
||||
CCITT = dict(poly=0x1021, init=0x0000, ref=True, out=0x0000)
|
||||
CCITT_FALSE = dict(poly=0x1021, init=0xFFFF, ref=False, out=0x0000)
|
||||
CCITT_TRUE = dict(poly=0x1021, init=0x0000, ref=True, out=0x0000)
|
||||
CDMA2000 = dict(poly=0xC867, init=0xFFFF, ref=False, out=0x0000)
|
||||
CMS = dict(poly=0x8005, init=0xFFFF, ref=False, out=0x0000)
|
||||
CRC_A = dict(poly=0x1021, init=0xC6C6, ref=True, out=0x0000)
|
||||
CRC_B = dict(poly=0x1021, init=0xFFFF, ref=True, out=0xFFFF)
|
||||
DARC = dict(poly=0x1021, init=0xFFFF, ref=False, out=0xFFFF)
|
||||
DDS_110 = dict(poly=0x8005, init=0x800D, ref=False, out=0x0000)
|
||||
DECT_R = dict(poly=0x0589, init=0x0000, ref=False, out=0x0001)
|
||||
DECT_X = dict(poly=0x0589, init=0x0000, ref=False, out=0x0000)
|
||||
DNP = dict(poly=0x3D65, init=0x0000, ref=True, out=0xFFFF)
|
||||
EN_13757 = dict(poly=0x3D65, init=0x0000, ref=False, out=0xFFFF)
|
||||
EPC = dict(poly=0x1021, init=0xFFFF, ref=False, out=0xFFFF)
|
||||
EPC_C1G2 = dict(poly=0x1021, init=0xFFFF, ref=False, out=0xFFFF)
|
||||
GENIBUS = dict(poly=0x1021, init=0xFFFF, ref=False, out=0xFFFF)
|
||||
GSM = dict(poly=0x1021, init=0x0000, ref=False, out=0xFFFF)
|
||||
I_CODE = dict(poly=0x1021, init=0xFFFF, ref=False, out=0xFFFF)
|
||||
IBM = dict(poly=0x8005, init=0x0000, ref=False, out=0x0000)
|
||||
IBM_3740 = dict(poly=0x1021, init=0xFFFF, ref=False, out=0x0000)
|
||||
IBM_SDLC = dict(poly=0x1021, init=0xFFFF, ref=True, out=0xFFFF)
|
||||
IEC_61158_2 = dict(poly=0x1DCF, init=0xFFFF, ref=False, out=0xFFFF)
|
||||
ISO_14443_3_A = dict(poly=0x1021, init=0xC6C6, ref=True, out=0x0000)
|
||||
ISO_14443_3_B = dict(poly=0x1021, init=0xFFFF, ref=True, out=0xFFFF)
|
||||
ISO_HDLC = dict(poly=0x1021, init=0xFFFF, ref=True, out=0xFFFF)
|
||||
KERMIT = dict(poly=0x1021, init=0x0000, ref=True, out=0x0000)
|
||||
LHA = dict(poly=0x8005, init=0x0000, ref=True, out=0x0000)
|
||||
LJ1200 = dict(poly=0x6F63, init=0x0000, ref=False, out=0x0000)
|
||||
M17 = dict(poly=0x5935, init=0xFFFF, ref=False, out=0x0000)
|
||||
MAXIM = dict(poly=0x8005, init=0x0000, ref=True, out=0xFFFF)
|
||||
MCRF4XX = dict(poly=0x1021, init=0xFFFF, ref=True, out=0x0000)
|
||||
MODBUS = dict(poly=0x8005, init=0xFFFF, ref=True, out=0x0000)
|
||||
NRSC_5 = dict(poly=0x080B, init=0xFFFF, ref=True, out=0x0000)
|
||||
OPENSAFETY_A = dict(poly=0x5935, init=0x0000, ref=False, out=0x0000)
|
||||
OPENSAFETY_B = dict(poly=0x755B, init=0x0000, ref=False, out=0x0000)
|
||||
PROFIBUS = dict(poly=0x1DCF, init=0xFFFF, ref=False, out=0xFFFF)
|
||||
RIELLO = dict(poly=0x1021, init=0xB2AA, ref=True, out=0x0000)
|
||||
SPI_FUJITSU = dict(poly=0x1021, init=0x1D0F, ref=False, out=0x0000)
|
||||
T10_DIF = dict(poly=0x8BB7, init=0x0000, ref=False, out=0x0000)
|
||||
TELEDISK = dict(poly=0xA097, init=0x0000, ref=False, out=0x0000)
|
||||
TMS37157 = dict(poly=0x1021, init=0x89EC, ref=True, out=0x0000)
|
||||
UMTS = dict(poly=0x8005, init=0x0000, ref=False, out=0x0000)
|
||||
USB = dict(poly=0x8005, init=0xFFFF, ref=True, out=0xFFFF)
|
||||
V_41_LSB = dict(poly=0x1021, init=0x0000, ref=True, out=0x0000)
|
||||
VERIFONE = dict(poly=0x8005, init=0x0000, ref=False, out=0x0000)
|
||||
X_25 = dict(poly=0x1021, init=0xFFFF, ref=True, out=0xFFFF)
|
||||
XMODEM = dict(poly=0x1021, init=0x0000, ref=False, out=0x0000)
|
||||
|
||||
poly: int
|
||||
init: int
|
||||
ref: bool
|
||||
out: int
|
||||
table: List[int]
|
||||
|
||||
def __init__(self, params: dict) -> None:
|
||||
super().__init__()
|
||||
self.poly = params["poly"]
|
||||
self.init = params["init"]
|
||||
self.ref = params["ref"]
|
||||
self.out = params["out"]
|
||||
self.table = None
|
||||
if self.ref:
|
||||
self.poly = self.reverse16(self.poly)
|
||||
self.init = self.reverse16(self.init)
|
||||
|
||||
@staticmethod
|
||||
def reverse16(num: int) -> int:
|
||||
out = 0
|
||||
for i in range(16):
|
||||
out |= ((num & (1 << i)) >> i) << (15 - i)
|
||||
return out
|
||||
|
||||
def calc(self, data: bytes) -> int:
|
||||
if self.ref:
|
||||
self._init_ref()
|
||||
return self._calc_ref(data)
|
||||
self._init_std()
|
||||
return self._calc_std(data)
|
||||
|
||||
def _init_std(self):
|
||||
if self.table:
|
||||
return
|
||||
self.table = []
|
||||
for b in range(256):
|
||||
crc = b << 8
|
||||
for _ in range(8):
|
||||
if crc & 0x8000:
|
||||
crc <<= 1
|
||||
crc ^= self.poly
|
||||
else:
|
||||
crc <<= 1
|
||||
self.table.append(crc & 0xFFFF)
|
||||
|
||||
def _init_ref(self):
|
||||
if self.table:
|
||||
return
|
||||
self.table = []
|
||||
for b in range(256):
|
||||
crc = b
|
||||
for _ in range(8):
|
||||
if crc & 0x0001:
|
||||
crc >>= 1
|
||||
crc ^= self.poly
|
||||
else:
|
||||
crc >>= 1
|
||||
self.table.append(crc)
|
||||
|
||||
def _calc_std(self, data: bytes) -> int:
|
||||
crc = self.init
|
||||
for b in data:
|
||||
b ^= crc // 256
|
||||
crc = self.table[b] ^ (crc * 256 % 0x10000)
|
||||
return crc ^ self.out
|
||||
|
||||
def _calc_ref(self, data: bytes) -> int:
|
||||
crc = self.init
|
||||
for b in data:
|
||||
b ^= crc % 256
|
||||
crc = self.table[b] ^ (crc // 256)
|
||||
return crc ^ self.out
|
||||
@@ -1,14 +0,0 @@
|
||||
# Copyright (c) Kuba Szczodrzyński 2022-06-02.
|
||||
|
||||
|
||||
def crc16(data):
|
||||
# https://gist.github.com/pintoXD/a90e398bba5a1b6c121de4e1265d9a29
|
||||
crc = 0x0000
|
||||
for b in data:
|
||||
crc ^= b
|
||||
for j in range(0, 8):
|
||||
if (crc & 0x0001) > 0:
|
||||
crc = (crc >> 1) ^ 0xA001
|
||||
else:
|
||||
crc = crc >> 1
|
||||
return crc
|
||||
53
tools/util/fileio.py
Normal file
53
tools/util/fileio.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# Copyright (c) Kuba Szczodrzyński 2022-06-10.
|
||||
|
||||
import json
|
||||
from io import BytesIO
|
||||
from os.path import dirname, getmtime, isfile, join
|
||||
from typing import Union
|
||||
|
||||
|
||||
def chname(path: str, name: str) -> str:
|
||||
"""Change the basename of 'path' to 'name'."""
|
||||
return join(dirname(path), name)
|
||||
|
||||
|
||||
def chext(path: str, ext: str) -> str:
|
||||
"""Change the file extension of 'path' to 'ext' (without the dot)."""
|
||||
return path.rpartition(".")[0] + "." + ext
|
||||
|
||||
|
||||
def isnewer(what: str, than: str) -> bool:
|
||||
"""Check if 'what' is newer than 'than'.
|
||||
|
||||
Returns False if 'what' is not a file.
|
||||
|
||||
Returns True if 'than' is not a file.
|
||||
"""
|
||||
if not isfile(what):
|
||||
return False
|
||||
if not isfile(than):
|
||||
return True
|
||||
return getmtime(what) > getmtime(than)
|
||||
|
||||
|
||||
def readbin(file: str) -> bytes:
|
||||
"""Read a binary file into a bytes object."""
|
||||
with open(file, "rb") as f:
|
||||
data = f.read()
|
||||
return data
|
||||
|
||||
|
||||
def writebin(file: str, data: Union[bytes, BytesIO]):
|
||||
"""Write data into a binary file."""
|
||||
with open(file, "wb") as f:
|
||||
if isinstance(data, BytesIO):
|
||||
f.write(data.getvalue())
|
||||
else:
|
||||
f.write(data)
|
||||
|
||||
|
||||
# same as load_json
|
||||
def readjson(file: str) -> Union[dict, list]:
|
||||
"""Read a JSON file into a dict or list."""
|
||||
with open(file, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
@@ -2,60 +2,138 @@
|
||||
|
||||
|
||||
def bswap(data: bytes) -> bytes:
|
||||
"""Reverse the byte array (big-endian <-> little-endian)."""
|
||||
return bytes(reversed(data))
|
||||
|
||||
|
||||
def betoint(data: bytes) -> int:
|
||||
"""Convert bytes to big-endian unsigned integer."""
|
||||
return int.from_bytes(data, byteorder="big")
|
||||
|
||||
|
||||
def letoint(data: bytes) -> int:
|
||||
"""Convert bytes to little-endian unsigned integer."""
|
||||
return int.from_bytes(data, byteorder="little")
|
||||
|
||||
|
||||
def betosint(data: bytes) -> int:
|
||||
"""Convert bytes to big-endian signed integer."""
|
||||
return int.from_bytes(data, byteorder="big", signed=True)
|
||||
|
||||
|
||||
def letosint(data: bytes) -> int:
|
||||
"""Convert bytes to little-endian signed integer."""
|
||||
return int.from_bytes(data, byteorder="little", signed=True)
|
||||
|
||||
|
||||
def inttobe32(data: int) -> bytes:
|
||||
"""Convert unsigned integer to 32 bits, big-endian."""
|
||||
return data.to_bytes(length=4, byteorder="big")
|
||||
|
||||
|
||||
def inttole32(data: int) -> bytes:
|
||||
"""Convert unsigned integer to 32 bits, little-endian."""
|
||||
return data.to_bytes(length=4, byteorder="little")
|
||||
|
||||
|
||||
def inttobe24(data: int) -> bytes:
|
||||
"""Convert unsigned integer to 24 bits, big-endian."""
|
||||
return data.to_bytes(length=3, byteorder="big")
|
||||
|
||||
|
||||
def inttole24(data: int) -> bytes:
|
||||
"""Convert unsigned integer to 24 bits, little-endian."""
|
||||
return data.to_bytes(length=3, byteorder="little")
|
||||
|
||||
|
||||
def inttobe16(data: int) -> bytes:
|
||||
"""Convert unsigned integer to 16 bits, big-endian."""
|
||||
return data.to_bytes(length=2, byteorder="big")
|
||||
|
||||
|
||||
def inttole16(data: int) -> bytes:
|
||||
"""Convert unsigned integer to 16 bits, little-endian."""
|
||||
return data.to_bytes(length=2, byteorder="little")
|
||||
|
||||
|
||||
def intto8(data: int) -> bytes:
|
||||
"""Convert unsigned integer to 8 bits."""
|
||||
return data.to_bytes(length=1, byteorder="big")
|
||||
|
||||
|
||||
def sinttobe32(data: int) -> bytes:
|
||||
"""Convert signed integer to 32 bits, big-endian."""
|
||||
return data.to_bytes(length=4, byteorder="big", signed=True)
|
||||
|
||||
|
||||
def sinttole32(data: int) -> bytes:
|
||||
"""Convert signed integer to 32 bits, little-endian."""
|
||||
return data.to_bytes(length=4, byteorder="little", signed=True)
|
||||
|
||||
|
||||
def sinttobe24(data: int) -> bytes:
|
||||
"""Convert signed integer to 24 bits, big-endian."""
|
||||
return data.to_bytes(length=3, byteorder="big", signed=True)
|
||||
|
||||
|
||||
def sinttole24(data: int) -> bytes:
|
||||
"""Convert signed integer to 24 bits, little-endian."""
|
||||
return data.to_bytes(length=3, byteorder="little", signed=True)
|
||||
|
||||
|
||||
def sinttobe16(data: int) -> bytes:
|
||||
"""Convert signed integer to 16 bits, big-endian."""
|
||||
return data.to_bytes(length=2, byteorder="big", signed=True)
|
||||
|
||||
|
||||
def sinttole16(data: int) -> bytes:
|
||||
"""Convert signed integer to 16 bits, little-endian."""
|
||||
return data.to_bytes(length=2, byteorder="little", signed=True)
|
||||
|
||||
|
||||
def sintto8(data: int) -> bytes:
|
||||
"""Convert signed integer to 8 bits."""
|
||||
return data.to_bytes(length=1, byteorder="little", signed=True)
|
||||
|
||||
|
||||
def align_up(x: int, n: int) -> int:
|
||||
"""Return x aligned up to block size of n."""
|
||||
return int((x - 1) // n + 1) * n
|
||||
|
||||
|
||||
def align_down(x: int, n: int) -> int:
|
||||
"""Return 'x' aligned down to block size of 'n'."""
|
||||
return int(x // n) * n
|
||||
|
||||
|
||||
def pad_up(x: int, n: int) -> int:
|
||||
"""Return how many bytes of padding is needed to align 'x'
|
||||
up to block size of 'n'."""
|
||||
return n - (x % n)
|
||||
|
||||
|
||||
def pad_data(data: bytes, n: int, char: int) -> bytes:
|
||||
"""Add 'char'-filled padding to 'data' to align to a 'n'-sized block."""
|
||||
if len(data) % n == 0:
|
||||
return data
|
||||
return data + (bytes([char]) * pad_up(len(data), n))
|
||||
|
||||
|
||||
def uint8(val):
|
||||
"""Get only the least-significant 8 bits of the value."""
|
||||
return val & 0xFF
|
||||
|
||||
|
||||
def uint16(val):
|
||||
"""Get only the least-significant 16 bits of the value."""
|
||||
return val & 0xFFFF
|
||||
|
||||
|
||||
def uint32(val):
|
||||
"""Get only the least-significant 32 bits of the value."""
|
||||
return val & 0xFFFFFFFF
|
||||
|
||||
|
||||
def uintmax(bits: int) -> int:
|
||||
"""Get maximum integer size for given bit width."""
|
||||
return (2**bits) - 1
|
||||
|
||||
Reference in New Issue
Block a user