pros_panic/
lib.rs

1//! Panic handler implementation for [`pros-rs`](https://crates.io/crates/pros-rs).
2//! Supports printing a backtrace when running in the simulator.
3//! If the `display_panics` feature is enabled, it will also display the panic message on the V5 Brain display.
4
5#![no_std]
6
7extern crate alloc;
8
9use alloc::{format, string::String};
10
11use pros_core::eprintln;
12#[cfg(feature = "display_panics")]
13use pros_devices::Screen;
14
15#[cfg(target_arch = "wasm32")]
16extern "C" {
17    /// Prints a backtrace to the debug console
18    fn sim_log_backtrace();
19}
20
21/// Draw an error box to the screen.
22///
23/// This function is internally used by the pros-rs panic handler for displaying
24/// panic messages graphically before exiting.
25#[cfg(feature = "display_panics")]
26fn draw_error(
27    screen: &mut pros_devices::screen::Screen,
28    msg: &str,
29) -> Result<(), pros_devices::screen::ScreenError> {
30    const ERROR_BOX_MARGIN: i16 = 16;
31    const ERROR_BOX_PADDING: i16 = 16;
32    const LINE_MAX_WIDTH: usize = 52;
33
34    let error_box_rect = pros_devices::screen::Rect::new(
35        ERROR_BOX_MARGIN,
36        ERROR_BOX_MARGIN,
37        Screen::HORIZONTAL_RESOLUTION - ERROR_BOX_MARGIN,
38        Screen::VERTICAL_RESOLUTION - ERROR_BOX_MARGIN,
39    );
40
41    screen.fill(&error_box_rect, pros_devices::color::Rgb::RED)?;
42    screen.stroke(&error_box_rect, pros_devices::color::Rgb::WHITE)?;
43
44    let mut buffer = String::new();
45    let mut line: i16 = 0;
46
47    for (i, character) in msg.char_indices() {
48        if !character.is_ascii_control() {
49            buffer.push(character);
50        }
51
52        if character == '\n' || ((buffer.len() % LINE_MAX_WIDTH == 0) && (i > 0)) {
53            screen.fill(
54                &pros_devices::screen::Text::new(
55                    buffer.as_str(),
56                    pros_devices::screen::TextPosition::Point(
57                        ERROR_BOX_MARGIN + ERROR_BOX_PADDING,
58                        ERROR_BOX_MARGIN + ERROR_BOX_PADDING + (line * Screen::LINE_HEIGHT),
59                    ),
60                    pros_devices::screen::TextFormat::Small,
61                ),
62                pros_devices::color::Rgb::WHITE,
63            )?;
64
65            line += 1;
66            buffer.clear();
67        }
68    }
69
70    screen.fill(
71        &pros_devices::screen::Text::new(
72            buffer.as_str(),
73            pros_devices::screen::TextPosition::Point(
74                ERROR_BOX_MARGIN + ERROR_BOX_PADDING,
75                ERROR_BOX_MARGIN + ERROR_BOX_PADDING + (line * Screen::LINE_HEIGHT),
76            ),
77            pros_devices::screen::TextFormat::Small,
78        ),
79        pros_devices::color::Rgb::WHITE,
80    )?;
81
82    Ok(())
83}
84
85#[panic_handler]
86/// The panic handler for pros-rs.
87pub fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
88    let current_task = pros_core::task::current();
89
90    let task_name = current_task.name().unwrap_or_else(|_| "<unknown>".into());
91
92    // task 'User Initialization (PROS)' panicked at src/lib.rs:22:1:
93    // panic message here
94    let msg = format!("task '{task_name}' {info}");
95
96    eprintln!("{msg}");
97
98    unsafe {
99        #[cfg(feature = "display_panics")]
100        draw_error(&mut Screen::new(), &msg).unwrap_or_else(|err| {
101            eprintln!("Failed to draw error message to screen: {err}");
102        });
103
104        #[cfg(target_arch = "wasm32")]
105        sim_log_backtrace();
106
107        pros_sys::exit(1);
108    }
109}