code wiki / (root) / nx_print_e2e_test.nx

nx_print_e2e_test.nx source

↩ module page · 110 lines · 4252 B

1// nx_print_e2e_test.nx -- THE end-to-end integration demo. Single 2// runnable composes every shipped primitive into the operator-side 3// workflow: 4// 5// 1. Build a synthetic mesh (Voron-cube-style tetrahedron at unit 6// scale -- real STL load is operator-side via nx_stl_load_binary 7// on a file buffer; we use the synthetic mesh in-test). 8// 2. Run the full slicer pipeline (nx_slice_pipeline) to produce 9// G-code into a memory buffer. 10// 3. Write the G-code bytes to stdout (fd 1) so the operator can 11// pipe to a .gcode file. 12// 4. Build the Moonraker POST /printer/print/start request bytes 13// for filename "cube.gcode" with API key "demo". 14// 5. Write the Moonraker request bytes to stderr (fd 2) so the 15// operator can inspect / pipe them into curl / nc for upload. 16// 6. Return 0 if every step succeeded. 17// 18// Operator workflow: 19// $ ./nx_print_e2e > cube.gcode 2> moonraker.req 20// (then operator uploads cube.gcode + sends moonraker.req) 21// 22// Assertions (in-test verification): 23// - G-code buffer non-empty + contains expected markers 24// - Moonraker request buffer non-empty + contains expected markers 25// - Both written to their respective fds 26// 27// expect_exit: 0 28// license_tier: ORIGINAL 29 30import "nx_syscalls.nx" 31import "nx_mesh.nx" 32import "nx_mesh_print_check.nx" 33import "nx_bvh.nx" 34import "nx_machine_graph.nx" 35import "nx_material_profile.nx" 36import "nx_gcode_emit.nx" 37import "nx_slice_pipeline.nx" 38import "nx_moonraker_client.nx" 39 40const Q14: i64 = 16384 41 42func smoke_contains(buf: *u8, len: i64, needle: *u8) -> i64 { 43 var nlen: i64 = 0 44 while needle[nlen] != 0 { nlen = nlen + 1 } 45 if len < nlen { return 0 } 46 var i: i64 = 0 47 while i <= len - nlen { 48 var j: i64 = 0 49 var matched: i64 = 1 50 while j < nlen { 51 if buf[i + j] != needle[j] { matched = 0; j = nlen } 52 j = j + 1 53 } 54 if matched == 1 { return 1 } 55 i = i + 1 56 } 57 return 0 58} 59 60func main() -> i64 { 61 // === Step 1: synthetic mesh === 62 let mesh: *NxMesh = nx_mesh_make_tetrahedron(Q14, 0) 63 if (mesh as i64) == 0 { return 5 } 64 65 // === Step 2: full slicer pipeline === 66 let machine: *NxMachineGraph = nx_machine_graph_qidi_xmax3() 67 let material: *NxMaterialProfile = nx_material_profile_generic_pla() 68 let layer_h: i64 = 3277 // 0.2 mm 69 let line_w: i64 = 6554 // 0.4 mm 70 let emitter: *NxGcodeEmitter = nx_gemit_new(machine, material, 71 layer_h, line_w, 131072) 72 if (emitter as i64) == 0 { return 10 } 73 nx_gemit_preamble(emitter) 74 let n_layers: i64 = nx_slice_pipe_run(emitter, mesh, 20) 75 if n_layers <= 0 { return 11 } 76 if emitter.len < 500 { return 12 } 77 78 // === Step 3: G-code to stdout (fd 1) === 79 let n_wrote_gcode: i64 = sys_write(1, emitter.buf, emitter.len) 80 if n_wrote_gcode != emitter.len { return 20 } 81 82 // === Step 4: Moonraker request bytes === 83 // Body: {"filename":"cube.gcode"} ; URL path: /printer/print/start 84 let mr_buf: *u8 = sys_mmap(4096) 85 let fn: *u8 = "cube.gcode" 86 let fn_len: i64 = 10 87 let body_buf: *u8 = sys_mmap(256) 88 let body_len: i64 = nx_mr_build_print_start_body(fn, fn_len, 89 body_buf, 256) 90 if body_len <= 0 { return 30 } 91 92 let host: *u8 = "10.0.0.5:7125" 93 let path: *u8 = "/printer/print/start" 94 let api: *u8 = "demo" 95 let req_len: i64 = nx_mr_build_post_request(host, 13, 96 path, 20, 97 body_buf, body_len, 98 api, 4, 99 mr_buf, 4096) 100 if req_len <= 0 { return 31 } 101 if smoke_contains(mr_buf, req_len, "POST /printer/print/start") != 1 { return 32 } 102 if smoke_contains(mr_buf, req_len, "X-Api-Key: demo") != 1 { return 33 } 103 if smoke_contains(mr_buf, req_len, "{\"filename\":\"cube.gcode\"}") != 1 { return 34 } 104 105 // === Step 5: Moonraker request to stderr (fd 2) === 106 let n_wrote_mr: i64 = sys_write(2, mr_buf, req_len) 107 if n_wrote_mr != req_len { return 40 } 108 109 return 0 110}