code wiki / (root) / nx_print_runtime_compose_test.nx

nx_print_runtime_compose_test.nx source

↩ module page · 150 lines · 6512 B

1// nx_print_runtime_compose_test.nx -- composition smoke for the 2// 9-progenitor runtime monitor. Walks one monitor through a 3// synthetic 1-hour print timeline, deliberately triggering each 4// of the 9 issue kinds at least once and verifying 5// n_issues_total counts every fire across all five step* surfaces: 6// nx_runtime_monitor_step (3 issue kinds) 7// nx_runtime_monitor_step_thermal (3 issue kinds) 8// nx_runtime_monitor_step_runout (1) 9// nx_runtime_monitor_step_layer_shift (1) 10// (Z_BACKWARD also via step() 1) 11// Total: 9 distinct kinds. 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 expect_kind(actual: i64, expected: i64, code: i64) -> i64 { 22 if actual != expected { return code } 23 return 0 24} 25 26func main() -> i64 { 27 let m: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14) 28 if (m as i64) == 0 { return 5 } 29 // 2°C tolerance, 2s alarm duration on thermals 30 nx_runtime_monitor_set_thermal(m, 2, 2000) 31 // 0.3mm tolerance on layer shift 32 nx_runtime_monitor_set_layer_shift_tolerance(m, (3 * Q14) / 10) 33 34 // ===== Phase 1: clean startup (no issues) ===== 35 // First event primes state. 36 if nx_runtime_monitor_step(m, 0, 0, 0, 0) != NX_RT_ISSUE_NONE { return 10 } 37 if nx_runtime_monitor_step_thermal(m, 60, 60, 210, 210, 30, 30, 0) != NX_RT_ISSUE_NONE { return 11 } 38 if nx_runtime_monitor_step_runout(m, 0) != NX_RT_ISSUE_NONE { return 12 } 39 if nx_runtime_monitor_step_layer_shift(m, 0, 0, 0, 0) != NX_RT_ISSUE_NONE { return 13 } 40 if m.n_issues_total != 0 { return 14 } 41 42 // ===== Phase 2: normal printing (3 layers) ===== 43 var t: i64 = 0 44 var layer: i64 = 1 45 while layer <= 3 { 46 t = t + 5000 47 let z: i64 = layer * Q14 / 5 // 0.2 mm/layer 48 let e_acc: i64 = layer * 10 * Q14 49 if nx_runtime_monitor_step(m, z, e_acc, 50 * Q14, t) != NX_RT_ISSUE_NONE { return 20 } 50 if nx_runtime_monitor_step_thermal(m, 60, 60, 210, 210, 30, 30, t) != NX_RT_ISSUE_NONE { return 21 } 51 layer = layer + 1 52 } 53 if m.n_issues_total != 0 { return 22 } 54 55 // ===== Phase 3: deliberately trigger STUCK_LAYER ===== 56 // Don't advance Z, wait > 15s (3 × 5s expected) 57 t = t + 20000 58 let v_stuck: i64 = nx_runtime_monitor_step(m, 3 * Q14 / 5, 40 * Q14, 1 * Q14, t) 59 let r1: i64 = expect_kind(v_stuck, NX_RT_ISSUE_STUCK_LAYER, 30) 60 if r1 != 0 { return r1 } 61 62 // ===== Phase 4: BED_TEMP_DROP ===== 63 // Bed drops 5°C (> 2°C tol) for > 2s 64 t = t + 1000 65 if nx_runtime_monitor_step_thermal(m, 55, 60, 210, 210, 30, 30, t) != NX_RT_ISSUE_NONE { return 40 } 66 t = t + 2500 67 let v_bed: i64 = nx_runtime_monitor_step_thermal(m, 55, 60, 210, 210, 30, 30, t) 68 let r2: i64 = expect_kind(v_bed, NX_RT_ISSUE_BED_TEMP_DROP, 41) 69 if r2 != 0 { return r2 } 70 71 // ===== Phase 5: HOTEND_TEMP_DROP ===== 72 // Recover bed, then drop hotend 73 t = t + 1000 74 if nx_runtime_monitor_step_thermal(m, 60, 60, 200, 210, 30, 30, t) != NX_RT_ISSUE_NONE { return 50 } 75 t = t + 2500 76 let v_hot: i64 = nx_runtime_monitor_step_thermal(m, 60, 60, 200, 210, 30, 30, t) 77 let r3: i64 = expect_kind(v_hot, NX_RT_ISSUE_HOTEND_TEMP_DROP, 51) 78 if r3 != 0 { return r3 } 79 80 // ===== Phase 6: CHAMBER_TEMP_DROP ===== 81 t = t + 1000 82 if nx_runtime_monitor_step_thermal(m, 60, 60, 210, 210, 25, 30, t) != NX_RT_ISSUE_NONE { return 60 } 83 t = t + 2500 84 let v_cham: i64 = nx_runtime_monitor_step_thermal(m, 60, 60, 210, 210, 25, 30, t) 85 let r4: i64 = expect_kind(v_cham, NX_RT_ISSUE_CHAMBER_TEMP_DROP, 61) 86 if r4 != 0 { return r4 } 87 88 // Thermal recovery 89 t = t + 1000 90 if nx_runtime_monitor_step_thermal(m, 60, 60, 210, 210, 30, 30, t) != NX_RT_ISSUE_NONE { return 62 } 91 92 // ===== Phase 7: FILAMENT_RUNOUT (edge) ===== 93 let v_run: i64 = nx_runtime_monitor_step_runout(m, 1) 94 let r5: i64 = expect_kind(v_run, NX_RT_ISSUE_FILAMENT_RUNOUT, 70) 95 if r5 != 0 { return r5 } 96 // Don't re-fire on steady-1 97 if nx_runtime_monitor_step_runout(m, 1) != NX_RT_ISSUE_NONE { return 71 } 98 // Operator reloads 99 if nx_runtime_monitor_step_runout(m, 0) != NX_RT_ISSUE_NONE { return 72 } 100 101 // ===== Phase 8: LAYER_SHIFT ===== 102 let v_shift: i64 = nx_runtime_monitor_step_layer_shift(m, 103 100 * Q14, 100 * Q14 - Q14, // 1mm drift > 0.3mm tol 104 200 * Q14, 200 * Q14) 105 let r6: i64 = expect_kind(v_shift, NX_RT_ISSUE_LAYER_SHIFT, 80) 106 if r6 != 0 { return r6 } 107 108 // ===== Phase 9: FLOW_ANOMALY ===== 109 // Need a fresh state because cumulative_xy_q14 is mid-layer 110 // and dz must be 0; the monitor's last_layer was at phase 3. 111 // We're well past the STUCK threshold now (last_layer_change was 112 // ~5 minutes ago in synthetic time). So a step at the same Z with 113 // big e and small xy would fire STUCK first. To isolate FLOW, 114 // use a second monitor. 115 let m2: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14) 116 nx_runtime_monitor_step(m2, 200 * Q14 / 1000, 0, 0, 0) 117 let v_flow: i64 = nx_runtime_monitor_step(m2, 118 200 * Q14 / 1000, // same Z (dz=0) 119 10 * Q14, // big e 120 1 * Q14, // small xy 121 100) 122 let r7: i64 = expect_kind(v_flow, NX_RT_ISSUE_FLOW_ANOMALY, 90) 123 if r7 != 0 { return r7 } 124 125 // ===== Phase 10: EXTRUDER_RUNAWAY ===== 126 let m3: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14) 127 nx_runtime_monitor_step(m3, 0, 0, 0, 0) 128 nx_runtime_monitor_step(m3, 4 * Q14 / 10, 10 * Q14, 50 * Q14, 5000) 129 // Stay at same Z; e jumps by 100mm with xy only 5mm 130 let v_run2: i64 = nx_runtime_monitor_step(m3, 131 4 * Q14 / 10, 132 110 * Q14, 5 * Q14, 6000) 133 let r8: i64 = expect_kind(v_run2, NX_RT_ISSUE_EXTRUDER_RUNAWAY, 100) 134 if r8 != 0 { return r8 } 135 136 // ===== Phase 11: Z_BACKWARD ===== 137 let m4: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14) 138 nx_runtime_monitor_step(m4, 0, 0, 0, 0) 139 nx_runtime_monitor_step(m4, 12 * Q14, 30 * Q14, 50 * Q14, 5000) 140 let v_back: i64 = nx_runtime_monitor_step(m4, 141 0, 30 * Q14, 0, 6000) 142 let r9: i64 = expect_kind(v_back, NX_RT_ISSUE_Z_BACKWARD, 110) 143 if r9 != 0 { return r9 } 144 145 // ===== Final tally on primary monitor m ===== 146 // m fired: STUCK + BED + HOTEND + CHAMBER + RUNOUT + SHIFT = 6 147 if m.n_issues_total != 6 { return 120 } 148 149 return 0 150}