nx_robot_firmware_gate.nx source
↩ module page · 126 lines · 6172 B
1// nx_robot_firmware_gate.nx -- R-ROBO-4 GATE: MCU firmware generation + fail-safe behaviour.
2// Generates NishiLang firmware for a control board, writes the real .nx artifact, and VERIFIES:
3// (1) the emitted firmware contains the never-brick STRUCTURE (clamp + watchdog + safe-state + loop);
4// (2) it embeds the board SPEC (setpoint/umax/pins) verbatim;
5// (3) host-sim NORMAL run converges to setpoint (the generated control law works);
6// (4) NEVER-BRICK clamp: command never exceeds UMAX;
7// (5) FAULT -> SAFE-STATE: with a sensor-loss fault injected, the generated firmware does NOT run
8// away (commands safe, position stays bounded);
9// (6) NEGATIVE CONTROL: a NAIVE firmware (no safe-state) with the SAME fault DOES run away --
10// proving the generated safe-state is doing real work.
11// 100% sovereign, integer-only. license_tier: ORIGINAL expect_exit: 0
12import "nx_syscalls.nx"
13import "nx_robot_firmware.nx"
14
15func sw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
16func sn(v: i64) -> i64 {
17 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
18 var m: i64 = v
19 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
20 let d: *u8 = sys_mmap(24); var k: i64 = 0
21 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
22 let o: *u8 = sys_mmap(24); var i: i64 = 0
23 while i < k { o[i] = d[k - 1 - i]; i = i + 1 }
24 sys_write(1, o, k); return 0
25}
26func slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
27func contains(hay: *u8, haylen: i64, needle: *u8) -> i64 {
28 let nl: i64 = slen(needle)
29 if nl == 0 { return 1 }
30 var i: i64 = 0
31 while i + nl <= haylen {
32 var j: i64 = 0
33 var ok: i64 = 1
34 while j < nl { if hay[i + j] != needle[j] { ok = 0; j = nl } else { j = j + 1 } }
35 if ok == 1 { return 1 }
36 i = i + 1
37 }
38 return 0
39}
40func check(name: *u8, cond: i64, tot: *i64) -> i64 {
41 if cond == 1 { sw(" ok " as *u8); tot[0] = tot[0] + 1 }
42 else { sw(" FAIL " as *u8); tot[1] = tot[1] + 1 }
43 sw(name); sw("\n" as *u8)
44 return 0
45}
46func abs_i(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
47
48func main() -> i64 {
49 let tot: *i64 = sys_mmap(16) as *i64
50 tot[0] = 0; tot[1] = 0
51 sw("=== nx_robot_firmware_gate R-ROBO-4 -- MCU firmware generation + fail-safe (never-brick) ===\n" as *u8)
52
53 let setpoint: i64 = 1000
54 let kp: i64 = 200
55 let umax: i64 = 300
56 let wd: i64 = 1000
57 let pin_step: i64 = 17
58 let pin_sensor: i64 = 34
59
60 let cap: i64 = 65536
61 let out: *u8 = sys_mmap(cap)
62 let flen: i64 = firmware_emit(setpoint, kp, umax, wd, pin_step, pin_sensor, out)
63 sw(" generated firmware bytes=" as *u8); sn(flen); sw("\n" as *u8)
64 let fd: i64 = sys_openat_wr("knowledge/nx_fw_demo_robot.nx" as *u8, 0x1a4)
65 if fd >= 0 { sys_write(fd, out, flen); sys_close(fd); sw(" wrote knowledge/nx_fw_demo_robot.nx (generated Nishi firmware)\n" as *u8) }
66 else { sw(" (artifact write skipped)\n" as *u8) }
67
68 // (1) never-brick structure present
69 var okstruct: i64 = 1
70 if contains(out, flen, "func fw_clamp(" as *u8) == 0 { okstruct = 0 }
71 if contains(out, flen, "func fw_safe_state(" as *u8) == 0 { okstruct = 0 }
72 if contains(out, flen, "FW_WATCHDOG_TICKS" as *u8) == 0 { okstruct = 0 }
73 if contains(out, flen, "while 1 == 1" as *u8) == 0 { okstruct = 0 }
74 if contains(out, flen, "hw_drive_step(FW_PIN_STEP, 0)" as *u8) == 0 { okstruct = 0 }
75 if contains(out, flen, "import \"nx_syscalls.nx\"" as *u8) == 0 { okstruct = 0 }
76 check("emitted firmware has never-brick STRUCTURE (clamp+watchdog+safe-state+loop)" as *u8, okstruct, tot)
77
78 // (2) board spec embedded verbatim
79 var okspec: i64 = 1
80 if contains(out, flen, "FW_SETPOINT: i64 = 1000" as *u8) == 0 { okspec = 0 }
81 if contains(out, flen, "FW_UMAX: i64 = 300" as *u8) == 0 { okspec = 0 }
82 if contains(out, flen, "FW_PIN_STEP: i64 = 17" as *u8) == 0 { okspec = 0 }
83 if contains(out, flen, "FW_PIN_SENSOR: i64 = 34" as *u8) == 0 { okspec = 0 }
84 check("emitted firmware embeds the board SPEC (setpoint/umax/pins) verbatim" as *u8, okspec, tot)
85
86 let load: i64 = 3
87 let inertia: i64 = 4
88 let ticks: i64 = 200
89 let mc: *i64 = sys_mmap(8) as *i64
90 let ra: *i64 = sys_mmap(8) as *i64
91
92 // (3) normal run converges (no fault: fault_at = ticks)
93 let pn: i64 = fw_run(setpoint, kp, umax, load, inertia, ticks, ticks, 1, mc, ra)
94 sw(" NORMAL: final pos=" as *u8); sn(pn); sw(" maxcmd=" as *u8); sn(mc[0]); sw(" runaway=" as *u8); sn(ra[0]); sw("\n" as *u8)
95 var ok3: i64 = 0
96 if abs_i(setpoint - pn) <= 30 { ok3 = 1 }
97 check("generated control law CONVERGES to setpoint (normal operation)" as *u8, ok3, tot)
98
99 // (4) never-brick clamp
100 var ok4: i64 = 0
101 if mc[0] <= umax { ok4 = 1 }
102 check("NEVER-BRICK: command never exceeds UMAX" as *u8, ok4, tot)
103
104 // (5) fault -> safe-state: inject sensor loss at t=50; generated firmware must NOT run away
105 let mc2: *i64 = sys_mmap(8) as *i64
106 let ra2: *i64 = sys_mmap(8) as *i64
107 let pf: i64 = fw_run(setpoint, kp, umax, load, inertia, ticks, 50, 1, mc2, ra2)
108 sw(" FAULT+SAFE: final pos=" as *u8); sn(pf); sw(" runaway=" as *u8); sn(ra2[0]); sw(" (safe-state holds)\n" as *u8)
109 var ok5: i64 = 0
110 if ra2[0] == 0 { ok5 = 1 }
111 check("FAULT -> SAFE-STATE: generated firmware does NOT run away on sensor loss" as *u8, ok5, tot)
112
113 // (6) negative control: naive firmware (no safe-state) with the same fault runs away
114 let mc3: *i64 = sys_mmap(8) as *i64
115 let ra3: *i64 = sys_mmap(8) as *i64
116 let pb: i64 = fw_run(setpoint, kp, umax, load, inertia, ticks, 50, 0, mc3, ra3)
117 sw(" NAIVE+FAULT: final pos=" as *u8); sn(pb); sw(" runaway=" as *u8); sn(ra3[0]); sw(" (unsafe)\n" as *u8)
118 var ok6: i64 = 0
119 if ra3[0] == 1 { ok6 = 1 }
120 check("NEG-CONTROL: naive firmware (no safe-state) DOES run away (safe-state earns its keep)" as *u8, ok6, tot)
121
122 sw("=== VERDICT pass=" as *u8); sn(tot[0]); sw(" fail=" as *u8); sn(tot[1]); sw(" ===\n" as *u8)
123 if tot[1] == 0 { sys_exit(0) }
124 sys_exit(1)
125 return 1
126}