Files
mywhoosh2garmin/tests/fit/builders.py
2026-08-15 10:49:13 +02:00

61 lines
2.1 KiB
Python

import struct
from app.fit.crc import fit_crc
def make_fit(data_records: bytes, *, header_size: int = 14) -> bytes:
if header_size not in {12, 14}:
raise ValueError(header_size)
header = bytearray(header_size)
header[0] = header_size
header[1] = 0x20
struct.pack_into("<H", header, 2, 0x0100)
struct.pack_into("<I", header, 4, len(data_records))
header[8:12] = b".FIT"
if header_size == 14:
struct.pack_into("<H", header, 12, fit_crc(header[:12]))
body = header + data_records
return bytes(body + struct.pack("<H", fit_crc(body)))
def definition(
local: int,
global_num: int,
fields: list[tuple[int, int, int]],
*,
endian: str = "<",
developer_fields: list[tuple[int, int, int]] | None = None,
) -> bytes:
"""Build a FIT definition message.
``developer_fields`` is an optional list of (field_num, size, developer_data_index)
triples. When provided (and non-empty), the record header's "has developer fields"
bit (0x20) is set and a developer field definition block is appended after the
native field definitions, per the FIT format.
"""
architecture = 1 if endian == ">" else 0
header_byte = 0x40 | local
if developer_fields:
header_byte |= 0x20
payload = bytearray([0, architecture])
payload.extend(struct.pack(f"{endian}H", global_num))
payload.append(len(fields))
for num, size, base_type in fields:
payload.extend(bytes([num, size, base_type]))
if developer_fields:
payload.append(len(developer_fields))
for num, size, dev_index in developer_fields:
payload.extend(bytes([num, size, dev_index]))
return bytes([header_byte]) + bytes(payload)
def data(local: int, payload: bytes) -> bytes:
return bytes([local]) + payload
def compressed_timestamp_data(local: int, time_offset: int, payload: bytes) -> bytes:
"""Build a compressed-timestamp data record header (bit 0x80 set, local message
type in bits 5-6, time offset in bits 0-4) followed by the record payload."""
header = 0x80 | ((local & 0x03) << 5) | (time_offset & 0x1F)
return bytes([header]) + payload