From 9b846970b8f0c0c4cc4b8384e97497ff4075fd6f Mon Sep 17 00:00:00 2001 From: Daniel Dybing Date: Sat, 7 Feb 2026 14:27:37 +0100 Subject: [PATCH] fix: Align CRC calculation with ETSI EN 300 706 standard --- src/teletext/models.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/teletext/models.py b/src/teletext/models.py index f896234..72ef6d8 100644 --- a/src/teletext/models.py +++ b/src/teletext/models.py @@ -78,11 +78,12 @@ class Page: def calculate_crc(self) -> int: """ Calculates the CRC-16 (CCITT) checksum for the page. - Covers Rows 0 to 23. - Row 0: Skips first 8 bytes (Header/Control). Uses bytes 8-39. - Rows 1-23: Uses all 40 bytes. - Data is 7-bit (stripped parity). - Initial value: 0 (ETSI EN 300 706 9.4.1.2). + According to ETSI EN 300 706 (Section 9.4.1.2 & Figure 13): + - Covers Row 0 columns 8-31 (Bytes 14-37 in packet, excluding header and clock). + - Covers Rows 1-25 columns 0-39 (Bytes 6-45 in packet). + - Total 1024 bytes (8192 bits). + - Data is 7-bit (stripped parity). + - Initial value: 0. """ crc = 0 poly = 0x1021 @@ -104,18 +105,27 @@ class Page: for p in self.packets: rows[p.row] = p - for r in range(24): # 0 to 23 + for r in range(26): # 0 to 25 + # Determine column range + if r == 0: + start_col, end_col = 8, 32 # Cols 8-31 (24 bytes) + else: + start_col, end_col = 0, 40 # Cols 0-39 (40 bytes) + if r in rows: data = rows[r].data - start_col = 8 if r == 0 else 0 + # Ensure data is long enough (should be 40) + d_len = len(data) - for i in range(start_col, 40): - byte_val = data[i] & 0x7F # Strip parity + for i in range(start_col, end_col): + if i < d_len: + byte_val = data[i] & 0x7F # Strip parity + else: + byte_val = 0x20 # Pad with space if short crc = update_crc(crc, byte_val) else: - # Missing row? Usually treated as spaces (0x20) - start_col = 8 if r == 0 else 0 - for i in range(start_col, 40): + # Missing row treated as spaces + for i in range(start_col, end_col): crc = update_crc(crc, 0x20) return crc