"""frame.py -- the USB-CDC wire protocol shared with OpenController/deck_input.cpp. frame = [0xA5][0x5A][type][len][payload(len)][sum8(type,len,payload...)] The reader resynchronizes on the 2-byte sync word, so any stray bytes (a boot banner, a serial monitor) are skipped harmlessly. Keep this file in lock-step with deck_input.{h,cpp}. """ import struct SYNC0 = 0xA5 SYNC1 = 0x5A # Deck -> nRF T_INPUT = 0x01 T_CONTROL = 0x02 T_REQ_STATUS = 0x03 # nRF -> Deck T_STATUS = 0x10 T_TEXT = 0x1F # INPUT payload: buttons u32, lx ly rx ry s16, lt rt u8, lpx lpy rpx rpy s16, ax ay az gx gy gz s16. # 4 + 8 + 2 + 8 + 12 = 34 bytes, little-endian. Matches applyInput() in deck_input.cpp. _INPUT = struct.Struct(" an INPUT frame.""" g = st.get if isinstance(st, dict) else (lambda k, d=0: getattr(st, k, d)) payload = _INPUT.pack( g("buttons", 0) & 0xFFFFFFFF, g("lx", 0), g("ly", 0), g("rx", 0), g("ry", 0), g("lt", 0) & 0xFF, g("rt", 0) & 0xFF, g("lpx", 0), g("lpy", 0), g("rpx", 0), g("rpy", 0), g("ax", 0), g("ay", 0), g("az", 0), g("gx", 0), g("gy", 0), g("gz", 0), ) return build(T_INPUT, payload) def build_set_forwarding(on): return build(T_CONTROL, bytes([0x01, 1 if on else 0])) def build_req_status(): return build(T_REQ_STATUS) def parse_status(payload): """Decode a T_STATUS payload into a dict. Mirrors deckStatusTask() in deck_input.cpp.""" if len(payload) < 4: return None flags, link_slot, sess_ch, nbond = payload[0], payload[1], payload[2], payload[3] bonds = [] off = 4 for _ in range(nbond): if off + 26 > len(payload): break used = payload[off] alive = payload[off + 1] puuid = struct.unpack_from(" 240: self._flush_text(out) elif st == 1: self._st = 2 if c == SYNC1 else (1 if c == SYNC0 else 0) elif st == 2: self._type = c self._sum = c self._st = 3 elif st == 3: self._len = c self._sum = (self._sum + c) & 0xFF self._buf = bytearray() self._st = 5 if c == 0 else 4 elif st == 4: self._buf.append(c) self._sum = (self._sum + c) & 0xFF if len(self._buf) >= self._len: self._st = 5 elif st == 5: if c == self._sum: out.append((self._type, bytes(self._buf))) self._st = 0 return out