code wiki / (root) / nx_klipper_gcode_validator_test.nx

nx_klipper_gcode_validator_test.nx source

↩ module page · 109 lines · 3994 B

1// nx_klipper_gcode_validator_test.nx -- exercise the Klipper grammar 2// validator + verify the slicer's emitted G-code passes. 3// 4// Closed-form invariants: 5// (a) Empty input -> BAD_INPUT 6// (b) Single valid line "G1 X10 Y20 E0.5 F1500\n" -> OK 7// (c) Comment line ";LAYER 5\n" -> OK 8// (d) Line missing command number "G\n" -> BAD_LINE 9// (e) Line with control char "G1\x01X10\n" -> BAD_CONTROL_CHAR 10// (f) Line with negative feedrate "G1 F-100\n" -> BAD_FEEDRATE 11// (g) Line with zero feedrate "G1 F0\n" -> BAD_FEEDRATE 12// (h) Line with bad parameter "G1 q10\n" (lowercase letter) -> BAD_PARAM 13// (i) Real emitted G-code from the slicer passes 14// 15// expect_exit: 0 16// license_tier: ORIGINAL 17 18import "nx_syscalls.nx" 19import "nx_mesh.nx" 20import "nx_machine_graph.nx" 21import "nx_material_profile.nx" 22import "nx_gcode_emit.nx" 23import "nx_slice_pipeline.nx" 24import "nx_klipper_gcode_validator.nx" 25 26func put_str(dst: *u8, src: *u8) -> i64 { 27 var i: i64 = 0 28 while src[i] != 0 { 29 dst[i] = src[i] 30 i = i + 1 31 } 32 return i 33} 34 35func main() -> i64 { 36 let line_box: *i64 = sys_mmap(8) as *i64 37 38 // ===== (a) Empty input -> BAD_INPUT ===== 39 let empty: *u8 = sys_mmap(4) 40 let r_empty: i64 = nx_klipper_gcode_validate(empty, 0, line_box) 41 if r_empty != NX_KGV_BAD_INPUT { return 10 } 42 43 // ===== (b) Valid line -> OK ===== 44 let line_b: *u8 = sys_mmap(64) 45 let nb: i64 = put_str(line_b, "G1 X10 Y20 E0.5 F1500\n") 46 let r_b: i64 = nx_klipper_gcode_validate(line_b, nb, line_box) 47 if r_b != NX_KGV_OK { return 20 } 48 49 // ===== (c) Comment line -> OK ===== 50 let line_c: *u8 = sys_mmap(64) 51 let nc: i64 = put_str(line_c, ";LAYER 5\n") 52 let r_c: i64 = nx_klipper_gcode_validate(line_c, nc, line_box) 53 if r_c != NX_KGV_OK { return 30 } 54 55 // ===== (d) Missing command number -> BAD_LINE ===== 56 let line_d: *u8 = sys_mmap(16) 57 let nd: i64 = put_str(line_d, "G\n") 58 let r_d: i64 = nx_klipper_gcode_validate(line_d, nd, line_box) 59 if r_d != NX_KGV_BAD_LINE { return 40 } 60 61 // ===== (e) Control char -> BAD_CONTROL_CHAR ===== 62 let line_e: *u8 = sys_mmap(32) 63 line_e[0] = 0x47 // 'G' 64 line_e[1] = 0x31 // '1' 65 line_e[2] = 0x01 // SOH control char 66 line_e[3] = 0x58 // 'X' 67 line_e[4] = 0x31 // '1' 68 line_e[5] = 0x30 // '0' 69 line_e[6] = 0x0A // \n 70 let r_e: i64 = nx_klipper_gcode_validate(line_e, 7, line_box) 71 if r_e != NX_KGV_BAD_CONTROL_CHAR { return 50 } 72 73 // ===== (f) Negative feedrate -> BAD_FEEDRATE ===== 74 let line_f: *u8 = sys_mmap(32) 75 let nf: i64 = put_str(line_f, "G1 F-100\n") 76 let r_f: i64 = nx_klipper_gcode_validate(line_f, nf, line_box) 77 if r_f != NX_KGV_BAD_FEEDRATE { return 60 } 78 79 // ===== (g) Zero feedrate -> BAD_FEEDRATE ===== 80 let line_g: *u8 = sys_mmap(32) 81 let ng: i64 = put_str(line_g, "G1 F0\n") 82 let r_g: i64 = nx_klipper_gcode_validate(line_g, ng, line_box) 83 if r_g != NX_KGV_BAD_FEEDRATE { return 70 } 84 85 // ===== (h) Lowercase parameter letter -> BAD_PARAM ===== 86 let line_h: *u8 = sys_mmap(32) 87 let nh: i64 = put_str(line_h, "G1 q10\n") 88 let r_h: i64 = nx_klipper_gcode_validate(line_h, nh, line_box) 89 if r_h != NX_KGV_BAD_PARAM { return 80 } 90 91 // ===== (i) Real slicer-emitted G-code passes ===== 92 let qidi: *NxMachineGraph = nx_machine_graph_qidi_xmax3() 93 let pla: *NxMaterialProfile = nx_material_profile_generic_pla() 94 let lh: i64 = 3277 95 let lw: i64 = 6554 96 let mesh: *NxMesh = nx_mesh_make_cube(5 * 16384, 0) 97 let e: *NxGcodeEmitter = nx_gemit_new(qidi, pla, lh, lw, 524288) 98 nx_gemit_preamble(e) 99 let n_layers: i64 = nx_slice_pipe_run_v2(e, mesh, 20, lh) 100 if n_layers <= 0 { return 90 } 101 let r_real: i64 = nx_klipper_gcode_validate(e.buf, e.len, line_box) 102 if r_real != NX_KGV_OK { 103 // Don't claim PASS if our own emitter outputs invalid Klipper 104 // G-code -- that's a real bug to fix. 105 return 91 106 } 107 108 return 0 109}