Document BullTron BLE commands
This commit is contained in:
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build BullTron/Daly-style BLE frames observed in the Android app."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
def crc16_modbus_swapped(hex_data: str) -> str:
|
||||
data = bytes.fromhex(hex_data)
|
||||
crc = 0xFFFF
|
||||
for byte in data:
|
||||
crc ^= byte
|
||||
for _ in range(8):
|
||||
if crc & 1:
|
||||
crc = (crc >> 1) ^ 0xA001
|
||||
else:
|
||||
crc >>= 1
|
||||
swapped = ((crc & 0xFF00) >> 8) | ((crc & 0x00FF) << 8)
|
||||
return f"{swapped:04X}"
|
||||
|
||||
|
||||
def read_frame(start: int, count: int) -> str:
|
||||
body = f"D203{start:04X}{count:04X}"
|
||||
return body + crc16_modbus_swapped(body)
|
||||
|
||||
|
||||
def write_single_frame(register: int, value: int) -> str:
|
||||
body = f"D206{register:04X}{value:04X}"
|
||||
return body + crc16_modbus_swapped(body)
|
||||
|
||||
|
||||
def write_multi_frame(start: int, count: int, payload_hex: str) -> str:
|
||||
payload = payload_hex.replace(" ", "").upper()
|
||||
body = f"D210{start:04X}{count:04X}{payload}"
|
||||
return body + crc16_modbus_swapped(body)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
|
||||
p_read = sub.add_parser("read")
|
||||
p_read.add_argument("start", type=lambda x: int(x, 0))
|
||||
p_read.add_argument("count", type=lambda x: int(x, 0))
|
||||
|
||||
p_write = sub.add_parser("write")
|
||||
p_write.add_argument("register", type=lambda x: int(x, 0))
|
||||
p_write.add_argument("value", type=lambda x: int(x, 0))
|
||||
|
||||
p_multi = sub.add_parser("write-multi")
|
||||
p_multi.add_argument("start", type=lambda x: int(x, 0))
|
||||
p_multi.add_argument("count", type=lambda x: int(x, 0))
|
||||
p_multi.add_argument("payload_hex")
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.cmd == "read":
|
||||
print(read_frame(args.start, args.count))
|
||||
elif args.cmd == "write":
|
||||
print(write_single_frame(args.register, args.value))
|
||||
elif args.cmd == "write-multi":
|
||||
print(write_multi_frame(args.start, args.count, args.payload_hex))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user