feat(framing): class for header with hamming(7,4)
This commit is contained in:
65
header.py
Normal file
65
header.py
Normal file
@@ -0,0 +1,65 @@
|
||||
from hamming_8_4_codec import hamming_8_4_encode, hamming_8_4_decode
|
||||
from crc import Configuration, Crc16
|
||||
PROTOCOL_IDENTIFIER = 0x0
|
||||
# CRC_POLY = (0xed2f << 1) + 1 # from https://users.ece.cmu.edu/~koopman/crc/index.html as "best 16-bit CRC" on 2025-10-24
|
||||
ONBEAT_CRC = Configuration(Crc16.IBM_3740)
|
||||
|
||||
|
||||
class Onbeat_Header:
|
||||
"""This class represents a header for a single packet of PLSTV."""
|
||||
|
||||
def __init__(self, protocol_id, protocol_configuration: int, callsign: str, pkt_len: int, pkt_sequence_id: int):
|
||||
if protocol_id >= 2 << 4:
|
||||
raise OverflowError(
|
||||
f"protocol identifier should be confined to 4 bits, got {protocol_id}")
|
||||
self.protocol_id = protocol_id
|
||||
|
||||
if protocol_configuration >= 2 << 4:
|
||||
raise OverflowError(
|
||||
f"protocol configuration should be confined to 4 bits, got {protocol_configuration}")
|
||||
self.protocol_configuration = protocol_configuration
|
||||
|
||||
call_len = len(callsign.encode())
|
||||
if call_len >= 10:
|
||||
raise OverflowError(
|
||||
f"Callsign must be confined to 10 bytes, got {callsign} with length {call_len} (using UTF-8)")
|
||||
self.callsign = callsign
|
||||
|
||||
if pkt_len >= 2 << 16:
|
||||
raise OverflowError(
|
||||
f"Maximum allowed packet size is {2 << 16 - 1} got {pkt_len}")
|
||||
self.pkt_len = pkt_len
|
||||
|
||||
if pkt_sequence_id >= 2 << 8:
|
||||
raise OverflowError(
|
||||
f"Packet sequence ID must be confined to 8 bits, got {pkt_sequence_id}")
|
||||
self.pkt_sequence_id = pkt_sequence_id
|
||||
|
||||
def encode(self) -> list[int]:
|
||||
header_asints = []
|
||||
header_asints += [(PROTOCOL_IDENTIFIER << 4) +
|
||||
self.protocol_configuration]
|
||||
header_asints += [(int.from_bytes(self.callsign.encode())
|
||||
>> 8*i) % 2 << 8 for i in range(0, 10)]
|
||||
header_asints += [(self.pkt_len >> 8), self.pkt_len % 2 << 8]
|
||||
header_asints += [self.pkt_sequence_id]
|
||||
header_crc = ONBEAT_CRC.checksum(bytes(header_asints))
|
||||
header_asints += [header_crc]
|
||||
return hamming_8_4_encode(header_asints)
|
||||
|
||||
def decode(self, header_encoded: list[int]):
|
||||
header_corrected = hamming_8_4_decode(header_encoded)
|
||||
checksum = ONBEAT_CRC.checksum(
|
||||
bytes(header_corrected[14] << 8 + header_corrected[15]))
|
||||
if checksum != 0:
|
||||
raise ValueError(
|
||||
"Checksum of header is non-zero, packet is invalid")
|
||||
self.protocol_id = header_corrected[0] >> 4
|
||||
self.protocol_configuration = header_corrected[0] % 16
|
||||
callsign_numeric = 0
|
||||
for i in range(1, 11):
|
||||
callsign_numeric += header_corrected[i]
|
||||
callsign_numeric <<= 8
|
||||
self.callsign = int.to_bytes(callsign_numeric, byteorder="big").decode()
|
||||
self.pkt_len = header_corrected[11] << 8 + header_corrected[12]
|
||||
self.pkt_sequence_id = header_corrected[13]
|
||||
Reference in New Issue
Block a user