nx_iot_local_tuya_v33.nx
buildroot/runtime/nx_iot_local_tuya_v33.nx
about
nx_iot_local_tuya_v33.nx -- Tuya v3.3 LAN wire-frame primitive.
Roadmap: nxc2/docs/NISHI_IOT_HUB_ROADMAP.md Epoch 2 (SPEAK).
Kind generator (per cardinal `feedback-kind-specific-generators-
not-broad-noise`): one primitive per vendor protocol family. This
file owns the Tuya v3.3 envelope only. Magic Home / WiZ / Yeelight
each get their own kind generator.
Wire format (Tuya v3.3, observed via tinytuya / tuyapi public
protocol notes -- INDEPENDENT_REDERIVE route per the catalog entry
in nishi-library/seeds/iot-hub-research.toml):
offset size field
------ ---- -----------------------------------------------
0 4 HEAD sentinel 0x00 0x00 0x55 0xAA (BE)
4 4 Sequence number (BE u32)
8 4 Command (BE u32; 7=CONTROL, 10=STATUS,
13=DP_QUERY, 0=BCAST, ...)
12 4 Payload length (BE u32; counts payload bytes
PLUS the trailing CRC+TAIL = 8)
16 N Payload (caller-supplied; for real
sessions this is AES-128-ECB
over PKCS7-padded JSON. The
AES layer composes against
nx_aes.nx and is the next slice;
this primitive is payload-agnostic)
16+N 4 CRC32 (BE; over offsets 0..16+N-1
with poly 0xEDB88320,
init 0xFFFFFFFF, xorout 0xFFFFFFFF)
16+N+4 4 TAIL sentinel 0x00 0x00 0xAA 0x55 (BE)
Total frame size = 16 + N + 8 = N + 24 bytes.
What this primitive does today:
- CRC32 with the standard zlib polynomial (KAT against the
canonical "123456789" -> 0xCBF43926 vector)
- frame encode: header + seq + cmd + len + payload + crc + tail
- frame decode: validate sentinels + length + CRC, return cmd/seq
dependencies 0 imports · 1 importers
imports: none
imported by: nx_iot_local_tuya_v33_test.nx
structs
| none |
consts
| 106 | const NX_TUYA_HEAD_B0: i64 = 0x00 |
| 107 | const NX_TUYA_HEAD_B1: i64 = 0x00 |
| 108 | const NX_TUYA_HEAD_B2: i64 = 0x55 |
| 109 | const NX_TUYA_HEAD_B3: i64 = 0xAA |
| 110 | const NX_TUYA_TAIL_B0: i64 = 0x00 |
| 111 | const NX_TUYA_TAIL_B1: i64 = 0x00 |
| 112 | const NX_TUYA_TAIL_B2: i64 = 0xAA |
| 113 | const NX_TUYA_TAIL_B3: i64 = 0x55 |
| 115 | const NX_TUYA_OVERHEAD: i64 = 24 // header(4)+seq(4)+cmd(4)+len(4)+crc(4)+tail(4) |
| 116 | const NX_TUYA_PREFIX_LEN: i64 = 16 // header+seq+cmd+len |
| 117 | const NX_TUYA_SUFFIX_LEN: i64 = 8 // crc+tail |
| 121 | const NX_TUYA_CMD_BCAST: i64 = 0 // broadcast announce |
| 122 | const NX_TUYA_CMD_CONTROL: i64 = 7 // set DPS |
| 123 | const NX_TUYA_CMD_STATUS: i64 = 10 // device status push |
| 124 | const NX_TUYA_CMD_HEARTBEAT: i64 = 9 // keep-alive |
| 125 | const NX_TUYA_CMD_DP_QUERY: i64 = 13 // query DPS |
| 126 | const NX_TUYA_CMD_PREFIX_31: i64 = 31 // 3.3 with 3.4 prefix |
| 130 | const NX_TUYA_DECODE_UNKNOWN: i64 = 0 |
| 131 | const NX_TUYA_DECODE_OK: i64 = 1 |
| 132 | const NX_TUYA_DECODE_BAD_HEADER: i64 = 2 |
| 133 | const NX_TUYA_DECODE_BAD_TAIL: i64 = 3 |
| 134 | const NX_TUYA_DECODE_BAD_CRC: i64 = 4 |
| 135 | const NX_TUYA_DECODE_BAD_LEN: i64 = 5 |
| 136 | const NX_TUYA_DECODE_BUF_TOO_SMALL: i64 = 6 |
| 137 | const NX_TUYA_DECODE_N: i64 = 7 |
functions
| 139 | func nx_tuya_decode_verdict_is_valid(v: i64) -> i64 called by 1: main |
| 147 | func nx_tuya_write_be32(buf: *u8, off: i64, v: i64) -> i64 |
| 155 | func nx_tuya_read_be32(buf: *u8, off: i64) -> i64 |
| 175 | func nx_tuya_crc32(buf: *u8, len: i64) -> i64 |
| 202 | func nx_tuya_frame_encode(cmd: i64, seq: i64, |
| 246 | func nx_tuya_frame_decode(buf: *u8, n: i64, |