• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cbruiz / printhor / 13775596467

10 Mar 2025 09:59PM UTC coverage: 90.713% (-0.02%) from 90.734%
13775596467

push

github

web-flow
Review/motion optimizations (#36)

* Module refactoring and light doc improvement
* Bump embassy upstream

184 of 218 new or added lines in 16 files covered. (84.4%)

11 existing lines in 1 file now uncovered.

14837 of 16356 relevant lines covered (90.71%)

733512.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.24
/printhor/src/bin/tasks/task_integration.rs
1
use crate::{hwa, processing};
2
use alloc::string::ToString;
3
use hwa::CoordSel;
4
#[allow(unused)]
5
use hwa::HwiContract;
6
use hwa::PersistentState;
7
use hwa::make_vector_real;
8
use hwa::math;
9
#[allow(unused)]
10
use hwa::{CommChannel, EventBusSubscriber, EventFlags, EventStatus};
11
#[allow(unused)]
12
use math::Real;
13
use processing::GCodeProcessor;
14

15
// A global static notifier to indicate when task_integration is completed
16
#[cfg(any(test, feature = "integration-test"))]
17
pub static INTEGRATION_STATUS: PersistentState<hwa::AsyncCsMutexType, bool> =
18
    PersistentState::new();
19

20
#[embassy_executor::task(pool_size = 1)]
4✔
21
pub async fn task_integration(
4✔
22
    mut processor: GCodeProcessor,
4✔
23
    #[cfg(feature = "with-sd-card")] mut card_controller: hwa::types::SDCardController,
4✔
24
    #[cfg(feature = "with-print-job")] mut printer_controller: hwa::controllers::PrinterController,
4✔
25
) {
4✔
26
    #[allow(unused)]
4✔
27
    let expect_immediate = |res| match res {
102✔
28
        processing::CodeExecutionSuccess::OK | processing::CodeExecutionSuccess::CONSUMED => {
29
            Ok(processing::CodeExecutionSuccess::OK)
102✔
30
        }
NEW
31
        processing::CodeExecutionSuccess::QUEUED => Ok(processing::CodeExecutionSuccess::OK),
×
NEW
32
        processing::CodeExecutionSuccess::DEFERRED(_) => Err(processing::CodeExecutionFailure::ERR),
×
33
    };
102✔
34
    #[allow(unused)]
35
    let expect_deferred = |res| match res {
8✔
36
        processing::CodeExecutionSuccess::OK | processing::CodeExecutionSuccess::CONSUMED => {
NEW
37
            Err(processing::CodeExecutionFailure::ERR)
×
38
        }
NEW
39
        processing::CodeExecutionSuccess::QUEUED => Err(processing::CodeExecutionFailure::ERR),
×
40
        processing::CodeExecutionSuccess::DEFERRED(evt) => Ok(evt),
8✔
41
    };
8✔
42

43
    let event_bus = processor.event_bus.clone();
4✔
44

45
    let mut subscriber = event_bus.subscriber().await;
4✔
46

47
    hwa::info!("[task_integration] Waiting for SYS_READY");
4✔
48
    subscriber
4✔
49
        .ft_wait_until(EventFlags::SYS_READY)
4✔
50
        .await
4✔
51
        .expect("Must be ready");
4✔
52

4✔
53
    hwa::info!("[task_integration] Got SYS_READY. Continuing");
4✔
54
    hwa::info!(
4✔
55
        "[task_integration] EventBus status is [{:?}]",
4✔
56
        event_bus.get_status().await
4✔
57
    );
58
    hwa::info!("##");
4✔
59
    hwa::info!("# Integration_task START.");
4✔
60

61
    hwa::info!("##");
4✔
62

63
    // Set endstops up for simulation for homing to be completed properly
64
    #[cfg(all(feature = "with-motion", feature = "native"))]
65
    {
66
        let dg = processor.motion_planner.motion_driver().lock().await;
4✔
67
        dg.step_actuator
4✔
68
            .set_end_stop_high(CoordSel::X | CoordSel::Y | CoordSel::Z)
4✔
69
    }
4✔
70

4✔
71
    {
4✔
72
        let test_name = "T1 [status: M100 (Machine info), M105, M115, M503, M119, M]";
4✔
73

4✔
74
        hwa::info!("## {} - BEGIN", test_name);
4✔
75
        processor
4✔
76
            .execute(
4✔
77
                CommChannel::Internal,
4✔
78
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::M100),
4✔
79
                true,
4✔
80
            )
4✔
81
            .await
4✔
82
            .and_then(expect_immediate)
4✔
83
            .expect("M100 OK");
4✔
84

4✔
85
        processor
4✔
86
            .execute(
4✔
87
                CommChannel::Internal,
4✔
88
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::M105),
4✔
89
                true,
4✔
90
            )
4✔
91
            .await
4✔
92
            .and_then(expect_immediate)
4✔
93
            .expect("M105 OK");
4✔
94

4✔
95
        processor
4✔
96
            .execute(
4✔
97
                CommChannel::Internal,
4✔
98
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::M115),
4✔
99
                true,
4✔
100
            )
4✔
101
            .await
4✔
102
            .and_then(expect_immediate)
4✔
103
            .expect("115 OK");
4✔
104

4✔
105
        processor
4✔
106
            .execute(
4✔
107
                CommChannel::Internal,
4✔
108
                &processing::GCodeCmd::new(
4✔
109
                    0,
4✔
110
                    None,
4✔
111
                    processing::GCodeValue::M503(processing::S { s: Some(math::ONE) }),
4✔
112
                ),
4✔
113
                true,
4✔
114
            )
4✔
115
            .await
4✔
116
            .and_then(expect_immediate)
4✔
117
            .expect("M503 S1 OK");
4✔
118

4✔
119
        processor
4✔
120
            .execute(
4✔
121
                CommChannel::Internal,
4✔
122
                &processing::GCodeCmd::new(
4✔
123
                    0,
4✔
124
                    None,
4✔
125
                    processing::GCodeValue::M503(processing::S {
4✔
126
                        s: Some(math::ZERO),
4✔
127
                    }),
4✔
128
                ),
4✔
129
                true,
4✔
130
            )
4✔
131
            .await
4✔
132
            .and_then(expect_immediate)
4✔
133
            .expect("M503 S0 OK");
4✔
134

4✔
135
        processor
4✔
136
            .execute(
4✔
137
                CommChannel::Internal,
4✔
138
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::M114),
4✔
139
                true,
4✔
140
            )
4✔
141
            .await
4✔
142
            .and_then(expect_immediate)
4✔
143
            .expect("M114 OK");
4✔
144

4✔
145
        processor
4✔
146
            .execute(
4✔
147
                CommChannel::Internal,
4✔
148
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::M119),
4✔
149
                true,
4✔
150
            )
4✔
151
            .await
4✔
152
            .and_then(expect_immediate)
4✔
153
            .expect("M119 OK");
4✔
154

4✔
155
        processor
4✔
156
            .execute(
4✔
157
                CommChannel::Internal,
4✔
158
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::G),
4✔
159
                true,
4✔
160
            )
4✔
161
            .await
4✔
162
            .and_then(expect_immediate)
4✔
163
            .expect("G (list G commands) OK");
4✔
164

4✔
165
        processor
4✔
166
            .execute(
4✔
167
                CommChannel::Internal,
4✔
168
                &processing::GCodeCmd::new(
4✔
169
                    0,
4✔
170
                    None,
4✔
171
                    processing::GCodeValue::M117(Some(String::from("hello"))),
4✔
172
                ),
4✔
173
                true,
4✔
174
            )
4✔
175
            .await
4✔
176
            .and_then(expect_immediate)
4✔
177
            .expect("M117 OK");
4✔
178

4✔
179
        processor
4✔
180
            .execute(
4✔
181
                CommChannel::Internal,
4✔
182
                &processing::GCodeCmd::new(
4✔
183
                    0,
4✔
184
                    None,
4✔
185
                    processing::GCodeValue::M118(Some(String::from("hello"))),
4✔
186
                ),
4✔
187
                true,
4✔
188
            )
4✔
189
            .await
4✔
190
            .and_then(expect_immediate)
4✔
191
            .expect("M118 OK");
4✔
192

4✔
193
        hwa::info!("## {} - END", test_name);
4✔
194
    }
195

196
    // Separator
197
    hwa::info!("##");
4✔
198

199
    #[cfg(feature = "with-ps-on")]
200
    {
201
        processor
4✔
202
            .execute(
4✔
203
                CommChannel::Internal,
4✔
204
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::M81),
4✔
205
                false,
4✔
206
            )
4✔
207
            .await
4✔
208
            .and_then(expect_immediate)
4✔
209
            .expect("M81 OK");
4✔
210

4✔
211
        processor
4✔
212
            .execute(
4✔
213
                CommChannel::Internal,
4✔
214
                &processing::GCodeCmd::new(
4✔
215
                    0,
4✔
216
                    None,
4✔
217
                    processing::GCodeValue::G0(processing::FXYZ::from(make_vector_real!(
4✔
218
                        x = 1.0,
4✔
219
                        y = 1.0
4✔
220
                    ))),
4✔
221
                ),
4✔
222
                false,
4✔
223
            )
4✔
224
            .await
4✔
225
            .and_then(expect_immediate)
4✔
226
            .expect_err("must not allow moving when Power is off");
4✔
227

4✔
228
        #[cfg(feature = "with-hot-bed")]
4✔
229
        processor
4✔
230
            .execute(
4✔
231
                CommChannel::Internal,
4✔
232
                &processing::GCodeCmd::new(
4✔
233
                    0,
4✔
234
                    None,
4✔
235
                    processing::GCodeValue::M140(processing::S {
4✔
236
                        s: hwa::make_optional_real!(1.0),
4✔
237
                    }),
4✔
238
                ),
4✔
239
                false,
4✔
240
            )
4✔
241
            .await
4✔
242
            .and_then(expect_immediate)
4✔
243
            .expect_err("must not allow when Power is off");
4✔
244

4✔
245
        #[cfg(feature = "with-hot-end")]
4✔
246
        processor
4✔
247
            .execute(
4✔
248
                CommChannel::Internal,
4✔
249
                &processing::GCodeCmd::new(
4✔
250
                    0,
4✔
251
                    None,
4✔
252
                    processing::GCodeValue::M104(processing::S {
4✔
253
                        s: hwa::make_optional_real!(1.0),
4✔
254
                    }),
4✔
255
                ),
4✔
256
                false,
4✔
257
            )
4✔
258
            .await
4✔
259
            .and_then(expect_immediate)
4✔
260
            .expect_err("must not allow when Power is off");
4✔
261

4✔
262
        #[cfg(feature = "with-fan-layer")]
4✔
263
        processor
4✔
264
            .execute(
4✔
265
                CommChannel::Internal,
4✔
266
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::M106),
4✔
267
                false,
4✔
268
            )
4✔
269
            .await
4✔
270
            .and_then(expect_immediate)
4✔
271
            .expect_err("must not allow when Power is off");
4✔
272

4✔
273
        #[cfg(feature = "with-hot-end")]
4✔
274
        processor
4✔
275
            .execute(
4✔
276
                CommChannel::Internal,
4✔
277
                &processing::GCodeCmd::new(
4✔
278
                    0,
4✔
279
                    None,
4✔
280
                    processing::GCodeValue::M109(processing::S {
4✔
281
                        s: hwa::make_optional_real!(1.0),
4✔
282
                    }),
4✔
283
                ),
4✔
284
                false,
4✔
285
            )
4✔
286
            .await
4✔
287
            .and_then(expect_immediate)
4✔
288
            .expect_err("must not allow when Power is off");
4✔
289

4✔
290
        let test_name = "T2 [M80 (Power On)]";
4✔
291

4✔
292
        hwa::info!("## {} - BEGIN", test_name);
4✔
293
        processor
4✔
294
            .execute(
4✔
295
                CommChannel::Internal,
4✔
296
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::M80),
4✔
297
                false,
4✔
298
            )
4✔
299
            .await
4✔
300
            .and_then(expect_immediate)
4✔
301
            .expect("M80 OK");
4✔
302
    }
4✔
303

4✔
304
    // Separator
4✔
305
    hwa::info!("##");
4✔
306

307
    #[cfg(feature = "with-trinamic")]
308
    {
309
        let test_name = "T3 [M502 (Trinamic set)]";
4✔
310
        hwa::info!("## {} - BEGIN", test_name);
4✔
311
        processor
4✔
312
            .execute(
4✔
313
                CommChannel::Internal,
4✔
314
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::M502),
4✔
315
                false,
4✔
316
            )
4✔
317
            .await
4✔
318
            .and_then(expect_immediate)
4✔
319
            .expect("M502 OK");
4✔
320
    }
4✔
321

4✔
322
    #[cfg(feature = "with-motion")]
4✔
323
    {
4✔
324
        let test_name = "T4 [G28 (Homming)]";
4✔
325
        let homing_gcode = processing::GCodeCmd::new(
4✔
326
            0,
4✔
327
            None,
4✔
328
            processing::GCodeValue::G28(processing::EXYZ::new()),
4✔
329
        );
4✔
330

4✔
331
        hwa::info!("## {} - BEGIN", test_name);
4✔
332
        let evt = processor
4✔
333
            .execute(CommChannel::Internal, &homing_gcode, false)
4✔
334
            .await
4✔
335
            .and_then(expect_deferred)
4✔
336
            .expect("G28 OK");
4✔
337

4✔
338
        subscriber.ft_wait_for(evt).await.expect("G28 completed");
4✔
339

4✔
340
        hwa::info!("## {} - BEGIN", test_name);
4✔
341
        processor
4✔
342
            .execute(
4✔
343
                CommChannel::Internal,
4✔
344
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::G29),
4✔
345
                true,
4✔
346
            )
4✔
347
            .await
4✔
348
            .and_then(expect_immediate)
4✔
349
            .expect("G29 OK");
4✔
350
        processor
4✔
351
            .execute(
4✔
352
                CommChannel::Internal,
4✔
353
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::G29_1),
4✔
354
                true,
4✔
355
            )
4✔
356
            .await
4✔
357
            .and_then(expect_immediate)
4✔
358
            .expect("G29.1 OK");
4✔
359
        processor
4✔
360
            .execute(
4✔
361
                CommChannel::Internal,
4✔
362
                &processing::GCodeCmd::new(0, None, processing::GCodeValue::G29_2),
4✔
363
                true,
4✔
364
            )
4✔
365
            .await
4✔
366
            .and_then(expect_immediate)
4✔
367
            .expect("G29.2 OK");
4✔
368
    }
4✔
369

4✔
370
    // Separator
4✔
371
    hwa::info!("##");
4✔
372
    #[cfg(feature = "with-motion")]
373
    {
374
        let test_name = "T5 [G92 (Reset Position)]";
4✔
375
        let set_pos_gcode = processing::GCodeCmd::new(
4✔
376
            5,
4✔
377
            Some(5),
4✔
378
            processing::GCodeValue::G92(
4✔
379
                hwa::make_vector_real!(e = 0.0, x = 0.0, y = 0.0, z = 0.0).into(),
4✔
380
            ),
4✔
381
        );
4✔
382

4✔
383
        hwa::info!("## {} - BEGIN", test_name);
4✔
384
        processor
4✔
385
            .execute(CommChannel::Internal, &set_pos_gcode, false)
4✔
386
            .await
4✔
387
            .and_then(expect_immediate)
4✔
388
            .expect("G92 OK");
4✔
389
    }
4✔
390

4✔
391
    // Separator
4✔
392
    hwa::info!("##");
4✔
393
    #[cfg(feature = "with-motion")]
394
    {
395
        let test_name = "T6 [G4 (Dwell)]";
4✔
396
        let set_pos_gcode = processing::GCodeCmd::new(
4✔
397
            6,
4✔
398
            Some(6),
4✔
399
            processing::GCodeValue::G4(processing::S { s: None }),
4✔
400
        );
4✔
401

4✔
402
        hwa::info!("## {} - BEGIN", test_name);
4✔
403
        processor
4✔
404
            .execute(CommChannel::Internal, &set_pos_gcode, false)
4✔
405
            .await
4✔
406
            .and_then(expect_deferred)
4✔
407
            .expect("G4 OK");
4✔
408
    }
4✔
409

4✔
410
    // Separator
4✔
411
    hwa::info!("##");
4✔
412

413
    #[cfg(feature = "with-sd-card")]
414
    {
415
        let test_name = "T7 [M20 (List SDCard)]";
4✔
416
        let gcode = processing::GCodeCmd::new(7, Some(7), processing::GCodeValue::M20(None));
4✔
417

4✔
418
        hwa::info!("## {} - BEGIN", test_name);
4✔
419
        crate::tasks::task_control::execute(
4✔
420
            &mut processor,
4✔
421
            CommChannel::Internal,
4✔
422
            &gcode,
4✔
423
            #[cfg(feature = "with-sd-card")]
4✔
424
            &mut card_controller,
4✔
425
            #[cfg(feature = "with-print-job")]
4✔
426
            &mut printer_controller,
4✔
427
        )
4✔
428
        .await
4✔
429
        .and_then(expect_immediate)
4✔
430
        .expect("M20 OK");
4✔
431
    }
4✔
432

4✔
433
    // Separator
4✔
434
    hwa::info!("##");
4✔
435

436
    #[cfg(feature = "with-sd-card")]
437
    {
438
        let test_name = "T8 [M20 (List SDCard)]";
4✔
439
        let gcode = processing::GCodeCmd::new(
4✔
440
            8,
4✔
441
            Some(8),
4✔
442
            processing::GCodeValue::M20(Some("/dir/".to_string())),
4✔
443
        );
4✔
444

4✔
445
        hwa::info!("## {} - BEGIN", test_name);
4✔
446
        crate::tasks::task_control::execute(
4✔
447
            &mut processor,
4✔
448
            CommChannel::Internal,
4✔
449
            &gcode,
4✔
450
            #[cfg(feature = "with-sd-card")]
4✔
451
            &mut card_controller,
4✔
452
            #[cfg(feature = "with-print-job")]
4✔
453
            &mut printer_controller,
4✔
454
        )
4✔
455
        .await
4✔
456
        .and_then(expect_immediate)
4✔
457
        .expect("M20 (ListDir) OK");
4✔
458

4✔
459
        let gcode = processing::GCodeCmd::new(
4✔
460
            8,
4✔
461
            Some(8),
4✔
462
            processing::GCodeValue::M20(Some("/XXX/".to_string())),
4✔
463
        );
4✔
464

4✔
465
        crate::tasks::task_control::execute(
4✔
466
            &mut processor,
4✔
467
            CommChannel::Internal,
4✔
468
            &gcode,
4✔
469
            #[cfg(feature = "with-sd-card")]
4✔
470
            &mut card_controller,
4✔
471
            #[cfg(feature = "with-print-job")]
4✔
472
            &mut printer_controller,
4✔
473
        )
4✔
474
        .await
4✔
475
        .and_then(expect_immediate)
4✔
476
        .expect_err("M20 (ListDir missing dir) Err");
4✔
477
    }
4✔
478
    /*
4✔
479
    #[cfg(feature = "integration-test-move-ortho")]
4✔
480
    {
4✔
481
        let test_name = "T6 []";
4✔
482
        hwa::info!("Testing G1 Ortho");
4✔
483

4✔
484
        let g1_code = tasks::GCodeCmd::new(
4✔
485
            0, None,
4✔
486
            tasks::GCodeValue::G1(tasks::XYZEFS {
4✔
487
                x: Some(Real::new(10, 0)),
4✔
488
                y: None,
4✔
489
                z: None,
4✔
490
                e: None,
4✔
491
                f: None,
4✔
492
                s: None,
4✔
493
            })
4✔
494
        );
4✔
495

4✔
496
        if let Some(_evt) = params
4✔
497
            .processor
4✔
498
            .execute(CommChannel::Internal, &g1_code, false)
4✔
499
            .await
4✔
500
            .and_then(expect_immediate)
4✔
501
            .ok()
4✔
502
        {
4✔
503
            hwa::trace!("-- G1 OK");
4✔
504
        } else {
4✔
505
            hwa::error!("G1 Unexpected state");
4✔
506
            finish_task(Err(()));
4✔
507
            return;
4✔
508
        }
4✔
509
    }
4✔
510

4✔
511
    #[cfg(feature = "integration-test-move-oblique")]
4✔
512
    {
4✔
513
        let test_name = "T7 []";
4✔
514
        hwa::info!("Testing G1 Oblique");
4✔
515

4✔
516
        let g1_code = tasks::GCodeCmd::new(
4✔
517
            0, None,
4✔
518
            tasks::GCodeValue::G1(tasks::XYZEFS {
4✔
519
                x: Some(Real::new(20, 0)),
4✔
520
                y: Some(Real::new(20, 0)),
4✔
521
                z: None,
4✔
522
                e: Some(Real::new(25, 1)),
4✔
523
                f: None,
4✔
524
                s: None,
4✔
525
            })
4✔
526
        );
4✔
527

4✔
528
        if let Some(_evt) = params
4✔
529
            .processor
4✔
530
            .execute(CommChannel::Internal, &g1_code, false)
4✔
531
            .await
4✔
532
            .and_then(expect_immediate)
4✔
533
            .ok()
4✔
534
        {
4✔
535
            hwa::info!("-- G1 Oblique OK");
4✔
536
        } else {
4✔
537
            hwa::error!("G1 Unexpected state");
4✔
538
            finish_task(Err(()));
4✔
539
            return;
4✔
540
        }
4✔
541
    }
4✔
542

4✔
543
    #[cfg(feature = "integration-test-move-boundaries-1")]
4✔
544
    {
4✔
545
        let test_name = "T8 []";
4✔
546
        hwa::info!("Testing G1 boundaries (1)");
4✔
547

4✔
548
        let g1_code = GCodeCmd::new(
4✔
549
            0, None,
4✔
550
            GCodeValue::G1(XYZEFS {
4✔
551
                x: None,
4✔
552
                y: None,
4✔
553
                z: None,
4✔
554
                e: Some(Real::new(-310, 2)),
4✔
555
                f: None,
4✔
556
                s: None,
4✔
557
            })
4✔
558
        );
4✔
559

4✔
560
        if let Some(_evt) = params
4✔
561
            .processor
4✔
562
            .execute(&g1_code, false)
4✔
563
            .await
4✔
564
            .and_then(expect_immediate)
4✔
565
            .ok()
4✔
566
        {
4✔
567
            hwa::info!("-- G1 boundaries (1) OK");
4✔
568
        } else {
4✔
569
            hwa::error!("G1 Unexpected state");
4✔
570
            finish_task(Err(()));
4✔
571
            return;
4✔
572
        }
4✔
573
    }
4✔
574

4✔
575
    #[cfg(feature = "integration-test-move-boundaries")]
4✔
576
    {
4✔
577
        let test_name = "T9 []";
4✔
578
        let g1_code = tasks::GCodeCmd::new(
4✔
579
            0, None,
4✔
580
            tasks::GCodeValue::G1(tasks::XYZEFS {
4✔
581
                x: Some(Real::new(7414, 2)),
4✔
582
                y: Some(Real::new(9066, 2)),
4✔
583
                z: None,
4✔
584
                e: Some(Real::new(335, 4)),
4✔
585
                f: None,
4✔
586
                s: None,
4✔
587
            })
4✔
588
        );
4✔
589

4✔
590
        if let Some(_evt) = params
4✔
591
            .processor
4✔
592
            .execute(CommChannel::Internal, &g1_code, false)
4✔
593
            .await
4✔
594
            .and_then(expect_immediate)
4✔
595
            .ok()
4✔
596
        {
4✔
597
            hwa::info!("-- G1 boundaries (2) OK");
4✔
598
        } else {
4✔
599
            hwa::error!("G1 Unexpected state");
4✔
600
            finish_task(Err(()));
4✔
601
            return;
4✔
602
        }
4✔
603
    }
4✔
604

4✔
605
    #[cfg(feature = "integration-test-dwell")]
4✔
606
    {
4✔
607
        let test_name = "T10 []";
4✔
608
        hwa::info!("Testing G4");
4✔
609
        if let Some(evt) = params
4✔
610
            .processor
4✔
611
            .execute(CommChannel::Internal, &GCodeCmd::new(0, None, GCodeValue::G4), false)
4✔
612
            .await
4✔
613
            .and_then(expect_deferred)
4✔
614
            .ok()
4✔
615
        {
4✔
616
            subscriber.ft_wait_for(evt).await.unwrap();
4✔
617
            hwa::info!("-- G4 OK");
4✔
618
        } else {
4✔
619
            hwa::error!("G4 Unexpected state");
4✔
620
            finish_task(Err(()));
4✔
621
            return;
4✔
622
        }
4✔
623
    }
4✔
624

4✔
625
    #[cfg(feature = "integration-test-set-hotend-temp")]
4✔
626
    {
4✔
627
        let test_name = "T11 []";
4✔
628
        hwa::info!("Testing M104");
4✔
629
        let m104_cmd = GCodeCmd::new(
4✔
630
            0, None,
4✔
631
            GCodeValue::M104(XYZE {
4✔
632
                s: Some(Real::new(235, 0)),
4✔
633
            })
4✔
634
        );
4✔
635
        if !params
4✔
636
            .processor
4✔
637
            .execute(
4✔
638
                CommChannel::Internal,
4✔
639
                &m104_cmd,
4✔
640
                false,
4✔
641
            )
4✔
642
            .await
4✔
643
            .and_then(expect_immediate)
4✔
644
            .is_ok()
4✔
645
        {
4✔
646
            hwa::error!("M104: unexpected result");
4✔
647
        }
4✔
648
        hwa::info!("Testing M109 S235");
4✔
649
        let m109_cmd = GCodeCmd::new(
4✔
650
            0, None,
4✔
651
            GCodeValue::M109(S {
4✔
652
                ln: None,
4✔
653
                s: Some(Real::new(235, 0)),
4✔
654
            })
4✔
655
        );
4✔
656
        if let Some(evt) = params
4✔
657
            .processor
4✔
658
            .execute(
4✔
659
                CommChannel::Internal,
4✔
660
                &m109_cmd,
4✔
661
                false,
4✔
662
            )
4✔
663
            .await
4✔
664
            .and_then(expect_deferred)
4✔
665
            .ok()
4✔
666
        {
4✔
667
            subscriber.ft_wait_for(evt).await.unwrap();
4✔
668
        }
4✔
669
    }
4✔
670
    #[cfg(feature = "integration-test-laser-engrave")]
4✔
671
    {
4✔
672
        let test_name = "T12 []";
4✔
673
        use crate::hwa::controllers::PrinterControllerEvent;
4✔
674

4✔
675
        hwa::info!("Testing GCODE for engraving");
4✔
676
        params
4✔
677
            .printer_controller
4✔
678
            .set(PrinterControllerEvent::SetFile(CommChannel::Internal, String::from("dir/laser.g")))
4✔
679
            .await
4✔
680
            .unwrap();
4✔
681
        match embassy_time::with_timeout(
4✔
682
            embassy_time::Duration::from_secs(5),
4✔
683
            subscriber.ft_wait_for(
4✔
684
                EventStatus::containing(EventFlags::JOB_PAUSED),
4✔
685
            ),
4✔
686
        )
4✔
687
        .await
4✔
688
        {
4✔
689
            Ok(_) => {
4✔
690
                // command resume (eq: M24)
4✔
691
                params
4✔
692
                    .printer_controller
4✔
693
                    .set(PrinterControllerEvent::Resume(CommChannel::Internal))
4✔
694
                    .await
4✔
695
                    .unwrap();
4✔
696
                // wait for job completion
4✔
697
                subscriber
4✔
698
                    .ft_wait_for(EventStatus::containing(EventFlags::JOB_COMPLETED))
4✔
699
                    .await
4✔
700
                    .unwrap();
4✔
701
            }
4✔
702
            Err(_) => {
4✔
703
                hwa::error!("Timeout dispatching engraving job");
4✔
704
                finish_task(Err(()));
4✔
705
                return;
4✔
706
            }
4✔
707
        }
4✔
708
    }
4✔
709
    #[cfg(feature = "integration-test-benchy")]
4✔
710
    {
4✔
711
        let test_name = "T13 []";
4✔
712
        use crate::hwa::controllers::PrinterControllerEvent;
4✔
713

4✔
714
        hwa::info!("Testing GCODE for benchy FDM print");
4✔
715
        params
4✔
716
            .printer_controller
4✔
717
            .set(PrinterControllerEvent::SetFile(CommChannel::Internal, String::from("benchy.g")))
4✔
718
            .await
4✔
719
            .unwrap();
4✔
720
        match embassy_time::with_timeout(
4✔
721
            embassy_time::Duration::from_secs(5),
4✔
722
            subscriber.ft_wait_for(
4✔
723
                printhor_hwa_common::EventStatus::containing(EventFlags::JOB_PAUSED),
4✔
724
            ),
4✔
725
        )
4✔
726
        .await
4✔
727
        {
4✔
728
            Ok(_) => {
4✔
729
                // command resume (eq: M24)
4✔
730
                params
4✔
731
                    .printer_controller
4✔
732
                    .set(PrinterControllerEvent::Resume(CommChannel::Internal))
4✔
733
                    .await
4✔
734
                    .unwrap();
4✔
735
                // wait for job completion
4✔
736
                subscriber
4✔
737
                    .ft_wait_for(printhor_hwa_common::EventStatus::containing(
4✔
738
                        EventFlags::JOB_COMPLETED,
4✔
739
                    ))
4✔
740
                    .await
4✔
741
                    .unwrap();
4✔
742
            }
4✔
743
            Err(_) => {
4✔
744
                hwa::error!("Timeout dispatching benchy job");
4✔
745
                finish_task(Err(()));
4✔
746
                return;
4✔
747
            }
4✔
748
        }
4✔
749
    }
4✔
750
    */
4✔
751

4✔
752
    #[cfg(feature = "with-print-job")]
4✔
753
    {
4✔
754
        let test_name = "T14 [Plotting)]";
4✔
755

4✔
756
        let gcode = processing::GCodeCmd::new(
4✔
757
            8,
4✔
758
            Some(8),
4✔
759
            processing::GCodeValue::M23(Some("dir/laser.g".to_string())),
4✔
760
        );
4✔
761
        hwa::info!("## {} - BEGIN", test_name);
4✔
762
        let resp = crate::tasks::task_control::execute(
4✔
763
            &mut processor,
4✔
764
            CommChannel::Internal,
4✔
765
            &gcode,
4✔
766
            #[cfg(feature = "with-sd-card")]
4✔
767
            &mut card_controller,
4✔
768
            #[cfg(feature = "with-print-job")]
4✔
769
            &mut printer_controller,
4✔
770
        )
4✔
771
        .await;
4✔
772
        if resp.and_then(expect_immediate).is_ok() {
4✔
773
            hwa::info!("## {} - END", test_name);
4✔
774
        } else {
775
            finish_task(Err(test_name));
×
776
            return;
×
777
        }
778

779
        match embassy_time::with_timeout(
4✔
780
            embassy_time::Duration::from_secs(5),
4✔
781
            subscriber.ft_wait_for(EventStatus::containing(EventFlags::JOB_PAUSED)),
4✔
782
        )
4✔
783
        .await
4✔
784
        {
785
            Ok(_) => {
786
                // command resume (eq: M24)
787

788
                let gcode = processing::GCodeCmd::new(8, Some(8), processing::GCodeValue::M24);
4✔
789

790
                let resp = crate::tasks::task_control::execute(
4✔
791
                    &mut processor,
4✔
792
                    CommChannel::Internal,
4✔
793
                    &gcode,
4✔
794
                    #[cfg(feature = "with-sd-card")]
4✔
795
                    &mut card_controller,
4✔
796
                    #[cfg(feature = "with-print-job")]
4✔
797
                    &mut printer_controller,
4✔
798
                )
4✔
799
                .await;
4✔
800
                if resp.and_then(expect_immediate).is_ok() {
4✔
801
                    match embassy_time::with_timeout(
4✔
802
                        embassy_time::Duration::from_secs(1200),
4✔
803
                        subscriber.ft_wait_until(EventFlags::JOB_COMPLETED),
4✔
804
                    )
4✔
805
                    .await
4✔
806
                    {
807
                        Ok(_r) => {
4✔
808
                            hwa::info!("## {} - END", test_name);
4✔
809
                        }
810
                        Err(_) => {
811
                            finish_task(Err(test_name));
×
812
                            return;
×
813
                        }
814
                    }
815
                } else {
816
                    finish_task(Err(test_name));
×
817
                    return;
×
818
                }
819
            }
820
            Err(_) => {
821
                //hwa::error!("Timeout expecting pause status");
822
                finish_task(Err(test_name));
×
823
                return;
×
824
            }
825
        }
826
    }
827
    // Separator
828
    hwa::info!("##");
4✔
829

830
    #[cfg(all(
831
        feature = "with-print-job",
832
        not(feature = "anthropomorphic-quad-robot")
833
    ))]
834
    {
835
        let test_name = "T15 [Plotting 2)]";
3✔
836

3✔
837
        let gcode = processing::GCodeCmd::new(
3✔
838
            9,
3✔
839
            Some(9),
3✔
840
            processing::GCodeValue::M23(Some("dir/pen.g".to_string())),
3✔
841
        );
3✔
842
        hwa::info!("## {} - BEGIN", test_name);
3✔
843
        let resp = crate::tasks::task_control::execute(
3✔
844
            &mut processor,
3✔
845
            CommChannel::Internal,
3✔
846
            &gcode,
3✔
847
            #[cfg(feature = "with-sd-card")]
3✔
848
            &mut card_controller,
3✔
849
            #[cfg(feature = "with-print-job")]
3✔
850
            &mut printer_controller,
3✔
851
        )
3✔
852
        .await;
3✔
853
        if resp.and_then(expect_immediate).is_ok() {
3✔
854
            hwa::info!("## {} - END", test_name);
3✔
855
        } else {
856
            finish_task(Err(test_name));
×
857
            return;
×
858
        }
859

860
        match embassy_time::with_timeout(
3✔
861
            embassy_time::Duration::from_secs(5),
3✔
862
            subscriber.ft_wait_for(EventStatus::containing(EventFlags::JOB_PAUSED)),
3✔
863
        )
3✔
864
        .await
3✔
865
        {
866
            Ok(_) => {
867
                // command resume (eq: M24)
868

869
                let gcode = processing::GCodeCmd::new(10, Some(10), processing::GCodeValue::M24);
3✔
870

871
                let resp = crate::tasks::task_control::execute(
3✔
872
                    &mut processor,
3✔
873
                    CommChannel::Internal,
3✔
874
                    &gcode,
3✔
875
                    #[cfg(feature = "with-sd-card")]
3✔
876
                    &mut card_controller,
3✔
877
                    #[cfg(feature = "with-print-job")]
3✔
878
                    &mut printer_controller,
3✔
879
                )
3✔
880
                .await;
3✔
881
                if resp.and_then(expect_immediate).is_ok() {
3✔
882
                    match embassy_time::with_timeout(
3✔
883
                        embassy_time::Duration::from_secs(1200),
3✔
884
                        subscriber.ft_wait_until(EventFlags::JOB_COMPLETED),
3✔
885
                    )
3✔
886
                    .await
3✔
887
                    {
888
                        Ok(_r) => {
3✔
889
                            hwa::info!("## {} - END", test_name);
3✔
890
                        }
891
                        Err(_) => {
892
                            finish_task(Err(test_name));
×
893
                            return;
×
894
                        }
895
                    }
896
                } else {
897
                    finish_task(Err(test_name));
×
898
                    return;
×
899
                }
900
            }
901
            Err(_) => {
902
                //hwa::error!("Timeout expecting pause status");
903
                finish_task(Err(test_name));
×
904
                return;
×
905
            }
906
        }
907
    }
908

909
    // Separator
910
    hwa::info!("##");
4✔
911

912
    #[cfg(all(
913
        feature = "with-print-job",
914
        not(feature = "anthropomorphic-quad-robot")
915
    ))]
916
    {
917
        let test_name = "T16 [Benchy)]";
3✔
918

3✔
919
        hwa::info!("## {} - BEGIN", test_name);
3✔
920

921
        // Set DRY_RUN Mode
922
        let resp = crate::tasks::task_control::execute(
3✔
923
            &mut processor,
3✔
924
            CommChannel::Internal,
3✔
925
            &(processing::GCodeCmd::new(
3✔
926
                11,
3✔
927
                Some(11),
3✔
928
                processing::GCodeValue::M37(processing::S {
3✔
929
                    s: Some(Real::new(1, 0)),
3✔
930
                }),
3✔
931
            )),
3✔
932
            #[cfg(feature = "with-sd-card")]
3✔
933
            &mut card_controller,
3✔
934
            #[cfg(feature = "with-print-job")]
3✔
935
            &mut printer_controller,
3✔
936
        )
3✔
937
        .await;
3✔
938
        if resp.and_then(expect_immediate).is_ok() {
3✔
939
        } else {
3✔
940
            finish_task(Err(test_name));
×
941
            return;
×
942
        }
943

944
        let gcode = processing::GCodeCmd::new(
3✔
945
            9,
3✔
946
            Some(9),
3✔
947
            processing::GCodeValue::M23(Some("BENCHY.G".to_string())),
3✔
948
        );
3✔
949
        let resp = crate::tasks::task_control::execute(
3✔
950
            &mut processor,
3✔
951
            CommChannel::Internal,
3✔
952
            &gcode,
3✔
953
            #[cfg(feature = "with-sd-card")]
3✔
954
            &mut card_controller,
3✔
955
            #[cfg(feature = "with-print-job")]
3✔
956
            &mut printer_controller,
3✔
957
        )
3✔
958
        .await;
3✔
959
        if resp.and_then(expect_immediate).is_ok() {
3✔
960
        } else {
3✔
961
            finish_task(Err(test_name));
×
962
            return;
×
963
        }
964

965
        match embassy_time::with_timeout(
3✔
966
            embassy_time::Duration::from_secs(5),
3✔
967
            subscriber.ft_wait_for(EventStatus::containing(EventFlags::JOB_PAUSED)),
3✔
968
        )
3✔
969
        .await
3✔
970
        {
971
            Ok(_) => {
972
                // command resume (eq: M24)
973

974
                let gcode = processing::GCodeCmd::new(10, Some(10), processing::GCodeValue::M24);
3✔
975

976
                let resp = crate::tasks::task_control::execute(
3✔
977
                    &mut processor,
3✔
978
                    CommChannel::Internal,
3✔
979
                    &gcode,
3✔
980
                    #[cfg(feature = "with-sd-card")]
3✔
981
                    &mut card_controller,
3✔
982
                    #[cfg(feature = "with-print-job")]
3✔
983
                    &mut printer_controller,
3✔
984
                )
3✔
985
                .await;
3✔
986
                if resp.and_then(expect_immediate).is_ok() {
3✔
987
                    match embassy_time::with_timeout(
3✔
988
                        embassy_time::Duration::from_secs(1200),
3✔
989
                        subscriber.ft_wait_until(EventFlags::JOB_COMPLETED),
3✔
990
                    )
3✔
991
                    .await
3✔
992
                    {
993
                        Ok(_r) => {}
3✔
994
                        Err(_) => {
995
                            finish_task(Err(test_name));
×
996
                            return;
×
997
                        }
998
                    }
999
                } else {
1000
                    finish_task(Err(test_name));
×
1001
                    return;
×
1002
                }
1003
            }
1004
            Err(_) => {
1005
                //hwa::error!("Timeout expecting pause status");
1006
                finish_task(Err(test_name));
×
1007
                return;
×
1008
            }
1009
        }
1010

1011
        // Unset DRY_RUN Mode
1012
        let resp = crate::tasks::task_control::execute(
3✔
1013
            &mut processor,
3✔
1014
            CommChannel::Internal,
3✔
1015
            &(processing::GCodeCmd::new(
3✔
1016
                11,
3✔
1017
                Some(11),
3✔
1018
                processing::GCodeValue::M37(processing::S {
3✔
1019
                    s: Some(Real::new(0, 0)),
3✔
1020
                }),
3✔
1021
            )),
3✔
1022
            #[cfg(feature = "with-sd-card")]
3✔
1023
            &mut card_controller,
3✔
1024
            #[cfg(feature = "with-print-job")]
3✔
1025
            &mut printer_controller,
3✔
1026
        )
3✔
1027
        .await;
3✔
1028
        if resp.and_then(expect_immediate).is_ok() {
3✔
1029
            hwa::info!("## {} - END", test_name);
3✔
1030
        } else {
1031
            finish_task(Err(test_name));
×
1032
            return;
×
1033
        }
1034
    }
1035

1036
    // Separator
1037
    hwa::info!("##");
4✔
1038

1039
    embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await;
4✔
1040
    hwa::info!("# Integration_task END.");
4✔
1041
    finish_task(Ok(()));
4✔
1042
    cfg_if::cfg_if! {
1043
        if #[cfg(test)] {
1044
        }
1045
        else if #[cfg(feature = "native")] {
1046
            // In native simulator, we
1047
            std::process::exit(0)
1048
        }
1049
        else {
1050
            // Otherwise... lets say someone wants to do integrated tests in baremetal...
1051
            // just let the task passing away
1052
        }
1053
    }
1054
}
4✔
1055

1056
fn finish_task(success: Result<(), &'static str>) {
4✔
1057
    INTEGRATION_STATUS.signal(success.is_err());
4✔
1058
    if let Some(_msg) = success.err() {
4✔
1059
        cfg_if::cfg_if! {
1060
            if #[cfg(all(not(test), feature = "native"))] {
1061
                panic!("Test {} failed", _msg);
1062
            }
1063
            else {
1064
                hwa::error!("Test {} failed", _msg);
×
1065
            }
1066
        }
1067
    }
4✔
1068
    #[cfg(test)]
1069
    hwa::Contract::sys_stop();
4✔
1070
    // In native simulator, we need to exit
4✔
1071
}
4✔
1072

1073
#[cfg(not(feature = "s-plot-bin"))]
1074
#[cfg(test)]
1075
mod integration_test {
1076
    use crate::hwa;
1077
    use crate::tasks::task_integration::INTEGRATION_STATUS;
1078
    use std::marker::PhantomData;
1079
    use std::sync::{Condvar, Mutex};
1080

1081
    struct Signaler {
1082
        mutex: Mutex<bool>,
1083
        condvar: Condvar,
1084
    }
1085

1086
    impl Signaler {
1087
        fn new() -> Self {
4✔
1088
            Self {
4✔
1089
                mutex: Mutex::new(false),
4✔
1090
                condvar: Condvar::new(),
4✔
1091
            }
4✔
1092
        }
4✔
1093

1094
        fn wait(&self) {
321,673✔
1095
            let mut signaled = self.mutex.lock().unwrap();
321,673✔
1096
            while !*signaled {
598,484✔
1097
                signaled = self.condvar.wait(signaled).unwrap();
276,811✔
1098
            }
276,811✔
1099
            *signaled = false;
321,673✔
1100
        }
321,673✔
1101
    }
1102

1103
    pub struct MockedExecutor {
1104
        inner: embassy_executor::raw::Executor,
1105
        not_send: PhantomData<*mut ()>,
1106
        signaler: &'static Signaler,
1107
    }
1108

1109
    impl MockedExecutor {
1110
        /// Create a new Executor.
1111
        pub fn new() -> Self {
4✔
1112
            let signaler = Box::leak(Box::new(Signaler::new()));
4✔
1113
            Self {
4✔
1114
                inner: embassy_executor::raw::Executor::new(signaler as *mut Signaler as *mut ()),
4✔
1115
                not_send: PhantomData,
4✔
1116
                signaler,
4✔
1117
            }
4✔
1118
        }
4✔
1119

1120
        pub fn run(&'static mut self, init: impl FnOnce(embassy_executor::Spawner)) {
4✔
1121
            init(self.inner.spawner());
4✔
1122

1123
            loop {
1124
                unsafe { self.inner.poll() };
321,677✔
1125
                if INTEGRATION_STATUS.signaled() {
321,677✔
1126
                    break;
4✔
1127
                }
321,673✔
1128
                self.signaler.wait()
321,673✔
1129
            }
1130
        }
4✔
1131
    }
1132

1133
    /// The integration test entry-point
1134
    #[embassy_executor::task(pool_size = 1)]
4✔
1135
    async fn mocked_main(spawner: embassy_executor::Spawner) {
4✔
1136
        crate::printhor_main(spawner, false).await;
4✔
1137
        if INTEGRATION_STATUS.wait().await {
4✔
1138
            hwa::info!("Integration task Succeeded");
×
1139
        } else {
1140
            panic!("Integration task Failed");
×
1141
        }
1142
    }
×
1143

1144
    #[test]
1145
    fn do_integration_test() {
4✔
1146
        std::env::set_current_dir(std::env::current_dir().unwrap().parent().unwrap()).unwrap();
4✔
1147
        // 1. Init embassy runtime
1148
        let executor = hwa::make_static_ref!("Executor", MockedExecutor, MockedExecutor::new());
4✔
1149

4✔
1150
        // 2. Spawn the [mocked_main] task
4✔
1151
        executor.run(|spawner| {
4✔
1152
            let _tk = spawner.must_spawn(mocked_main(spawner));
4✔
1153
        });
4✔
1154
        hwa::info!("executor gone...");
4✔
1155
    }
4✔
1156
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc