nx_moonraker_loop_e2e_test.nx source
↩ module page · 115 lines · 4742 B
1// nx_moonraker_loop_e2e_test.nx -- full input-side substrate loop:
2// real-shape Moonraker JSON -> parse -> pump -> verdict -> wire
3// bytes ready for nx_mr_post_ipv4.
4//
5// This is the CANONICAL composition smoke for the spaghetti
6// prevention loop. Two synthetic Moonraker query responses
7// (one healthy, one with bed-cooled-down-mid-print) flow through
8// the entire substrate input + decision + output chain.
9//
10// Scenarios:
11// A. Healthy snapshot -> NONE -> 0 wire bytes
12// B. Hot bed dropping (1st obs) -> NONE -> 0 wire bytes (timer started)
13// C. Hot bed dropping (3s later) -> BED_TEMP_DROP -> "POST /printer/print/pause"
14//
15// expect_exit: 0
16// license_tier: ORIGINAL
17
18import "nx_syscalls.nx"
19import "nx_print_runtime_monitor.nx"
20import "nx_print_telemetry.nx"
21import "nx_print_response.nx"
22import "nx_moonraker_telemetry_parse.nx"
23
24const Q14: i64 = 16384
25
26func cstr_len(s: *u8) -> i64 {
27 var n: i64 = 0
28 while s[n] != 0 { n = n + 1 }
29 return n
30}
31
32func contains_substring(hay: *u8, hay_len: i64, needle: *u8) -> i64 {
33 var n_len: i64 = 0
34 while needle[n_len] != 0 { n_len = n_len + 1 }
35 if n_len > hay_len { return 0 }
36 var i: i64 = 0
37 while i <= hay_len - n_len {
38 var j: i64 = 0
39 var ok: i64 = 1
40 while j < n_len {
41 if hay[i + j] != needle[j] { ok = 0; j = n_len }
42 j = j + 1
43 }
44 if ok == 1 { return 1 }
45 i = i + 1
46 }
47 return 0
48}
49
50func main() -> i64 {
51 let m: *NxRuntimeMonitor = nx_runtime_monitor_new(5000, 3, 5 * Q14, 2 * Q14)
52 if (m as i64) == 0 { return 5 }
53 nx_runtime_monitor_set_thermal(m, 3, 2000)
54
55 let host: *u8 = "192.168.1.123:7125"
56 let host_len: i64 = 18
57 let out_buf: *u8 = sys_mmap(2048)
58
59 // ===== Scenario A: Healthy snapshot =====
60 let body_a: *u8 =
61"{\"result\":{\"status\":{\"extruder\":{\"temperature\":210.0,\"target\":210.0},\"heater_bed\":{\"temperature\":60.0,\"target\":60.0},\"motion_report\":{\"live_position\":[100.0,100.0,0.4,30.0],\"live_extruder_position\":30.0,\"live_velocity\":60.0}}}}"
62 let bx_a: *i64 = (sys_mmap(8)) as *i64
63 let by_a: *i64 = (sys_mmap(8)) as *i64
64 let bz_a: *i64 = (sys_mmap(8)) as *i64
65 let be_a: *i64 = (sys_mmap(8)) as *i64
66 let bv_a: *i64 = (sys_mmap(8)) as *i64
67 *bx_a = 0
68 *by_a = 0
69 *bz_a = 0
70 *be_a = 0
71 *bv_a = 0
72
73 let ev_a: *NxPrintTelemetry = nx_print_telemetry_new()
74 ev_a.event_time_ms = 1000
75 if nx_moonraker_parse_thermal(body_a, cstr_len(body_a), ev_a) != NX_MR_PARSE_OK { return 10 }
76 if nx_moonraker_parse_motion(body_a, cstr_len(body_a),
77 bx_a, by_a, bz_a, be_a, bv_a) != NX_MR_PARSE_OK { return 11 }
78 ev_a.z_q14 = *bz_a
79 ev_a.e_q14 = *be_a
80 ev_a.xy_delta_q14 = 0 // first event; no previous to diff
81 ev_a.has_motion = 1
82
83 let v_a: i64 = nx_runtime_monitor_pump_telemetry(m, ev_a)
84 if v_a != NX_RT_ISSUE_NONE { return 12 }
85 let n_a: i64 = nx_print_build_response_for_issue(
86 v_a, host, host_len, 0 as *u8, 0, out_buf, 2048)
87 if n_a != 0 { return 13 }
88
89 // ===== Scenario B: Bed dropping (first observation, timer starts) =====
90 let body_b: *u8 =
91"{\"result\":{\"status\":{\"extruder\":{\"temperature\":210.0,\"target\":210.0},\"heater_bed\":{\"temperature\":55.0,\"target\":60.0},\"motion_report\":{\"live_position\":[100.5,100.5,0.4,30.5],\"live_extruder_position\":30.5,\"live_velocity\":60.0}}}}"
92 let ev_b: *NxPrintTelemetry = nx_print_telemetry_new()
93 ev_b.event_time_ms = 2000
94 if nx_moonraker_parse_thermal(body_b, cstr_len(body_b), ev_b) != NX_MR_PARSE_OK { return 20 }
95 if ev_b.bed_actual_c != 55 { return 21 }
96 let v_b: i64 = nx_runtime_monitor_pump_telemetry(m, ev_b)
97 if v_b != NX_RT_ISSUE_NONE { return 22 } // timer started, not yet alarm
98
99 // ===== Scenario C: Bed still dropped 3s later -> ALARM =====
100 let body_c: *u8 =
101"{\"result\":{\"status\":{\"extruder\":{\"temperature\":210.0,\"target\":210.0},\"heater_bed\":{\"temperature\":54.0,\"target\":60.0}}}}"
102 let ev_c: *NxPrintTelemetry = nx_print_telemetry_new()
103 ev_c.event_time_ms = 5000 // 3s past initial dropout at 2000ms
104 if nx_moonraker_parse_thermal(body_c, cstr_len(body_c), ev_c) != NX_MR_PARSE_OK { return 30 }
105 let v_c: i64 = nx_runtime_monitor_pump_telemetry(m, ev_c)
106 if v_c != NX_RT_ISSUE_BED_TEMP_DROP { return 31 }
107
108 let n_c: i64 = nx_print_build_response_for_issue(
109 v_c, host, host_len, 0 as *u8, 0, out_buf, 2048)
110 if n_c <= 0 { return 32 }
111 if contains_substring(out_buf, n_c, "POST /printer/print/pause") != 1 { return 33 }
112 if contains_substring(out_buf, n_c, "Host: 192.168.1.123:7125") != 1 { return 34 }
113
114 return 0
115}