#!/usr/bin/env python3 """Build Berger/JBD BLE frames observed in the Android app.""" from __future__ import annotations import argparse def checksum(command: int, payload: bytes = b"") -> int: """JBD two's-complement checksum over command, length, and payload.""" total = (command + len(payload) + sum(payload)) & 0xFFFF return ((total ^ 0xFFFF) + 1) & 0xFFFF def frame(mode: int, command: int, payload: bytes = b"") -> bytes: check = checksum(command, payload) return bytes([0xDD, mode, command, len(payload), *payload, check >> 8, check & 0xFF, 0x77]) def read_frame(command: int) -> bytes: return frame(0xA5, command) def write_frame(command: int, payload: bytes) -> bytes: return frame(0x5A, command, payload) def name_frame(command: int, payload: bytes = b"") -> bytes: check = (command + len(payload) + sum(payload)) & 0xFF return bytes([0xFF, 0xAA, command, len(payload), *payload, check]) def parse_hex_bytes(value: str) -> bytes: clean = value.replace(" ", "").replace(":", "") return bytes.fromhex(clean) def main() -> None: parser = argparse.ArgumentParser() sub = parser.add_subparsers(dest="cmd", required=True) p_read = sub.add_parser("read") p_read.add_argument("command", type=lambda x: int(x, 0)) p_write = sub.add_parser("write") p_write.add_argument("command", type=lambda x: int(x, 0)) p_write.add_argument("payload_hex", nargs="?", default="") p_name = sub.add_parser("name") p_name.add_argument("value") args = parser.parse_args() if args.cmd == "read": print(read_frame(args.command).hex().upper()) elif args.cmd == "write": print(write_frame(args.command, parse_hex_bytes(args.payload_hex)).hex().upper()) elif args.cmd == "name": print(name_frame(0x07, args.value.encode("ascii")).hex().upper()) if __name__ == "__main__": main()