code wiki / (root) / nx_robot_signal_gate.nx

nx_robot_signal_gate.nx source

↩ module page · 126 lines · 6044 B

1// nx_robot_signal_gate.nx -- R-ROBO-6 GATE: the hardware signal/register rung (STEP/DIR + PWM + GPIO), 2// built from the rung below (nx_robot_step pulse plan). VERIFIES: 3// (1) GPIO write/read + level-normalize (garbage level -> 1); 4// (2) NEVER-BRICK pin-mask: a write to a non-allowed pin is REJECTED and the pin is unchanged; 5// (3) STEP/DIR waveform from a pulse plan: rising-edge count EXACTLY equals the commanded steps 6// (round-trip pulses->waveform->steps), DIR level matches direction; 7// (4) full-move: command (20,8,-5); generate per-axis waveforms; rising edges == |delta| each, 8// negative axis sets DIR high; 9// (5) PWM: in-range duty -> exact high-count; over/under -> CLAMPED (never-brick); 10// (6) EXHAUSTIVE never-brick: sweep PWM duty -50..200 -> high-count always in [0,PERIOD]; 11// (7) NEGATIVE CONTROL: a raw register write escapes the pin-mask (proving the mask is load-bearing). 12// 100% sovereign, integer-only, hardware-rung-up. license_tier: ORIGINAL expect_exit: 0 13import "nx_syscalls.nx" 14import "nx_robot_signal.nx" 15 16func sw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 17func sn(v: i64) -> i64 { 18 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 19 var m: i64 = v 20 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 21 let d: *u8 = sys_mmap(24); var k: i64 = 0 22 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 23 let o: *u8 = sys_mmap(24); var i: i64 = 0 24 while i < k { o[i] = d[k - 1 - i]; i = i + 1 } 25 sys_write(1, o, k); return 0 26} 27func check(name: *u8, cond: i64, tot: *i64) -> i64 { 28 if cond == 1 { sw(" ok " as *u8); tot[0] = tot[0] + 1 } 29 else { sw(" FAIL " as *u8); tot[1] = tot[1] + 1 } 30 sw(name); sw("\n" as *u8) 31 return 0 32} 33func abs_i(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 34 35func main() -> i64 { 36 let tot: *i64 = sys_mmap(16) as *i64 37 tot[0] = 0; tot[1] = 0 38 sw("=== nx_robot_signal_gate R-ROBO-6 -- hardware signal/register rung (STEP/DIR + PWM + GPIO) ===\n" as *u8) 39 40 let NB: i64 = 8 41 let pins: *i64 = gpio_new(NB) 42 let allowed: *i64 = gpio_new(NB) 43 allowed[0] = 1; allowed[1] = 1 // STEP + DIR pins writable; pins 2..7 are NOT 44 45 // (1) write/read + normalize 46 gpio_write(pins, allowed, 0, 1) 47 var ok1: i64 = 0 48 if gpio_read(pins, 0) == 1 { 49 gpio_write(pins, allowed, 1, 99) // garbage level -> normalized to 1 50 if gpio_read(pins, 1) == 1 { ok1 = 1 } 51 } 52 check("GPIO write/read + level-normalize (garbage->1)" as *u8, ok1, tot) 53 54 // (2) never-brick pin mask: write to a disallowed pin (5) rejected, pin stays 0 55 let rej: i64 = gpio_write(pins, allowed, 5, 1) 56 var ok2: i64 = 0 57 if rej == (0 - 1) { if gpio_read(pins, 5) == 0 { ok2 = 1 } } 58 check("NEVER-BRICK pin-mask: write to non-allowed pin REJECTED (pin unchanged)" as *u8, ok2, tot) 59 60 // build a pulse plan: 3 axes, delta (20, 8, -5) 61 let naxes: i64 = 3 62 let delta: *i64 = sys_mmap(64) as *i64 63 delta[0] = 20; delta[1] = 8; delta[2] = 0 - 5 64 let dir: *i64 = sys_mmap(64) as *i64 65 let maxt: i64 = 64 66 let puls: *i64 = sys_mmap(maxt * naxes * 8) as *i64 67 let nt: i64 = robot_step_plan(delta, naxes, dir, puls, maxt) 68 69 // (3) STEP/DIR waveform for axis 1 (8 steps, +dir) 70 let trace: *i64 = sys_mmap(4096) as *i64 71 let nw1: i64 = gen_step_dir(puls, naxes, nt, 1, dir[1], pins, allowed, trace) 72 let re1: i64 = count_rising(trace, nw1, SIG_STEP_BIT) 73 sw(" axis1: waveform writes=" as *u8); sn(nw1); sw(" STEP rising-edges=" as *u8); sn(re1); sw(" (expect 8)\n" as *u8) 74 var ok3: i64 = 0 75 if re1 == 8 { ok3 = 1 } 76 check("STEP/DIR waveform: rising-edge count == commanded steps (axis1=8)" as *u8, ok3, tot) 77 78 // (4) axis 2: 5 steps, dir = -1 -> DIR high 79 let pins2: *i64 = gpio_new(NB) 80 let trace2: *i64 = sys_mmap(4096) as *i64 81 let nw2: i64 = gen_step_dir(puls, naxes, nt, 2, dir[2], pins2, allowed, trace2) 82 let re2: i64 = count_rising(trace2, nw2, SIG_STEP_BIT) 83 sw(" axis2: STEP rising-edges=" as *u8); sn(re2); sw(" DIR pin=" as *u8); sn(gpio_read(pins2, SIG_DIR_BIT)); sw(" (expect 5, DIR=1)\n" as *u8) 84 var ok4: i64 = 0 85 if re2 == 5 { if gpio_read(pins2, SIG_DIR_BIT) == 1 { ok4 = 1 } } 86 check("full move: per-axis edges == |delta| and negative axis sets DIR high" as *u8, ok4, tot) 87 88 // (5) PWM in-range + clamp 89 let pat: *i64 = sys_mmap(SIG_PWM_PERIOD * 8) as *i64 90 let d1: i64 = gen_pwm(30, pat) 91 let h1: i64 = count_high(pat, SIG_PWM_PERIOD) 92 let d2: i64 = gen_pwm(150, pat) // clamp to 100 93 let h2: i64 = count_high(pat, SIG_PWM_PERIOD) 94 let d3: i64 = gen_pwm(0 - 10, pat) // clamp to 0 95 let h3: i64 = count_high(pat, SIG_PWM_PERIOD) 96 sw(" PWM duty 30->high " as *u8); sn(h1); sw(", 150->high " as *u8); sn(h2); sw(", -10->high " as *u8); sn(h3); sw("\n" as *u8) 97 var ok5: i64 = 0 98 if h1 == 30 { if h2 == 100 { if h3 == 0 { ok5 = 1 } } } 99 check("PWM: exact high-count + clamp to [0,PERIOD] (never-brick)" as *u8, ok5, tot) 100 101 // (6) exhaustive never-brick PWM sweep 102 var esc: i64 = 0 103 var du: i64 = 0 - 50 104 while du <= 200 { 105 let dd: i64 = gen_pwm(du, pat) 106 let hh: i64 = count_high(pat, SIG_PWM_PERIOD) 107 if hh < 0 { esc = 1 } 108 if hh > SIG_PWM_PERIOD { esc = 1 } 109 du = du + 1 110 } 111 var ok6: i64 = 0 112 if esc == 0 { ok6 = 1 } 113 check("EXHAUSTIVE never-brick: PWM high-count always in [0,PERIOD] over -50..200" as *u8, ok6, tot) 114 115 // (7) negative control: raw write escapes the pin mask 116 let pins3: *i64 = gpio_new(NB) 117 gpio_write_raw(pins3, 5, 1) // poke disallowed pin 5 directly 118 var ok7: i64 = 0 119 if gpio_read(pins3, 5) == 1 { ok7 = 1 } 120 check("NEG-CONTROL: raw write escapes pin-mask (mask earns its keep)" as *u8, ok7, 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}