vexide_core/
program.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//! Functions for modifying the state of the current
//! user program.

use core::{convert::Infallible, fmt::Debug, time::Duration};

use vex_sdk::{vexSerialWriteFree, vexSystemExitRequest, vexTasksRun};

use crate::{io, time::Instant};

/// A trait that can be implemented for arbitrary return types in the main function.
pub trait Termination {
    /// Run specific termination logic.
    /// Unlike in the standard library, this function does not return a status code.
    fn report(self);
}
impl Termination for () {
    fn report(self) {}
}
impl Termination for ! {
    fn report(self) {}
}
impl Termination for Infallible {
    fn report(self) {}
}
impl<T: Termination, E: Debug> Termination for Result<T, E> {
    fn report(self) {
        match self {
            Ok(t) => t.report(),
            Err(e) => io::println!("Error: {e:?}"),
        }
    }
}

const FLUSH_TIMEOUT: Duration = Duration::from_millis(15);

/// Exits the program using vexSystemExitRequest.
/// This function will not instantly exit the program,
/// but will instead wait up to 15mS to force the serial buffer to flush.
pub fn exit() -> ! {
    let exit_time = Instant::now();

    unsafe {
        // Force the serial buffer to flush
        while exit_time.elapsed() < FLUSH_TIMEOUT {
            vexTasksRun();

            // If the buffer has been fully flushed, exit the loop
            if vexSerialWriteFree(io::STDIO_CHANNEL) == (io::Stdout::INTERNAL_BUFFER_SIZE as i32) {
                break;
            }
        }

        // Request program exit.
        vexSystemExitRequest();

        // Loop while vexos decides what to do with our exit request.
        loop {
            vexTasksRun();
        }
    }
}