nx_iot_local_magic_home_test.nx source
↩ module page · 267 lines · 10400 B
1// nx_iot_local_magic_home_test.nx -- end-to-end smoke for the
2// Magic Home / Flux LED kind generator.
3//
4// Coverage:
5// - sealed-enum verdict validity gate (full enum)
6// - checksum: sum-mod-256 reference values
7// - frame builders: power on / off / RGBW persist / RGBW transient /
8// RGB-only / warm-white / query / preset. Each verifies byte
9// layout + checksum.
10// - discovery payload + reply parse (well-formed + malformed)
11// - status parser: v9 (14 bytes) + v10 (16 bytes) + bad sentinel
12// + bad checksum + bad length
13//
14// expect_exit: 0
15//
16// license_tier: ORIGINAL
17
18import "nx_syscalls_x86_64.nx"
19import "nx_iot_local_magic_home.nx"
20
21func main() -> i64 {
22 // ---- Verdict gate ----------------------------------------------
23 if nx_iot_mh_verdict_is_valid(NX_IOT_MH_VERDICT_UNKNOWN) != 1 { return 1 }
24 if nx_iot_mh_verdict_is_valid(NX_IOT_MH_VERDICT_OK) != 1 { return 2 }
25 if nx_iot_mh_verdict_is_valid(NX_IOT_MH_VERDICT_BAD_LEN) != 1 { return 3 }
26 if nx_iot_mh_verdict_is_valid(NX_IOT_MH_VERDICT_BAD_SENTINEL) != 1 { return 4 }
27 if nx_iot_mh_verdict_is_valid(NX_IOT_MH_VERDICT_BAD_CHECKSUM) != 1 { return 5 }
28 if nx_iot_mh_verdict_is_valid(NX_IOT_MH_VERDICT_BUF_TOO_SMALL) != 1 { return 6 }
29 if nx_iot_mh_verdict_is_valid(NX_IOT_MH_VERDICT_BAD_ARG) != 1 { return 7 }
30 if nx_iot_mh_verdict_is_valid(NX_IOT_MH_VERDICT_N) != 0 { return 8 }
31
32 // ---- Checksum reference values --------------------------------
33 let buf: *u8 = sys_mmap(16)
34 // All zeros: sum = 0
35 var i: i64 = 0
36 while i < 16 { buf[i] = 0; i = i + 1 }
37 if nx_iot_mh_checksum(buf, 16) != 0 { return 10 }
38
39 // 1 + 2 + 3 = 6
40 buf[0] = 1; buf[1] = 2; buf[2] = 3
41 if nx_iot_mh_checksum(buf, 3) != 6 { return 11 }
42
43 // 0xFF + 0x02 = 0x101 -> 0x01 (mod 256)
44 buf[0] = 0xFF; buf[1] = 0x02
45 if nx_iot_mh_checksum(buf, 2) != 0x01 { return 12 }
46
47 // ---- Power ON --------------------------------------------------
48 let f: *u8 = sys_mmap(32)
49 let pn: i64 = nx_iot_mh_build_power(f, 32, 1)
50 if pn != 4 { return 20 }
51 if f[0] != 0x71 { return 21 }
52 if f[1] != 0x23 { return 22 }
53 if f[2] != 0x0F { return 23 }
54 // checksum = 0x71 + 0x23 + 0x0F = 0xA3
55 if f[3] != 0xA3 { return 24 }
56
57 // ---- Power OFF -------------------------------------------------
58 let po: i64 = nx_iot_mh_build_power(f, 32, 0)
59 if po != 4 { return 25 }
60 if f[1] != 0x24 { return 26 }
61 if f[3] != 0xA4 { return 27 } // 0x71 + 0x24 + 0x0F = 0xA4
62
63 // ---- Set RGBW persist -----------------------------------------
64 let rn: i64 = nx_iot_mh_build_rgbw(f, 32, 100, 200, 50, 80, 1)
65 if rn != 8 { return 30 }
66 if f[0] != 0x31 { return 31 }
67 if f[1] != 100 { return 32 }
68 if f[2] != 200 { return 33 }
69 if f[3] != 50 { return 34 }
70 if f[4] != 80 { return 35 }
71 if f[5] != 0xF0 { return 36 }
72 if f[6] != 0x0F { return 37 }
73 // checksum = 0x31 + 100 + 200 + 50 + 80 + 0xF0 + 0x0F = 734 = 0x2DE -> 0xDE
74 if f[7] != 0xDE { return 38 }
75
76 // ---- Set RGBW transient (persist=0) ---------------------------
77 let rt: i64 = nx_iot_mh_build_rgbw(f, 32, 100, 200, 50, 80, 0)
78 if rt != 8 { return 40 }
79 if f[6] != 0x00 { return 41 }
80 // checksum differs since byte 6 changes 0x0F -> 0x00
81 // sum - 0x0F = 734 - 15 = 719 = 0x2CF -> 0xCF
82 if f[7] != 0xCF { return 42 }
83
84 // ---- RGB only --------------------------------------------------
85 let rg: i64 = nx_iot_mh_build_rgb(f, 32, 255, 128, 64)
86 if rg != 8 { return 50 }
87 if f[1] != 255 { return 51 }
88 if f[2] != 128 { return 52 }
89 if f[3] != 64 { return 53 }
90 if f[4] != 0 { return 54 }
91
92 // ---- Warm-white only ------------------------------------------
93 let ww: i64 = nx_iot_mh_build_warm_white(f, 32, 200)
94 if ww != 8 { return 60 }
95 if f[0] != 0x31 { return 61 }
96 if f[1] != 0 { return 62 }
97 if f[2] != 0 { return 63 }
98 if f[3] != 0 { return 64 }
99 if f[4] != 200 { return 65 }
100 if f[5] != 0x0F { return 66 }
101
102 // ---- Query -----------------------------------------------------
103 let qn: i64 = nx_iot_mh_build_query(f, 32)
104 if qn != 4 { return 70 }
105 if f[0] != 0x81 { return 71 }
106 if f[1] != 0x8A { return 72 }
107 if f[2] != 0x8B { return 73 }
108 // checksum = 0x81 + 0x8A + 0x8B = 0x196 -> 0x96
109 if f[3] != 0x96 { return 74 }
110
111 // ---- Preset ---------------------------------------------------
112 let pr: i64 = nx_iot_mh_build_preset(f, 32, 0x25, 0x10)
113 if pr != 5 { return 80 }
114 if f[0] != 0x61 { return 81 }
115 if f[1] != 0x25 { return 82 }
116 if f[2] != 0x10 { return 83 }
117 if f[3] != 0x0F { return 84 }
118 // checksum = 0x61 + 0x25 + 0x10 + 0x0F = 0xA5
119 if f[4] != 0xA5 { return 85 }
120
121 // ---- Cap underflow -------------------------------------------
122 let small: *u8 = sys_mmap(4)
123 if nx_iot_mh_build_rgbw(small, 4, 0, 0, 0, 0, 0) != -1 { return 90 }
124 if nx_iot_mh_build_warm_white(small, 4, 0) != -1 { return 91 }
125 if nx_iot_mh_build_preset(small, 4, 0, 0) != -1 { return 92 }
126
127 // ---- Discovery payload ----------------------------------------
128 let d: *u8 = sys_mmap(32)
129 let dn: i64 = nx_iot_mh_build_discovery(d, 32)
130 if dn != 17 { return 100 }
131 if d[0] != 0x48 { return 101 } // H
132 if d[16] != 0x44 { return 102 } // D
133
134 // ---- Discovery reply parse ------------------------------------
135 // Build "192.168.1.10,B4E62D000001,AK001-ZJ200" inline.
136 let r: *u8 = sys_mmap(64)
137 r[0]=0x31; r[1]=0x39; r[2]=0x32; r[3]=0x2E; r[4]=0x31; r[5]=0x36
138 r[6]=0x38; r[7]=0x2E; r[8]=0x31; r[9]=0x2E; r[10]=0x31; r[11]=0x30
139 r[12]=0x2C // ,
140 r[13]=0x42; r[14]=0x34; r[15]=0x45; r[16]=0x36; r[17]=0x32; r[18]=0x44
141 r[19]=0x30; r[20]=0x30; r[21]=0x30; r[22]=0x30; r[23]=0x30; r[24]=0x31
142 r[25]=0x2C // ,
143 r[26]=0x41; r[27]=0x4B; r[28]=0x30; r[29]=0x30; r[30]=0x31
144 let r_len: i64 = 31
145
146 let c1_ptr: *i64 = sys_mmap(8) as *i64
147 let c2_ptr: *i64 = sys_mmap(8) as *i64
148 let dv: *i64 = sys_mmap(8) as *i64
149 let dr: i64 = nx_iot_mh_parse_discovery_reply(r, r_len, c1_ptr, c2_ptr, dv)
150 if dr != 0 { return 110 }
151 if dv[0] != NX_IOT_MH_VERDICT_OK { return 111 }
152 if c1_ptr[0] != 12 { return 112 }
153 if c2_ptr[0] != 25 { return 113 }
154
155 // Malformed (no commas)
156 let bad: *u8 = sys_mmap(16)
157 bad[0]=0x41; bad[1]=0x42; bad[2]=0x43; bad[3]=0x44; bad[4]=0x45
158 let bdr: i64 = nx_iot_mh_parse_discovery_reply(bad, 5, c1_ptr, c2_ptr, dv)
159 if bdr != -1 { return 114 }
160 if dv[0] != NX_IOT_MH_VERDICT_BAD_SENTINEL { return 115 }
161
162 // Too short
163 let sdr: i64 = nx_iot_mh_parse_discovery_reply(bad, 3, c1_ptr, c2_ptr, dv)
164 if sdr != -1 { return 116 }
165 if dv[0] != NX_IOT_MH_VERDICT_BAD_LEN { return 117 }
166
167 // ---- Status parser: v9 (14 bytes) ON RGB(100,200,50) ----------
168 let s: *u8 = sys_mmap(32)
169 s[0] = 0x81 // sentinel
170 s[1] = 0x33 // model
171 s[2] = 0x23 // power ON
172 s[3] = 0x61 // mode custom RGB
173 s[4] = 0x10 // speed
174 s[5] = 100 // R
175 s[6] = 200 // G
176 s[7] = 50 // B
177 s[8] = 80 // ww
178 s[9] = 0x04
179 s[10] = 0x00
180 s[11] = 0x0F
181 s[12] = 0
182 // checksum at s[13] = sum of bytes 0..12 mod 256
183 var ss: i64 = 0
184 var k: i64 = 0
185 while k < 13 { ss = ss + ((s[k] as i64) & 0xff); k = k + 1 }
186 s[13] = ss & 0xff
187
188 let st: *IotMhStatus = sys_mmap(80) as *IotMhStatus
189 let sv: *i64 = sys_mmap(8) as *i64
190 let psr: i64 = nx_iot_mh_parse_status(s, 14, st, sv)
191 if psr != 0 { return 120 }
192 if sv[0] != NX_IOT_MH_VERDICT_OK { return 121 }
193 if st.power != NX_IOT_MH_POWER_ON { return 122 }
194 if st.mode != 0x61 { return 123 }
195 if st.speed != 0x10 { return 124 }
196 if st.r != 100 { return 125 }
197 if st.g != 200 { return 126 }
198 if st.b != 50 { return 127 }
199 if st.ww != 80 { return 128 }
200 if st.cw != 0 { return 129 }
201 if st.is_v10 != 0 { return 130 }
202
203 // ---- Status v10 (16 bytes) with cool-white ---------------------
204 let s10: *u8 = sys_mmap(32)
205 k = 0
206 while k < 13 { s10[k] = s[k]; k = k + 1 }
207 s10[10] = 150 // cool-white
208 s10[11] = 0x0F
209 s10[12] = 0
210 s10[13] = 0
211 s10[14] = 0
212 // checksum over [0..15)
213 var ss2: i64 = 0
214 k = 0
215 while k < 15 { ss2 = ss2 + ((s10[k] as i64) & 0xff); k = k + 1 }
216 s10[15] = ss2 & 0xff
217
218 let st10: *IotMhStatus = sys_mmap(80) as *IotMhStatus
219 let psr10: i64 = nx_iot_mh_parse_status(s10, 16, st10, sv)
220 if psr10 != 0 { return 140 }
221 if sv[0] != NX_IOT_MH_VERDICT_OK { return 141 }
222 if st10.cw != 150 { return 142 }
223 if st10.is_v10 != 1 { return 143 }
224
225 // ---- Status: bad length ----------------------------------------
226 let bl: i64 = nx_iot_mh_parse_status(s, 10, st, sv)
227 if bl != -1 { return 150 }
228 if sv[0] != NX_IOT_MH_VERDICT_BAD_LEN { return 151 }
229
230 // ---- Status: bad sentinel --------------------------------------
231 let sb: *u8 = sys_mmap(32)
232 k = 0
233 while k < 14 { sb[k] = s[k]; k = k + 1 }
234 sb[0] = 0xFF
235 // recompute checksum so we isolate the sentinel failure
236 var ss3: i64 = 0
237 k = 0
238 while k < 13 { ss3 = ss3 + ((sb[k] as i64) & 0xff); k = k + 1 }
239 sb[13] = ss3 & 0xff
240 let bsr: i64 = nx_iot_mh_parse_status(sb, 14, st, sv)
241 if bsr != -1 { return 160 }
242 if sv[0] != NX_IOT_MH_VERDICT_BAD_SENTINEL { return 161 }
243
244 // ---- Status: bad checksum --------------------------------------
245 let bc: *u8 = sys_mmap(32)
246 k = 0
247 while k < 14 { bc[k] = s[k]; k = k + 1 }
248 bc[13] = bc[13] ^ 0xFF // corrupt
249 let bcr: i64 = nx_iot_mh_parse_status(bc, 14, st, sv)
250 if bcr != -1 { return 170 }
251 if sv[0] != NX_IOT_MH_VERDICT_BAD_CHECKSUM { return 171 }
252
253 // ---- Power OFF in status ---------------------------------------
254 let sf: *u8 = sys_mmap(32)
255 k = 0
256 while k < 14 { sf[k] = s[k]; k = k + 1 }
257 sf[2] = NX_IOT_MH_POWER_BYTE_OFF
258 var ss4: i64 = 0
259 k = 0
260 while k < 13 { ss4 = ss4 + ((sf[k] as i64) & 0xff); k = k + 1 }
261 sf[13] = ss4 & 0xff
262 let off_r: i64 = nx_iot_mh_parse_status(sf, 14, st, sv)
263 if off_r != 0 { return 180 }
264 if st.power != NX_IOT_MH_POWER_OFF { return 181 }
265
266 return 0
267}