nx_preflight_test.nx source
↩ module page · 101 lines · 4835 B
1// nx_preflight_test.nx -- exercise preflight orchestrator with
2// good + bad inputs across every failure class.
3//
4// Closed-form invariants:
5// (a) Tetrahedron + Qidi X-Max 3 + Generic PLA + sane params -> SAFE.
6// (b) n_checks_run == 4; n_failed == 0 on the safe case.
7// (c) Non-manifold (3-tri mesh, removed one) -> UNSAFE / NOT_MANIFOLD.
8// (d) Mesh 500mm cube (exceeds 325mm Qidi build) -> UNSAFE / MESH_TOO_LARGE.
9// (e) Material with bad temp (mutate PLA to print 260°C) -> UNSAFE / BAD_THERMAL.
10// (f) Slicer max_speed 1000 mm/s (Qidi max 600) at 0.4×0.2 line ->
11// flow = 0.4 × 0.2 × 1000 = 80 mm³/s > machine 35 mm³/s -> UNSAFE / FLOW_EXCEEDED_MACHINE.
12// (g) Slicer max_speed 200 at 0.4×0.2 -> flow 16 mm³/s; material max 15 ->
13// UNSAFE / FLOW_EXCEEDED_MATERIAL.
14// (h) Verdict name lookup non-NULL for every reason.
15//
16// expect_exit: 0
17// license_tier: ORIGINAL
18
19import "nx_syscalls.nx"
20import "nx_mesh.nx"
21import "nx_mesh_print_check.nx"
22import "nx_machine_graph.nx"
23import "nx_material_profile.nx"
24import "nx_preflight.nx"
25
26const Q14: i64 = 16384
27
28func main() -> i64 {
29 let tet: *NxMesh = nx_mesh_make_tetrahedron(Q14, 0) // 1mm = tiny mesh
30 let qidi: *NxMachineGraph = nx_machine_graph_qidi_xmax3()
31 let pla: *NxMaterialProfile = nx_material_profile_generic_pla()
32
33 // line_width 0.4mm = 6554 Q14; layer_height 0.2mm = 3277 Q14;
34 // typical print speed 150 mm/s.
35 let lw: i64 = 6554
36 let lh: i64 = 3277
37 let speed_ok: i64 = 150
38
39 // --- (a)(b) SAFE case ---
40 let r_safe: *NxPreflightResult = nx_preflight_check(tet, qidi, pla, lh, lw, speed_ok)
41 if r_safe.verdict != NX_PREFLIGHT_SAFE { return 10 }
42 if r_safe.first_reason != NX_PFR_OK { return 11 }
43 if r_safe.n_checks_run != 5 { return 12 } // now 5 checks
44 if r_safe.n_failed != 0 { return 13 }
45
46 // --- (c) Non-manifold mesh ---
47 let bad_mesh: *NxMesh = nx_mesh_make_tetrahedron(Q14, 0)
48 bad_mesh.n_tris = 3 // remove one triangle -> open mesh
49 let r_nm: *NxPreflightResult = nx_preflight_check(bad_mesh, qidi, pla, lh, lw, speed_ok)
50 if r_nm.verdict != NX_PREFLIGHT_UNSAFE { return 20 }
51 if r_nm.first_reason != NX_PFR_NOT_MANIFOLD { return 21 }
52
53 // --- (d) Mesh too large: 500mm cube ---
54 // 500mm = 8192000 Q14. Just need bbox extent > build (Qidi 325mm).
55 // Build a tetrahedron with edge 500mm.
56 let huge: *NxMesh = nx_mesh_make_tetrahedron(500 * Q14, 0)
57 let r_big: *NxPreflightResult = nx_preflight_check(huge, qidi, pla, lh, lw, speed_ok)
58 if r_big.verdict != NX_PREFLIGHT_UNSAFE { return 30 }
59 if r_big.first_reason != NX_PFR_MESH_TOO_LARGE { return 31 }
60
61 // --- (e) Bad thermal: mutate PLA to print 260°C ---
62 let pla_bad: *NxMaterialProfile = nx_material_profile_generic_pla()
63 pla_bad.hotend_print_c = 260 // > PLA decomp 250
64 let r_t: *NxPreflightResult = nx_preflight_check(tet, qidi, pla_bad, lh, lw, speed_ok)
65 if r_t.verdict != NX_PREFLIGHT_UNSAFE { return 40 }
66 if r_t.first_reason != NX_PFR_BAD_THERMAL { return 41 }
67
68 // --- (f) Flow exceeds machine: 1000 mm/s at 0.4×0.2 = 80 mm³/s > 35 ---
69 let r_fm: *NxPreflightResult = nx_preflight_check(tet, qidi, pla, lh, lw, 1000)
70 if r_fm.verdict != NX_PREFLIGHT_UNSAFE { return 50 }
71 if r_fm.first_reason != NX_PFR_FLOW_EXCEEDED_MACHINE { return 51 }
72
73 // --- (g) Flow exceeds material: 250 mm/s × 0.4 × 0.2 = 19 mm³/s > material 15 ---
74 // (At 200 mm/s the integer flow = 15 = material max exactly, no breach.
75 // 250 mm/s breaches cleanly.)
76 let r_fmat: *NxPreflightResult = nx_preflight_check(tet, qidi, pla, lh, lw, 250)
77 if r_fmat.verdict != NX_PREFLIGHT_UNSAFE { return 60 }
78 if r_fmat.first_reason != NX_PFR_FLOW_EXCEEDED_MATERIAL { return 61 }
79
80 // --- (h) Layer too thick: 0.35mm layer on 0.4mm nozzle (>0.3 max) ---
81 let lh_thick: i64 = 5734 // 0.35mm in Q14
82 let r_thick: *NxPreflightResult = nx_preflight_check(tet, qidi, pla, lh_thick, lw, 100)
83 if r_thick.verdict != NX_PREFLIGHT_UNSAFE { return 90 }
84 if r_thick.first_reason != NX_PFR_LAYER_TOO_THICK { return 91 }
85
86 // --- (i) Layer too thin: 0.05mm layer on 0.4mm nozzle (<0.1 min) ---
87 let lh_thin: i64 = 820 // 0.05mm in Q14
88 let r_thin: *NxPreflightResult = nx_preflight_check(tet, qidi, pla, lh_thin, lw, 100)
89 if r_thin.verdict != NX_PREFLIGHT_UNSAFE { return 100 }
90 if r_thin.first_reason != NX_PFR_LAYER_TOO_THIN { return 101 }
91
92 // --- (j) Reason name lookup for all verdicts ---
93 var ri: i64 = 0
94 while ri < NX_PFR_N {
95 let nm: *u8 = nx_pfr_name(ri)
96 if (nm as i64) == 0 { return 110 + ri }
97 ri = ri + 1
98 }
99
100 return 0
101}