#![no_std]
extern crate alloc;
#[allow(unused_imports)]
use alloc::string::{String, ToString};
#[allow(unused_imports)]
use core::fmt::Write;
use vexide_core::{backtrace::Backtrace, println};
#[cfg(feature = "display_panics")]
use vexide_devices::{
color::Rgb,
geometry::Point2,
screen::{Rect, Screen, Text, TextSize},
};
#[cfg(target_arch = "wasm32")]
extern "C" {
fn sim_log_backtrace();
}
#[cfg(feature = "display_panics")]
fn draw_error(screen: &mut Screen, msg: &str, backtrace: &Backtrace) {
const ERROR_BOX_MARGIN: i16 = 16;
const ERROR_BOX_PADDING: i16 = 16;
const LINE_HEIGHT: i16 = 20;
const LINE_MAX_WIDTH: usize = 52;
screen.set_render_mode(vexide_devices::screen::RenderMode::Immediate);
fn draw_text(screen: &mut Screen, buffer: &str, line: i16) {
screen.fill(
&Text::new(
buffer,
TextSize::Small,
Point2 {
x: ERROR_BOX_MARGIN + ERROR_BOX_PADDING,
y: ERROR_BOX_MARGIN + ERROR_BOX_PADDING + (line * LINE_HEIGHT),
},
),
Rgb::WHITE,
);
}
let error_box_rect = Rect::new(
Point2 {
x: ERROR_BOX_MARGIN,
y: ERROR_BOX_MARGIN,
},
Point2 {
x: Screen::HORIZONTAL_RESOLUTION - ERROR_BOX_MARGIN,
y: Screen::VERTICAL_RESOLUTION - ERROR_BOX_MARGIN,
},
);
screen.fill(&error_box_rect, Rgb::RED);
screen.stroke(&error_box_rect, Rgb::WHITE);
let mut buffer = String::new();
let mut line: i16 = 0;
for (i, character) in msg.char_indices() {
if !character.is_ascii_control() {
buffer.push(character);
}
if character == '\n' || ((buffer.len() % LINE_MAX_WIDTH == 0) && (i > 0)) {
draw_text(screen, &buffer, line);
line += 1;
buffer.clear();
}
}
if !buffer.is_empty() {
draw_text(screen, &buffer, line);
line += 1;
}
line += 1;
draw_text(screen, "stack backtrace:", line);
line += 1;
if !backtrace.frames.is_empty() {
const ROW_LENGTH: usize = 3;
for (col, frames) in backtrace.frames.chunks(ROW_LENGTH).enumerate() {
let mut msg = String::new();
for (row, frame) in frames.iter().enumerate() {
write!(msg, "{:>3}: {:?} ", col * ROW_LENGTH + row, frame).unwrap();
}
draw_text(screen, msg.trim_end(), line);
line += 1;
}
}
}
#[panic_handler]
pub fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
println!("{info}");
let backtrace = Backtrace::capture();
#[cfg(feature = "display_panics")]
draw_error(unsafe { &mut Screen::new() }, &info.to_string(), &backtrace);
#[cfg(target_arch = "wasm32")]
unsafe {
sim_log_backtrace();
}
#[cfg(not(target_arch = "wasm32"))]
if !backtrace.frames.is_empty() {
println!("{backtrace}");
}
#[cfg(not(feature = "display_panics"))]
vexide_core::program::exit();
#[cfg(feature = "display_panics")]
loop {
unsafe {
vex_sdk::vexTasksRun();
}
}
}