nx_print_telemetry_test.nx source
↩ module page · 120 lines · 4942 B
1// nx_print_telemetry_test.nx -- exercise the unified telemetry
2// pump across all 4 enabled surfaces.
3//
4// Closed-form invariants:
5// (a) Empty event (all has_* = 0): no issue, no count
6// (b) Motion-only event with normal values: no issue
7// (c) Motion + thermal + runout + shift all populated, normal: no issue
8// (d) Shift drift fires LAYER_SHIFT (priority 1)
9// (e) When multiple kinds fire on one tick, returned verdict is
10// the priority-1 winner BUT n_issues_total counts all fires
11// (f) Partial population: has_motion=1, others 0; runout sensor
12// set but has_runout=0 -> no runout fire
13// (g) Null m / null ev returns NONE
14//
15// expect_exit: 0
16// license_tier: ORIGINAL
17
18import "nx_syscalls.nx"
19import "nx_print_runtime_monitor.nx"
20import "nx_print_telemetry.nx"
21
22const Q14: i64 = 16384
23
24func main() -> i64 {
25 let m: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14)
26 if (m as i64) == 0 { return 5 }
27 nx_runtime_monitor_set_thermal(m, 2, 2000)
28 nx_runtime_monitor_set_layer_shift_tolerance(m, (3 * Q14) / 10)
29
30 // ===== (a) Empty event: no issue =====
31 let e0: *NxPrintTelemetry = nx_print_telemetry_new()
32 if (e0 as i64) == 0 { return 6 }
33 let v0: i64 = nx_runtime_monitor_pump_telemetry(m, e0)
34 if v0 != NX_RT_ISSUE_NONE { return 10 }
35 if m.n_issues_total != 0 { return 11 }
36
37 // ===== (b) Motion-only event, normal =====
38 let e1: *NxPrintTelemetry = nx_print_telemetry_new()
39 e1.event_time_ms = 0
40 e1.z_q14 = 0
41 e1.e_q14 = 0
42 e1.xy_delta_q14 = 0
43 e1.has_motion = 1
44 if nx_runtime_monitor_pump_telemetry(m, e1) != NX_RT_ISSUE_NONE { return 20 }
45 // Second event progresses normally
46 let e1b: *NxPrintTelemetry = nx_print_telemetry_new()
47 e1b.event_time_ms = 5000
48 e1b.z_q14 = Q14 / 5 // 0.2mm
49 e1b.e_q14 = 10 * Q14
50 e1b.xy_delta_q14 = 50 * Q14
51 e1b.has_motion = 1
52 if nx_runtime_monitor_pump_telemetry(m, e1b) != NX_RT_ISSUE_NONE { return 21 }
53 if m.n_issues_total != 0 { return 22 }
54
55 // ===== (c) All four surfaces populated, normal values =====
56 let e2: *NxPrintTelemetry = nx_print_telemetry_new()
57 e2.event_time_ms = 10000
58 e2.z_q14 = 2 * Q14 / 5
59 e2.e_q14 = 20 * Q14
60 e2.xy_delta_q14 = 50 * Q14
61 e2.has_motion = 1
62 e2.bed_actual_c = 60
63 e2.bed_setpoint_c = 60
64 e2.hotend_actual_c = 210
65 e2.hotend_setpoint_c = 210
66 e2.chamber_actual_c = 30
67 e2.chamber_setpoint_c = 30
68 e2.has_thermal = 1
69 e2.runout_triggered = 0
70 e2.has_runout = 1
71 e2.commanded_x_q14 = 100 * Q14
72 e2.actual_x_q14 = 100 * Q14
73 e2.commanded_y_q14 = 100 * Q14
74 e2.actual_y_q14 = 100 * Q14
75 e2.has_shift = 1
76 if nx_runtime_monitor_pump_telemetry(m, e2) != NX_RT_ISSUE_NONE { return 30 }
77
78 // ===== (d) Shift drift fires LAYER_SHIFT (priority 1) =====
79 let e3: *NxPrintTelemetry = nx_print_telemetry_new()
80 e3.event_time_ms = 15000
81 e3.commanded_x_q14 = 100 * Q14
82 e3.actual_x_q14 = 100 * Q14 - Q14 // 1mm drift > 0.3mm tol
83 e3.commanded_y_q14 = 100 * Q14
84 e3.actual_y_q14 = 100 * Q14
85 e3.has_shift = 1
86 let v3: i64 = nx_runtime_monitor_pump_telemetry(m, e3)
87 if v3 != NX_RT_ISSUE_LAYER_SHIFT { return 40 }
88
89 // ===== (e) Multiple kinds fire on one tick -> priority winner returned,
90 // n_issues_total counts every fire.
91 let pre_count: i64 = m.n_issues_total
92 let e4: *NxPrintTelemetry = nx_print_telemetry_new()
93 e4.event_time_ms = 20000
94 e4.commanded_x_q14 = 100 * Q14
95 e4.actual_x_q14 = 100 * Q14 - Q14 // drift -> LAYER_SHIFT
96 e4.commanded_y_q14 = 100 * Q14
97 e4.actual_y_q14 = 100 * Q14
98 e4.has_shift = 1
99 e4.runout_triggered = 1 // edge 0->1 -> RUNOUT
100 e4.has_runout = 1
101 let v4: i64 = nx_runtime_monitor_pump_telemetry(m, e4)
102 if v4 != NX_RT_ISSUE_LAYER_SHIFT { return 50 } // priority 1 wins
103 // Both fired: count incremented by 2
104 if m.n_issues_total != pre_count + 2 { return 51 }
105
106 // ===== (f) Partial population: has_runout = 0, runout_triggered = 1
107 // -> no runout fire =====
108 let m2: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14)
109 let e5: *NxPrintTelemetry = nx_print_telemetry_new()
110 e5.runout_triggered = 1
111 e5.has_runout = 0 // explicitly skip runout surface
112 if nx_runtime_monitor_pump_telemetry(m2, e5) != NX_RT_ISSUE_NONE { return 60 }
113 if m2.n_issues_total != 0 { return 61 }
114
115 // ===== (g) Null guards =====
116 if nx_runtime_monitor_pump_telemetry(0 as *NxRuntimeMonitor, e0) != NX_RT_ISSUE_NONE { return 70 }
117 if nx_runtime_monitor_pump_telemetry(m, 0 as *NxPrintTelemetry) != NX_RT_ISSUE_NONE { return 71 }
118
119 return 0
120}