nx_machine_graph_test.nx source
↩ module page · 107 lines · 4099 B
1// nx_machine_graph_test.nx -- exercise the Qidi X-Max 3 factory +
2// validator on both the seed default and on hand-corrupted variants.
3//
4// Closed-form invariants:
5// (a) qidi_xmax3 factory returns non-null + validate == OK.
6// (b) Build volume matches verified spec (325 × 325 × 315 mm).
7// (c) Kinematics == COREXY; extruder == DIRECT_DRIVE.
8// (d) Thermal envelope: hotend 350°C, bed 120°C, chamber 65°C,
9// max_flow 35 mm³/s -- all verified against qidi3d.com 2026-05-19.
10// (e) Acceleration = 20000 mm/s², max XY velocity = 600 mm/s.
11// (f) Has Klipper features: input_shaping, auto_bed_mesh, z_probe.
12// (g) Validator catches: bad kinematics, bad build, bad thermal,
13// bad motion, bad hardware.
14// (h) Verdict-name lookup returns non-null for every defined verdict.
15//
16// expect_exit: 0
17// license_tier: ORIGINAL
18
19import "nx_syscalls.nx"
20import "nx_machine_graph.nx"
21
22func main() -> i64 {
23 let g: *NxMachineGraph = nx_machine_graph_qidi_xmax3()
24 if (g as i64) == 0 { return 5 }
25
26 // --- (a) Validate clean factory output ---
27 if nx_machine_graph_validate(g) != NX_MACHINE_OK { return 10 }
28
29 // --- (b) Build volume ---
30 if g.build_x_mm != 325 { return 20 }
31 if g.build_y_mm != 325 { return 21 }
32 if g.build_z_mm != 315 { return 22 }
33
34 // --- (c) Kinematics + extruder ---
35 if g.kinematics != NX_KIN_COREXY { return 30 }
36 if g.extruder_type != NX_EXT_DIRECT_DRIVE { return 31 }
37
38 // --- (d) Thermal + flow ---
39 if g.hotend_max_c != 350 { return 40 }
40 if g.bed_max_c != 120 { return 41 }
41 if g.chamber_max_c != 65 { return 42 }
42 if g.max_flow_mm3s != 35 { return 43 }
43
44 // --- (e) Motion ---
45 if g.max_velocity_xy_mms != 600 { return 50 }
46 if g.max_accel_mms2 != 20000 { return 51 }
47
48 // --- (f) Features ---
49 if g.has_input_shaping != 1 { return 60 }
50 if g.has_auto_bed_mesh != 1 { return 61 }
51 if g.has_z_probe != 1 { return 62 }
52
53 // --- (g) Validator catches mutations ---
54 g.kinematics = 99
55 if nx_machine_graph_validate(g) != NX_MACHINE_ERR_BAD_KIN { return 70 }
56 g.kinematics = NX_KIN_COREXY
57
58 g.build_x_mm = -1
59 if nx_machine_graph_validate(g) != NX_MACHINE_ERR_BAD_BUILD { return 71 }
60 g.build_x_mm = 325
61
62 g.hotend_max_c = 100 // less than hotend_min_c=170
63 if nx_machine_graph_validate(g) != NX_MACHINE_ERR_BAD_THERMAL { return 72 }
64 g.hotend_max_c = 350
65
66 g.max_accel_mms2 = 0
67 if nx_machine_graph_validate(g) != NX_MACHINE_ERR_BAD_MOTION { return 73 }
68 g.max_accel_mms2 = 20000
69
70 g.nozzle_dia_um = 0
71 if nx_machine_graph_validate(g) != NX_MACHINE_ERR_BAD_HARDWARE { return 74 }
72 g.nozzle_dia_um = 400
73
74 if nx_machine_graph_validate(g) != NX_MACHINE_OK { return 79 }
75
76 // --- (h) Verdict-name lookup ---
77 var v: i64 = 0
78 while v <= NX_MACHINE_ERR_BAD_HARDWARE {
79 let n: *u8 = nx_machine_verdict_name(v)
80 if (n as i64) == 0 { return 80 + v }
81 v = v + 1
82 }
83
84 // --- (i) New factories: Prusa MK4, Voron 2.4, Bambu X1C ---
85 let mk4: *NxMachineGraph = nx_machine_graph_prusa_mk4()
86 if (mk4 as i64) == 0 { return 100 }
87 if nx_machine_graph_validate(mk4) != NX_MACHINE_OK { return 101 }
88 if mk4.kinematics != NX_KIN_CARTESIAN { return 102 } // i3-style
89 if mk4.build_x_mm != 250 { return 103 }
90 if mk4.chamber_max_c != 0 { return 104 } // no chamber
91
92 let voron: *NxMachineGraph = nx_machine_graph_voron_2_4()
93 if (voron as i64) == 0 { return 110 }
94 if nx_machine_graph_validate(voron) != NX_MACHINE_OK { return 111 }
95 if voron.kinematics != NX_KIN_COREXY { return 112 }
96 if voron.build_x_mm != 300 { return 113 }
97 if voron.chamber_max_c != 60 { return 114 }
98
99 let bambu: *NxMachineGraph = nx_machine_graph_bambu_x1c()
100 if (bambu as i64) == 0 { return 120 }
101 if nx_machine_graph_validate(bambu) != NX_MACHINE_OK { return 121 }
102 if bambu.kinematics != NX_KIN_COREXY { return 122 }
103 if bambu.build_x_mm != 256 { return 123 }
104 if bambu.max_accel_mms2 != 20000 { return 124 }
105
106 return 0
107}