From 4599b2b71c6253a0d3b57ae5108fe92c9bb74b07 Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Sat, 15 Aug 2026 10:21:09 +0200 Subject: [PATCH] feat: add FIT CRC calculation --- app/fit/__init__.py | 0 app/fit/crc.py | 18 ++++++++++++++++++ tests/fit/__init__.py | 0 tests/fit/test_crc.py | 11 +++++++++++ 4 files changed, 29 insertions(+) create mode 100644 app/fit/__init__.py create mode 100644 app/fit/crc.py create mode 100644 tests/fit/__init__.py create mode 100644 tests/fit/test_crc.py diff --git a/app/fit/__init__.py b/app/fit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/fit/crc.py b/app/fit/crc.py new file mode 100644 index 0000000..6ababa3 --- /dev/null +++ b/app/fit/crc.py @@ -0,0 +1,18 @@ +CRC_TABLE = ( + 0x0000, 0xCC01, 0xD801, 0x1400, + 0xF001, 0x3C00, 0x2800, 0xE401, + 0xA001, 0x6C00, 0x7800, 0xB401, + 0x5000, 0x9C01, 0x8801, 0x4400, +) + + +def fit_crc(data: bytes | bytearray | memoryview) -> int: + crc = 0 + for byte in data: + tmp = CRC_TABLE[crc & 0xF] + crc = (crc >> 4) & 0x0FFF + crc ^= tmp ^ CRC_TABLE[byte & 0xF] + tmp = CRC_TABLE[crc & 0xF] + crc = (crc >> 4) & 0x0FFF + crc ^= tmp ^ CRC_TABLE[(byte >> 4) & 0xF] + return crc & 0xFFFF diff --git a/tests/fit/__init__.py b/tests/fit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/fit/test_crc.py b/tests/fit/test_crc.py new file mode 100644 index 0000000..dd77d20 --- /dev/null +++ b/tests/fit/test_crc.py @@ -0,0 +1,11 @@ +from app.fit.crc import fit_crc + + +def test_empty_crc_is_zero() -> None: + assert fit_crc(b"") == 0 + + +def test_crc_is_incremental_equivalent() -> None: + payload = b".FIT-device-metadata" + assert fit_crc(payload) == fit_crc(memoryview(payload)) + assert 0 <= fit_crc(payload) <= 0xFFFF