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(" 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