code wiki / (root) / nx_robot_hal.nx

nx_robot_hal.nx source

↩ module page · 78 lines · 3747 B

1// nx_robot_hal.nx -- SOVEREIGN fail-safe hardware-write DRIVER (the HAL the generated firmware binds 2// to). This is the never-brick-critical rung (#26): the layer that actually writes actuator outputs 3// and reads sensors. NEVER-BRICK BY CONSTRUCTION + proven MECHANICALLY by the gate (not promised): 4// * every actuator write is CLAMPED to a safe envelope [HW_SAFE_MIN, HW_SAFE_MAX] before it lands 5// -- no command, however large/negative/malicious, can escape it (defense-in-depth even if the 6// firmware's own clamp were wrong); 7// * pins default to SAFE (0 / disabled) on init; 8// * a WATCHDOG forces an e-stop (all outputs safe) if not kicked; 9// * E-STOP is latched and zeroes every output; 10// * sensor readings are range-checked (out-of-range => invalid => firmware goes safe). 11// Backend here is a MOCK device (an i64 register array) so the whole chain is gate-provable WITHOUT 12// real hardware. HONEST: binding these to a real board's MMIO addresses (the actual GPIO/PWM/step 13// registers) is the final step and needs the bench -- but the fail-safe LOGIC is real + proven now. 14// State layout (i64 array hw): hw[0..HW_NP) = actual pin outputs; hw[HW_NP+p] = sensor[p]; 15// hw[2*HW_NP] = watchdog counter; hw[2*HW_NP+1] = estop latch. 16// license_tier: ORIGINAL expect_exit: 0 17import "nx_syscalls.nx" 18 19const HW_NP: i64 = 32 20const HW_SAFE_MAX: i64 = 400 // actuator output ceiling (e.g. step-rate / current cap) 21const HW_SAFE_MIN: i64 = 0 - 400 22const HW_SENSOR_MIN: i64 = 0 23const HW_SENSOR_MAX: i64 = 4095 // 12-bit ADC 24const HW_WD_LIMIT: i64 = 100 // watchdog ticks before auto e-stop 25 26// allocate + safe-default a mock device (all outputs 0, estop clear, wd 0) 27func hwd_new() -> *i64 { 28 let hw: *i64 = sys_mmap((2 * HW_NP + 2) * 8) as *i64 29 var i: i64 = 0 30 while i < 2 * HW_NP + 2 { hw[i] = 0; i = i + 1 } 31 return hw 32} 33 34func hwd_init_pin(hw: *i64, pin: i64) -> i64 { hw[pin] = 0; return 0 } // safe default 35 36// latched e-stop: set the flag AND force every output to safe (0) 37func hwd_estop(hw: *i64) -> i64 { 38 hw[2 * HW_NP + 1] = 1 39 var p: i64 = 0 40 while p < HW_NP { hw[p] = 0; p = p + 1 } 41 return 0 42} 43 44// FAIL-SAFE actuator write: honor e-stop, then CLAMP to the safe envelope BY CONSTRUCTION, then 45// land the value in the mock register. Returns the ACTUAL written value (always in-envelope). 46func hwd_drive(hw: *i64, pin: i64, u: i64) -> i64 { 47 var v: i64 = u 48 if hw[2 * HW_NP + 1] != 0 { v = 0 } // e-stop latched -> safe 49 if v > HW_SAFE_MAX { v = HW_SAFE_MAX } // never-brick clamp (high) 50 if v < HW_SAFE_MIN { v = HW_SAFE_MIN } // never-brick clamp (low) 51 hw[pin] = v 52 return v 53} 54 55// UNSAFE raw write -- models a NON-fail-safe driver; used ONLY by the gate's negative control. 56func hwd_drive_raw(hw: *i64, pin: i64, u: i64) -> i64 { hw[pin] = u; return u } 57 58// read back the actual output that landed on a pin 59func hwd_out(hw: *i64, pin: i64) -> i64 { return hw[pin] } 60 61func hwd_set_sensor(hw: *i64, pin: i64, val: i64) -> i64 { hw[HW_NP + pin] = val; return 0 } 62func hwd_read_sensor(hw: *i64, pin: i64) -> i64 { return hw[HW_NP + pin] } 63 64// range-check a sensor reading: out-of-range => invalid (1) => firmware must go safe 65func hwd_sensor_invalid(s: i64) -> i64 { 66 if s < HW_SENSOR_MIN { return 1 } 67 if s > HW_SENSOR_MAX { return 1 } 68 return 0 69} 70 71// watchdog: kick to reset; tick each loop -- on overrun it auto-e-stops (fail-safe) 72func hwd_wd_kick(hw: *i64) -> i64 { hw[2 * HW_NP] = 0; return 0 } 73func hwd_wd_tick(hw: *i64) -> i64 { 74 hw[2 * HW_NP] = hw[2 * HW_NP] + 1 75 if hw[2 * HW_NP] > HW_WD_LIMIT { hwd_estop(hw) } 76 return 0 77} 78func hwd_estopped(hw: *i64) -> i64 { return hw[2 * HW_NP + 1] }