use crate::display::HalDelay;
use crate::{display, pac};
use core::cell::RefCell;
use core::panic::PanicInfo;
use embedded_graphics::geometry::Point;
use embedded_graphics::mono_font::ascii::FONT_6X10;
use embedded_graphics::mono_font::MonoTextStyle;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::{Dimensions, DrawTarget, RgbColor};
use embedded_graphics::text::{Alignment, Text};
use embedded_graphics::Drawable;
use mipidsi::models::ST7789;
use mipidsi::options::{ColorInversion, Orientation};
use stm32h7xx_hal::delay::Delay;
use stm32h7xx_hal::gpio::GpioExt;
use stm32h7xx_hal::prelude::{_stm32h7xx_hal_pwr_PwrExt, _stm32h7xx_hal_rcc_RccExt};
use stm32h7xx_hal::rcc::ResetEnable;
use stm32h7xx_hal::stm32::Peripherals;
#[inline(never)]
#[panic_handler]
unsafe fn panic(info: &PanicInfo) -> ! {
handle_panic(info)
}
struct PanicData {
message: [u8; 256],
message_len: usize,
file: [u8; 64],
file_len: usize,
line: u32,
}
unsafe fn handle_panic(info: &PanicInfo) -> ! {
#[cfg(not(feature = "alloc"))]
let message = info.message().as_str();
#[cfg(feature = "alloc")]
use alloc::string::ToString;
#[cfg(feature = "alloc")]
let message = Some(info.message().to_string());
let location = info.location();
let mut panic_data = PanicData {
message: [0u8; 256],
message_len: 0,
file: [0u8; 64],
file_len: 0,
line: 10,
};
if let Some(message) = message {
let take = message.len().min(panic_data.message.len());
panic_data.message[..take].copy_from_slice(&message.as_bytes()[..take]);
panic_data.message_len = take;
}
if let Some(location) = location {
let take = location.file().len().min(panic_data.file.len());
panic_data.line = location.line();
panic_data.file[..take].copy_from_slice(&location.file().as_bytes()[..take]);
panic_data.file_len = take;
} else {
panic_data.line = u32::MAX;
}
show_panic(panic_data);
loop {}
}
unsafe fn show_panic(data: PanicData) {
cortex_m::interrupt::disable();
let cortex = cortex_m::Peripherals::steal();
let peripherals = Peripherals::steal();
let pwr = peripherals.PWR.constrain();
let pwr_cfg = pwr.freeze();
let rcc = peripherals.RCC.constrain();
let ccdr = rcc.freeze(pwr_cfg, &peripherals.SYSCFG);
let gpiob = peripherals.GPIOB.split(ccdr.peripheral.GPIOB);
let gpioc = peripherals.GPIOC.split(ccdr.peripheral.GPIOC);
let gpiog = peripherals.GPIOG.split_without_reset(ccdr.peripheral.GPIOG);
let (disp_timer, _) = pac::timers::display_timer(
&ccdr.clocks,
peripherals.TIM3,
gpiob.pb1,
gpioc.pc8,
ccdr.peripheral.TIM3,
);
let disp_pin = unsafe { pac::sram::init(peripherals.FMC, gpioc.pc7) };
ccdr.peripheral
.FMC
.kernel_clk_mux(stm32h7xx_hal::pac::rcc::d1ccipr::FMCSEL_A::Per)
.enable();
crate::DELAY = Some(RefCell::new(Delay::new(cortex.SYST, ccdr.clocks)));
let message = core::str::from_utf8(&data.message[..data.message_len])
.unwrap_or("malformed panic message");
let file = core::str::from_utf8(&data.file[..data.file_len]).unwrap_or("malformed panic file");
let mut line = [0u8; u32::MAX.ilog10() as usize + 1];
let line_len = itoa(data.line, &mut line);
let line = core::str::from_utf8(&line[..line_len]).unwrap_or("??");
let mut disp = display::AlarmoDisplay::new(
disp_timer,
disp_pin,
gpiog.pg4,
crate::DELAY.as_ref().unwrap(),
);
disp.hard_reset();
disp.set_backlight(1.0);
let mut delay = HalDelay;
let mut disp = mipidsi::Builder::new(ST7789, disp)
.invert_colors(ColorInversion::Inverted)
.orientation(Orientation {
mirrored: false,
rotation: mipidsi::options::Rotation::Deg270,
})
.init(&mut delay)
.unwrap();
disp.clear(Rgb565::BLUE).ok();
let style = MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE);
Text::with_alignment("!! PANIC !!", Point::new(160, 30), style, Alignment::Center)
.draw(&mut disp)
.ok();
let text_msg = Text::new(message, Point::new(15, 50), style);
let max_y = text_msg
.bounding_box()
.bottom_right()
.map(|p| p.y)
.unwrap_or_default();
text_msg.draw(&mut disp).ok();
Text::new(file, Point::new(15, max_y + 10), style)
.draw(&mut disp)
.ok();
Text::new(line, Point::new(15, max_y + 30), style)
.draw(&mut disp)
.ok();
}
fn itoa(mut num: u32, buf: &mut [u8]) -> usize {
if num == 0 {
buf[0] = b'0';
return 1;
}
let mut chars = 0;
while num > 0 {
buf[chars] = char::from_digit(num % 10, 10).map(|c| c as u8).unwrap();
num /= 10;
chars += 1;
}
buf[..chars].reverse();
chars
}