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}