nx_print_runtime_shift_test.nx source
↩ module page · 88 lines · 3444 B
1// nx_print_runtime_shift_test.nx -- layer-shift / lost-steps detection.
2//
3// Closed-form invariants:
4// (a) Perfect cmd == act on both axes: no fire
5// (b) Sub-tolerance drift: no fire
6// (c) X drift > tolerance: fires LAYER_SHIFT
7// (d) Y drift > tolerance: fires LAYER_SHIFT
8// (e) Negative drift (actual ahead of commanded): fires too (abs)
9// (f) Setter rejects negative tolerance + null monitor
10// (g) Tighter tolerance catches smaller drift
11// (h) n_issues_total tracks fires
12//
13// expect_exit: 0
14// license_tier: ORIGINAL
15
16import "nx_syscalls.nx"
17import "nx_print_runtime_monitor.nx"
18
19const Q14: i64 = 16384
20
21func main() -> i64 {
22 let m: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14)
23 if (m as i64) == 0 { return 5 }
24
25 // Default tolerance is 0.5mm = Q14/2.
26
27 // ===== (a) Perfect cmd == act: no fire =====
28 let v0: i64 = nx_runtime_monitor_step_layer_shift(m,
29 100 * Q14, 100 * Q14,
30 200 * Q14, 200 * Q14)
31 if v0 != NX_RT_ISSUE_NONE { return 10 }
32
33 // ===== (b) Sub-tolerance drift (0.3mm on X): no fire =====
34 // 0.3mm = 3*Q14/10
35 let small_drift: i64 = (3 * Q14) / 10
36 let v1: i64 = nx_runtime_monitor_step_layer_shift(m,
37 100 * Q14, 100 * Q14 - small_drift,
38 200 * Q14, 200 * Q14)
39 if v1 != NX_RT_ISSUE_NONE { return 20 }
40
41 // ===== (c) X drift > tolerance (0.8mm): fires =====
42 let big_drift: i64 = (8 * Q14) / 10 // 0.8mm > 0.5mm tol
43 let v2: i64 = nx_runtime_monitor_step_layer_shift(m,
44 100 * Q14, 100 * Q14 - big_drift,
45 200 * Q14, 200 * Q14)
46 if v2 != NX_RT_ISSUE_LAYER_SHIFT { return 30 }
47 if m.n_issues_total != 1 { return 31 }
48
49 // ===== (d) Y drift > tolerance: fires =====
50 let v3: i64 = nx_runtime_monitor_step_layer_shift(m,
51 100 * Q14, 100 * Q14,
52 200 * Q14, 200 * Q14 - big_drift)
53 if v3 != NX_RT_ISSUE_LAYER_SHIFT { return 40 }
54 if m.n_issues_total != 2 { return 41 }
55
56 // ===== (e) Negative drift (actual ahead of commanded): also fires =====
57 let v4: i64 = nx_runtime_monitor_step_layer_shift(m,
58 100 * Q14, 100 * Q14 + big_drift, // act 0.8mm AHEAD
59 200 * Q14, 200 * Q14)
60 if v4 != NX_RT_ISSUE_LAYER_SHIFT { return 50 }
61 if m.n_issues_total != 3 { return 51 }
62
63 // ===== (f) Setter guards =====
64 if nx_runtime_monitor_set_layer_shift_tolerance(m, -1) != NX_RT_BAD_INPUT { return 60 }
65 if nx_runtime_monitor_set_layer_shift_tolerance(0 as *NxRuntimeMonitor, 1) != NX_RT_BAD_INPUT { return 61 }
66
67 // ===== (g) Tighter tolerance catches smaller drift =====
68 let m2: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14)
69 // Tighten to 0.1mm
70 if nx_runtime_monitor_set_layer_shift_tolerance(m2, Q14 / 10) != NX_RT_OK { return 70 }
71 // 0.2mm drift now fires (would NOT have fired at default 0.5mm)
72 let drift_02: i64 = (2 * Q14) / 10
73 let v_tight: i64 = nx_runtime_monitor_step_layer_shift(m2,
74 100 * Q14, 100 * Q14 - drift_02,
75 200 * Q14, 200 * Q14)
76 if v_tight != NX_RT_ISSUE_LAYER_SHIFT { return 71 }
77
78 // Same drift on m (default 0.5mm) should NOT fire
79 let v_loose: i64 = nx_runtime_monitor_step_layer_shift(m,
80 100 * Q14, 100 * Q14 - drift_02,
81 200 * Q14, 200 * Q14)
82 if v_loose != NX_RT_ISSUE_NONE { return 72 }
83
84 // ===== (h) Issue count tracking =====
85 if m.n_issues_total != 3 { return 80 } // c + d + e
86
87 return 0
88}