nx_robot_signal.nx source
↩ module page · 94 lines · 4299 B
1// nx_robot_signal.nx -- SOVEREIGN hardware SIGNAL/REGISTER rung (the lowest robot-control layer,
2// beneath the driver). A real stepper driver chip (A4988/DRV8825 class) does NOT consume an integer
3// "output" -- it consumes a STEP/DIR digital WAVEFORM on GPIO pins: a rising edge on STEP = one motor
4// micro-step, DIR level = direction. A servo/ESC consumes a PWM bit pattern. This rung MODELS the
5// GPIO register and GENERATES those actual signals from the pulse plan (nx_robot_step, the rung above
6// feeds DOWN into this one) -- building from the hardware rung up. 100% Nishi, integer-only.
7// NEVER-BRICK (#26) BY CONSTRUCTION at the register level:
8// * a write to a NON-allowed pin is REJECTED (can't poke arbitrary hardware registers);
9// * a pin level is normalized to {0,1} (can't write a garbage register value);
10// * PWM duty is clamped to [0, PERIOD] (can't command an out-of-range / >100% pulse).
11// GPIO modeled as arrays (pins[bit]=level, allowed[bit]=writable?) = a faithful register model with
12// no undefined bit-twiddling. Binding pins[] to a real board's MMIO base address is the bench step.
13// license_tier: ORIGINAL expect_exit: 0
14import "nx_syscalls.nx"
15import "nx_robot_step.nx"
16
17const SIG_STEP_BIT: i64 = 0
18const SIG_DIR_BIT: i64 = 1
19const SIG_PWM_PERIOD: i64 = 100
20
21// allocate a GPIO model: returns pins[]; caller also passes an allowed[] mask.
22func gpio_new(nbits: i64) -> *i64 {
23 let p: *i64 = sys_mmap(nbits * 8) as *i64
24 var i: i64 = 0
25 while i < nbits { p[i] = 0; i = i + 1 }
26 return p
27}
28
29// FAIL-SAFE register write: reject disallowed pins, normalize level to {0,1}. returns level written, or -1 if rejected.
30func gpio_write(pins: *i64, allowed: *i64, bit: i64, level: i64) -> i64 {
31 if allowed[bit] == 0 { return 0 - 1 } // never-brick: only declared pins are writable
32 var v: i64 = 0
33 if level != 0 { v = 1 } // normalize -> no garbage register value
34 pins[bit] = v
35 return v
36}
37// UNSAFE raw write (neg-control only): no mask, no normalize -> models poking an arbitrary register.
38func gpio_write_raw(pins: *i64, bit: i64, level: i64) -> i64 { pins[bit] = level; return level }
39func gpio_read(pins: *i64, bit: i64) -> i64 { return pins[bit] }
40
41// Generate the STEP/DIR waveform for one axis from its pulse plan. Records every register write into
42// trace[] (flat: trace[2*k]=bit, trace[2*k+1]=level). Sets DIR once, then per planned pulse emits a
43// STEP rising edge (1) then falling edge (0). Returns the number of register writes.
44func gen_step_dir(puls: *i64, naxes: i64, nt: i64, axis: i64, dir: i64,
45 pins: *i64, allowed: *i64, trace: *i64) -> i64 {
46 var w: i64 = 0
47 var dlevel: i64 = 0
48 if dir < 0 { dlevel = 1 }
49 gpio_write(pins, allowed, SIG_DIR_BIT, dlevel)
50 trace[2 * w] = SIG_DIR_BIT; trace[2 * w + 1] = dlevel; w = w + 1
51 var t: i64 = 0
52 while t < nt {
53 if puls[t * naxes + axis] == 1 {
54 gpio_write(pins, allowed, SIG_STEP_BIT, 1)
55 trace[2 * w] = SIG_STEP_BIT; trace[2 * w + 1] = 1; w = w + 1
56 gpio_write(pins, allowed, SIG_STEP_BIT, 0)
57 trace[2 * w] = SIG_STEP_BIT; trace[2 * w + 1] = 0; w = w + 1
58 }
59 t = t + 1
60 }
61 return w
62}
63
64// count rising edges (0->1) of a given bit in a waveform trace = motor steps actually emitted
65func count_rising(trace: *i64, nw: i64, bit: i64) -> i64 {
66 var c: i64 = 0
67 var prev: i64 = 0
68 var k: i64 = 0
69 while k < nw {
70 if trace[2 * k] == bit {
71 let lv: i64 = trace[2 * k + 1]
72 if prev == 0 { if lv == 1 { c = c + 1 } }
73 prev = lv
74 }
75 k = k + 1
76 }
77 return c
78}
79
80// Generate a PWM bit pattern over SIG_PWM_PERIOD slots from a duty value; duty clamped to [0,PERIOD]
81// (never-brick). pat[i] = 1 for the first (clamped duty) slots. returns the actual (clamped) duty.
82func gen_pwm(duty: i64, pat: *i64) -> i64 {
83 var d: i64 = duty
84 if d < 0 { d = 0 }
85 if d > SIG_PWM_PERIOD { d = SIG_PWM_PERIOD }
86 var i: i64 = 0
87 while i < SIG_PWM_PERIOD { if i < d { pat[i] = 1 } else { pat[i] = 0 } i = i + 1 }
88 return d
89}
90func count_high(pat: *i64, n: i64) -> i64 {
91 var c: i64 = 0; var i: i64 = 0
92 while i < n { if pat[i] == 1 { c = c + 1 } i = i + 1 }
93 return c
94}