cart_firmware_added
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Decode a captured frame as SBUS: UART 100 kbit/s 8E2, 25-byte frame,
|
||||
16 channels x 11 bits.
|
||||
|
||||
Usage: .venv/bin/python tools/decode.py captures/<name>.npz
|
||||
"""
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
BIT_US = 10.0
|
||||
|
||||
path = sys.argv[1]
|
||||
d = np.load(path)
|
||||
volts = d["volts"]
|
||||
srate = float(d["srate"])
|
||||
dt_us = 1e6 / srate
|
||||
|
||||
# idle level dominates the record; UART logic 1 == idle regardless of
|
||||
# physical polarity (this line is standard inverted SBUS: idle low)
|
||||
idle = np.median(volts)
|
||||
p10, p90 = np.percentile(volts, [10, 90])
|
||||
active = p10 if abs(p10 - idle) > abs(p90 - idle) else p90
|
||||
thr = (idle + active) / 2
|
||||
if active > idle:
|
||||
sig = (volts < thr).astype(np.int8) # pulses up -> logic 0
|
||||
else:
|
||||
sig = (volts > thr).astype(np.int8)
|
||||
|
||||
edges = np.flatnonzero(np.diff(sig)) + 1
|
||||
starts = np.concatenate(([0], edges))
|
||||
ends = np.concatenate((edges, [len(sig)]))
|
||||
levels = sig[starts]
|
||||
dur_us = (ends - starts) * dt_us
|
||||
|
||||
stream = []
|
||||
for lv, du in zip(levels[1:-1], dur_us[1:-1]):
|
||||
stream.extend([int(lv)] * max(1, round(du / BIT_US)))
|
||||
# trailing idle of last stop bits is trimmed by run cut; pad with idle-high
|
||||
stream.extend([1] * 24)
|
||||
|
||||
# deframe 8E2: start=0, 8 data LSB-first, even parity, 2 stop=1
|
||||
i = 0
|
||||
frames = []
|
||||
errors = []
|
||||
while i + 12 <= len(stream):
|
||||
if stream[i] == 1:
|
||||
i += 1
|
||||
continue
|
||||
data = stream[i + 1 : i + 9]
|
||||
par = stream[i + 9]
|
||||
stops = stream[i + 10 : i + 12]
|
||||
byte = sum(b << k for k, b in enumerate(data))
|
||||
if par != (sum(data) & 1):
|
||||
errors.append((len(frames), "parity"))
|
||||
if stops != [1, 1]:
|
||||
errors.append((len(frames), f"stop={stops}"))
|
||||
frames.append(byte)
|
||||
i += 12
|
||||
|
||||
print(f"decoded {len(frames)} bytes, errors: {errors if errors else 'none'}")
|
||||
print("hex:", " ".join(f"{b:02X}" for b in frames))
|
||||
|
||||
if len(frames) >= 25 and frames[0] == 0x0F:
|
||||
payload = frames[1:23]
|
||||
flags = frames[23]
|
||||
footer = frames[24]
|
||||
bits = 0
|
||||
for k, b in enumerate(payload):
|
||||
bits |= b << (8 * k)
|
||||
ch = [(bits >> (11 * n)) & 0x7FF for n in range(16)]
|
||||
print("\nSBUS frame OK" if footer == 0x00 else f"\nfooter unexpected: {footer:02X}")
|
||||
print("channels:", ch)
|
||||
print(f"flags: 0x{flags:02X} (bit0=ch17 bit1=ch18 bit2=frame_lost bit3=failsafe)")
|
||||
else:
|
||||
print("not a valid SBUS frame (no 0x0F header)")
|
||||
Reference in New Issue
Block a user