code wiki / (root) / nx_iot_local_magic_home_test.nx

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}