refactor(core): unify error screens

[no changelog]
pull/2879/head
tychovrahe 1 year ago committed by matejcik
parent 64bc94cbc9
commit 9b8984896e

@ -191,11 +191,11 @@ void ui_screen_done(int restart_seconds, secbool full_redraw) {
const char *str; const char *str;
char count_str[24]; char count_str[24];
if (restart_seconds >= 1) { if (restart_seconds >= 1) {
mini_snprintf(count_str, sizeof(count_str), "DONE! RESTARTING IN %d", mini_snprintf(count_str, sizeof(count_str), "RESTARTING IN %d",
restart_seconds); restart_seconds);
str = count_str; str = count_str;
} else { } else {
str = "DONE! RECONNECT THE DEVICE"; str = "RECONNECT THE DEVICE";
} }
screen_install_success(str, initial_setup, full_redraw); screen_install_success(str, initial_setup, full_redraw);

@ -17,8 +17,8 @@ uint32_t screen_intro(const char* bld_version_str, const char* vendor_str,
uint8_t vendor_str_len, const char* version_str); uint8_t vendor_str_len, const char* version_str);
uint32_t screen_menu(const char* bld_version_str); uint32_t screen_menu(const char* bld_version_str);
void screen_connect(void); void screen_connect(void);
void screen_fatal_error_c(const char* msg, const char* file); void screen_fatal_error_rust(const char* title, const char* msg,
void screen_error_shutdown_c(const char* label, const char* msg); const char* footer);
void screen_wipe_success(void); void screen_wipe_success(void);
void screen_wipe_fail(void); void screen_wipe_fail(void);
uint32_t screen_install_success(const char* reboot_msg, bool initial_setup, uint32_t screen_install_success(const char* reboot_msg, bool initial_setup,

@ -6,11 +6,6 @@ mod ffi {
} }
use crate::ui::screens::screen_fatal_error; use crate::ui::screens::screen_fatal_error;
#[cfg(not(feature = "bootloader"))]
use heapless::String;
#[cfg(not(feature = "bootloader"))]
use crate::ui::util::u32_to_str;
fn shutdown() -> ! { fn shutdown() -> ! {
unsafe { ffi::trezor_shutdown() } unsafe { ffi::trezor_shutdown() }
@ -18,22 +13,13 @@ fn shutdown() -> ! {
#[cfg(feature = "bootloader")] #[cfg(feature = "bootloader")]
pub fn __fatal_error(_expr: &str, _msg: &str, _file: &str, _line: u32, _func: &str) -> ! { pub fn __fatal_error(_expr: &str, _msg: &str, _file: &str, _line: u32, _func: &str) -> ! {
screen_fatal_error(Some("BL.rs"), "BL.rs"); screen_fatal_error("BL.rs", "BL.rs", "PLEASE VISIT\nTREZOR.IO/RSOD");
shutdown() shutdown()
} }
#[cfg(not(feature = "bootloader"))] #[cfg(not(feature = "bootloader"))]
pub fn __fatal_error(_expr: &str, msg: &str, file: &str, line: u32, _func: &str) -> ! { pub fn __fatal_error(_expr: &str, msg: &str, _file: &str, _line: u32, _func: &str) -> ! {
let mut buf: String<256> = String::new(); screen_fatal_error("FATAL ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD");
let _ = buf.push_str(file); // Nothing we can do if this fails
let _ = buf.push_str(": ");
let mut line_buf = [0u8; 10];
if let Some(text) = u32_to_str(line, &mut line_buf) {
let _ = buf.push_str(text);
}
screen_fatal_error(Some(msg), buf.as_str());
shutdown() shutdown()
} }

@ -26,64 +26,24 @@ unsafe fn get_str(text: &str) -> StrBuffer {
unsafe { StrBuffer::from_ptr_and_len(text.as_ptr(), text.len()) } unsafe { StrBuffer::from_ptr_and_len(text.as_ptr(), text.len()) }
} }
pub fn screen_fatal_error(msg: Option<&str>, file: &str) { pub fn screen_fatal_error(title: &str, msg: &str, footer: &str) {
// SAFETY: these will get placed into `frame` which does not outlive this // SAFETY: these will get placed into `frame` which does not outlive this
// function // function
let msg = msg.map(|s| unsafe { get_str(s) }); let title = unsafe { get_str(title) };
let file = unsafe { get_str(file) }; let msg = unsafe { get_str(msg) };
let footer = unsafe { get_str(footer) };
let m_top = if let Some(msg) = msg {
let mut messages = ParagraphVecShort::new(); let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_BOLD, "FATAL ERROR!".into()).centered()); messages.add(Paragraph::new(&TEXT_BOLD, title).centered());
messages.add(Paragraph::new(&TEXT_NORMAL, msg).centered()); messages.add(Paragraph::new(&TEXT_NORMAL, msg).centered());
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) let m_top =
} else {
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_BOLD, "FATAL ERROR!".into()).centered());
messages.add(Paragraph::new(&TEXT_NORMAL, file).centered());
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
};
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_BOLD, "PLEASE CONTACT".into()).centered());
messages.add(Paragraph::new(&TEXT_BOLD, "TREZOR SUPPORT".into()).centered());
let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new(WHITE, BLACK, Icon::new(ICON_FAIL), m_top, m_bottom, true);
frame.place(constant::screen());
frame.paint();
}
pub fn screen_error_shutdown(msg: Option<&str>, label: &str) {
// SAFETY: these will get placed into `frame` which does not outlive this
// function
let msg = msg.map(|s| unsafe { get_str(s) });
let label = unsafe { get_str(label) };
let m_top = if let Some(msg) = msg {
let mut messages = ParagraphVecShort::new(); let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_BOLD, label).centered()); messages.add(Paragraph::new(&TEXT_BOLD, footer).centered());
messages.add(Paragraph::new(&TEXT_NORMAL, msg).centered());
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
} else {
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_BOLD, label).centered());
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
};
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_BOLD, "PLEASE UNPLUG".into()).centered());
messages.add(Paragraph::new(&TEXT_BOLD, "THE DEVICE".into()).centered());
let m_bottom = let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());

@ -355,7 +355,7 @@ extern "C" fn screen_wipe_success() {
BLD_WIPE_CANCEL_BTN_COLOR, BLD_WIPE_CANCEL_BTN_COLOR,
Icon::new(CHECK40), Icon::new(CHECK40),
m_top, m_top,
m_bottom, Some(m_bottom),
true, true,
); );
show(&mut frame, true); show(&mut frame, true);
@ -383,7 +383,7 @@ extern "C" fn screen_wipe_fail() {
BLD_WIPE_CANCEL_BTN_COLOR, BLD_WIPE_CANCEL_BTN_COLOR,
Icon::new(WARNING40), Icon::new(WARNING40),
m_top, m_top,
m_bottom, Some(m_bottom),
true, true,
); );
show(&mut frame, true); show(&mut frame, true);
@ -433,7 +433,7 @@ extern "C" fn screen_install_fail() {
BLD_BTN_COLOR, BLD_BTN_COLOR,
Icon::new(WARNING40), Icon::new(WARNING40),
m_top, m_top,
m_bottom, Some(m_bottom),
true, true,
); );
show(&mut frame, true); show(&mut frame, true);
@ -457,7 +457,7 @@ fn screen_install_success_bld(msg: &'static str, complete_draw: bool) {
BLD_BTN_COLOR, BLD_BTN_COLOR,
Icon::new(CHECK40), Icon::new(CHECK40),
m_top, m_top,
m_bottom, Some(m_bottom),
complete_draw, complete_draw,
); );
show(&mut frame, complete_draw); show(&mut frame, complete_draw);
@ -483,7 +483,7 @@ fn screen_install_success_initial(msg: &'static str, complete_draw: bool) {
WELCOME_HIGHLIGHT_COLOR, WELCOME_HIGHLIGHT_COLOR,
Icon::new(CHECK40), Icon::new(CHECK40),
m_top, m_top,
m_bottom, Some(m_bottom),
complete_draw, complete_draw,
); );
show(&mut frame, complete_draw); show(&mut frame, complete_draw);

@ -0,0 +1,105 @@
use crate::ui::{
component::{
text::paragraphs::{ParagraphStrType, ParagraphVecShort, Paragraphs},
Child, Component, Event, EventCtx, Label, Never, Pad,
},
constant::screen,
display::{self, Icon},
geometry::{Alignment::Center, Point, Rect, TOP_CENTER},
};
use crate::ui::model_tt::{
constant::WIDTH,
theme::{
FATAL_ERROR_COLOR, FATAL_ERROR_HIGHLIGHT_COLOR, ICON_WARNING40, RESULT_FOOTER_HEIGHT,
RESULT_FOOTER_START, RESULT_PADDING, TEXT_ERROR_BOLD, WHITE,
},
};
const TITLE_AREA_START: i16 = 70;
const ICON_TOP: i16 = 27;
pub struct ErrorScreen<T> {
bg: Pad,
title: Child<Label<T>>,
message: Child<Paragraphs<ParagraphVecShort<T>>>,
footer: Child<Paragraphs<ParagraphVecShort<T>>>,
}
impl<T: ParagraphStrType> ErrorScreen<T> {
pub fn new(
title: T,
message: Paragraphs<ParagraphVecShort<T>>,
footer: Paragraphs<ParagraphVecShort<T>>,
) -> Self {
let title = Label::new(title, Center, TEXT_ERROR_BOLD);
Self {
bg: Pad::with_background(FATAL_ERROR_COLOR).with_clear(),
title: Child::new(title),
message: Child::new(message),
footer: Child::new(footer),
}
}
}
impl<T: ParagraphStrType> Component for ErrorScreen<T> {
type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect {
self.bg.place(screen());
let title_area = Rect::new(
Point::new(RESULT_PADDING, TITLE_AREA_START),
Point::new(WIDTH - RESULT_PADDING, RESULT_FOOTER_START),
);
self.title.place(title_area);
let (_, message_area) = title_area.split_top(self.title.inner().area().height());
self.message.place(message_area);
let bottom_area = Rect::new(
Point::new(RESULT_PADDING, RESULT_FOOTER_START),
Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
);
self.footer.place(bottom_area);
bounds
}
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
None
}
fn paint(&mut self) {
self.bg.paint();
let icon = Icon::new(ICON_WARNING40);
icon.draw(
Point::new(screen().center().x, ICON_TOP),
TOP_CENTER,
WHITE,
FATAL_ERROR_COLOR,
);
self.title.paint();
self.message.paint();
display::rect_fill_rounded(
Rect::new(
Point::new(RESULT_PADDING, RESULT_FOOTER_START),
Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
),
FATAL_ERROR_HIGHLIGHT_COLOR,
FATAL_ERROR_COLOR,
2,
);
self.footer.paint();
}
}

@ -5,6 +5,7 @@ mod dialog;
mod fido; mod fido;
#[rustfmt::skip] #[rustfmt::skip]
mod fido_icons; mod fido_icons;
mod error;
mod frame; mod frame;
mod hold_to_confirm; mod hold_to_confirm;
#[cfg(feature = "dma2d")] #[cfg(feature = "dma2d")]
@ -27,6 +28,7 @@ pub use button::{
}; };
pub use coinjoin_progress::CoinJoinProgress; pub use coinjoin_progress::CoinJoinProgress;
pub use dialog::{Dialog, DialogMsg, IconDialog}; pub use dialog::{Dialog, DialogMsg, IconDialog};
pub use error::ErrorScreen;
pub use fido::{FidoConfirm, FidoMsg}; pub use fido::{FidoConfirm, FidoMsg};
pub use frame::{Frame, FrameMsg, NotificationFrame}; pub use frame::{Frame, FrameMsg, NotificationFrame};
pub use hold_to_confirm::{HoldToConfirm, HoldToConfirmMsg}; pub use hold_to_confirm::{HoldToConfirm, HoldToConfirmMsg};

@ -8,17 +8,23 @@ use crate::ui::{
geometry::{Point, Rect, CENTER}, geometry::{Point, Rect, CENTER},
}; };
use crate::ui::model_tt::constant::{HEIGHT, WIDTH}; use crate::ui::model_tt::{
constant::WIDTH,
theme::{RESULT_FOOTER_HEIGHT, RESULT_FOOTER_START, RESULT_PADDING},
};
const MESSAGE_AREA_START: i16 = 82;
const ICON_CENTER_Y: i16 = 62;
pub struct ResultScreen<T> { pub struct ResultScreen<T> {
bg: Pad, bg: Pad,
small_pad: Pad, footer_pad: Pad,
fg_color: Color, fg_color: Color,
bg_color: Color, bg_color: Color,
msg_area_color: Color, msg_area_color: Color,
icon: Icon, icon: Icon,
message_top: Child<Paragraphs<ParagraphVecShort<T>>>, message: Child<Paragraphs<ParagraphVecShort<T>>>,
message_bottom: Child<Paragraphs<ParagraphVecShort<T>>>, footer: Option<Child<Paragraphs<ParagraphVecShort<T>>>>,
} }
impl<T: ParagraphStrType> ResultScreen<T> { impl<T: ParagraphStrType> ResultScreen<T> {
@ -27,25 +33,25 @@ impl<T: ParagraphStrType> ResultScreen<T> {
bg_color: Color, bg_color: Color,
msg_area_color: Color, msg_area_color: Color,
icon: Icon, icon: Icon,
message_top: Paragraphs<ParagraphVecShort<T>>, message: Paragraphs<ParagraphVecShort<T>>,
message_bottom: Paragraphs<ParagraphVecShort<T>>, footer: Option<Paragraphs<ParagraphVecShort<T>>>,
complete_draw: bool, complete_draw: bool,
) -> Self { ) -> Self {
let mut instance = Self { let mut instance = Self {
bg: Pad::with_background(bg_color), bg: Pad::with_background(bg_color),
small_pad: Pad::with_background(bg_color), footer_pad: Pad::with_background(bg_color),
fg_color, fg_color,
bg_color, bg_color,
msg_area_color, msg_area_color,
icon, icon,
message_top: Child::new(message_top), message: Child::new(message),
message_bottom: Child::new(message_bottom), footer: footer.map(Child::new),
}; };
if complete_draw { if complete_draw {
instance.bg.clear(); instance.bg.clear();
} else { } else {
instance.small_pad.clear(); instance.footer_pad.clear();
} }
instance instance
} }
@ -55,16 +61,33 @@ impl<T: ParagraphStrType> Component for ResultScreen<T> {
type Msg = Never; type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect { fn place(&mut self, bounds: Rect) -> Rect {
self.bg self.bg.place(screen());
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
self.message_top let message_arae = if let Some(footer) = &mut self.footer {
.place(Rect::new(Point::new(15, 59), Point::new(WIDTH - 15, 176))); let footer_area = Rect::new(
Point::new(RESULT_PADDING, RESULT_FOOTER_START),
let bottom_area = Rect::new(Point::new(6, 176), Point::new(WIDTH - 6, 176 + 56)); Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
);
self.footer_pad.place(footer_area);
footer.place(footer_area);
Rect::new(
Point::new(RESULT_PADDING, MESSAGE_AREA_START),
Point::new(WIDTH - RESULT_PADDING, RESULT_FOOTER_START),
)
} else {
Rect::new(
Point::new(RESULT_PADDING, MESSAGE_AREA_START),
Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
)
};
self.small_pad.place(bottom_area); self.message.place(message_arae);
self.message_bottom.place(bottom_area);
bounds bounds
} }
@ -75,21 +98,30 @@ impl<T: ParagraphStrType> Component for ResultScreen<T> {
fn paint(&mut self) { fn paint(&mut self) {
self.bg.paint(); self.bg.paint();
self.small_pad.paint(); self.footer_pad.paint();
self.icon.draw( self.icon.draw(
Point::new(screen().center().x, 45), Point::new(screen().center().x, ICON_CENTER_Y),
CENTER, CENTER,
self.fg_color, self.fg_color,
self.bg_color, self.bg_color,
); );
self.message_top.paint(); self.message.paint();
if let Some(bottom) = &mut self.footer {
display::rect_fill_rounded( display::rect_fill_rounded(
Rect::new(Point::new(6, 176), Point::new(WIDTH - 6, 176 + 56)), Rect::new(
Point::new(RESULT_PADDING, RESULT_FOOTER_START),
Point::new(
WIDTH - RESULT_PADDING,
RESULT_FOOTER_START + RESULT_FOOTER_HEIGHT,
),
),
self.msg_area_color, self.msg_area_color,
self.bg_color, self.bg_color,
2, 2,
); );
self.message_bottom.paint(); bottom.paint();
}
} }
} }

@ -5,15 +5,11 @@ use crate::ui::{
text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt}, text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt},
Component, Component,
}, },
display::Icon,
geometry::LinearPlacement, geometry::LinearPlacement,
model_tt::{ model_tt::{
component::ResultScreen, component::ErrorScreen,
constant, constant,
theme::{ theme::{TEXT_ERROR_HIGHLIGHT, TEXT_ERROR_NORMAL},
FATAL_ERROR_COLOR, FATAL_ERROR_HIGHLIGHT_COLOR, ICON_WARNING40, TEXT_ERROR_BOLD,
TEXT_ERROR_HIGHLIGHT, TEXT_ERROR_NORMAL, WHITE,
},
}, },
}; };
@ -29,87 +25,28 @@ unsafe fn get_str(text: &str) -> StrBuffer {
unsafe { StrBuffer::from_ptr_and_len(text.as_ptr(), text.len()) } unsafe { StrBuffer::from_ptr_and_len(text.as_ptr(), text.len()) }
} }
pub fn screen_fatal_error(msg: Option<&str>, file: &str) { pub fn screen_fatal_error(title: &str, msg: &str, footer: &str) {
// SAFETY: these will get placed into `frame` which does not outlive this // SAFETY: these will get placed into `frame` which does not outlive this
// function // function
let msg = msg.map(|s| unsafe { get_str(s) }); let title = unsafe { get_str(title) };
let file = unsafe { get_str(file) }; let msg = unsafe { get_str(msg) };
let footer = unsafe { get_str(footer) };
let m_top = if let Some(msg) = msg {
let mut messages = ParagraphVecShort::new(); let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "FATAL ERROR!".into()).centered());
messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, msg).centered()); messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, msg).centered());
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()) let m_top =
} else {
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "FATAL ERROR!".into()).centered());
messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, file).centered());
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
};
let mut messages = ParagraphVecShort::new();
messages.add(
Paragraph::new(
&TEXT_ERROR_HIGHLIGHT,
"PLEASE CONTACT\nTREZOR SUPPORT".into(),
)
.centered(),
);
let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new(
WHITE,
FATAL_ERROR_COLOR,
FATAL_ERROR_HIGHLIGHT_COLOR,
Icon::new(ICON_WARNING40),
m_top,
m_bottom,
true,
);
frame.place(constant::screen());
frame.paint();
}
pub fn screen_error_shutdown(label: &str, msg: Option<&str>) {
// SAFETY: these will get placed into `frame` which does not outlive this
// function
let msg = msg.map(|s| unsafe { get_str(s) });
let label = unsafe { get_str(label) };
let m_top = if let Some(msg) = msg {
let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, label).centered());
messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, msg).centered());
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
} else {
let mut messages = ParagraphVecShort::new(); let mut messages = ParagraphVecShort::new();
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, label).centered()); messages.add(Paragraph::new(&TEXT_ERROR_HIGHLIGHT, footer).centered());
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
};
let mut messages = ParagraphVecShort::new();
messages
.add(Paragraph::new(&TEXT_ERROR_HIGHLIGHT, "PLEASE UNPLUG\nTHE DEVICE".into()).centered());
let m_bottom = let m_bottom =
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center()); Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new( let mut frame = ErrorScreen::new(title, m_top, m_bottom);
WHITE,
FATAL_ERROR_COLOR,
FATAL_ERROR_HIGHLIGHT_COLOR,
Icon::new(ICON_WARNING40),
m_top,
m_bottom,
true,
);
frame.place(constant::screen()); frame.place(constant::screen());
frame.paint(); frame.paint();
} }

@ -556,6 +556,9 @@ pub const CORNER_BUTTON_SPACING: i16 = BUTTON_SPACING;
pub const INFO_BUTTON_HEIGHT: i16 = 44; pub const INFO_BUTTON_HEIGHT: i16 = 44;
pub const PIN_BUTTON_HEIGHT: i16 = 40; pub const PIN_BUTTON_HEIGHT: i16 = 40;
pub const MNEMONIC_BUTTON_HEIGHT: i16 = 52; pub const MNEMONIC_BUTTON_HEIGHT: i16 = 52;
pub const RESULT_PADDING: i16 = 6;
pub const RESULT_FOOTER_START: i16 = 178;
pub const RESULT_FOOTER_HEIGHT: i16 = 56;
pub const fn button_bar<T>(inner: T) -> FixedHeightBar<T> { pub const fn button_bar<T>(inner: T) -> FixedHeightBar<T> {
FixedHeightBar::bottom(inner, BUTTON_HEIGHT) FixedHeightBar::bottom(inner, BUTTON_HEIGHT)

@ -7,34 +7,25 @@ pub use super::model_tr::screens::*;
pub use super::model_tt::screens::*; pub use super::model_tt::screens::*;
use crate::ui::util::from_c_str; use crate::ui::util::from_c_str;
#[no_mangle] macro_rules! convert_str {
extern "C" fn screen_fatal_error_c(msg: *const cty::c_char, file: *const cty::c_char) { ($str:expr) => {
let msg = if msg.is_null() { if ($str).is_null() {
None
} else {
unsafe { from_c_str(msg) }
};
let file = if file.is_null() {
"" ""
} else { } else {
unwrap!(unsafe { from_c_str(file) }) unwrap!(unsafe { from_c_str($str) })
}
}; };
screen_fatal_error(msg, file);
} }
#[no_mangle] #[no_mangle]
extern "C" fn screen_error_shutdown_c(msg: *const cty::c_char, file: *const cty::c_char) { extern "C" fn screen_fatal_error_rust(
let msg = if msg.is_null() { title: *const cty::c_char,
None msg: *const cty::c_char,
} else { footer: *const cty::c_char,
unsafe { from_c_str(msg) } ) {
}; let title = convert_str!(title);
let file = if file.is_null() { let msg = convert_str!(msg);
"" let footer = convert_str!(footer);
} else {
unwrap!(unsafe { from_c_str(file) })
};
screen_fatal_error(msg, file); screen_fatal_error(title, msg, footer);
} }

@ -55,6 +55,31 @@ void __attribute__((noreturn)) trezor_shutdown(void) {
; ;
} }
void __attribute__((noreturn))
error_uni(const char *label, const char *msg, const char *footer) {
display_orientation(0);
#ifdef FANCY_FATAL_ERROR
screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD");
display_refresh();
#else
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
if (label) {
display_printf("%s\n", label);
}
if (msg) {
display_printf("%s\n", msg);
}
if (footer) {
display_printf("\n%s\n", footer);
}
#endif
display_backlight(255);
display_refresh();
trezor_shutdown();
}
void __attribute__((noreturn)) void __attribute__((noreturn))
__fatal_error(const char *expr, const char *msg, const char *file, int line, __fatal_error(const char *expr, const char *msg, const char *file, int line,
const char *func) { const char *func) {
@ -64,7 +89,8 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line,
#ifdef FANCY_FATAL_ERROR #ifdef FANCY_FATAL_ERROR
char buf[256] = {0}; char buf[256] = {0};
mini_snprintf(buf, sizeof(buf), "%s: %d", file, line); mini_snprintf(buf, sizeof(buf), "%s: %d", file, line);
screen_fatal_error_c(msg, buf); screen_fatal_error_rust("FATAL ERROR", msg != NULL ? msg : buf,
"PLEASE VISIT\nTREZOR.IO/RSOD");
display_refresh(); display_refresh();
#else #else
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
@ -94,8 +120,10 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line,
void __attribute__((noreturn)) void __attribute__((noreturn))
error_shutdown(const char *label, const char *msg) { error_shutdown(const char *label, const char *msg) {
display_orientation(0); display_orientation(0);
#ifdef FANCY_FATAL_ERROR #ifdef FANCY_FATAL_ERROR
screen_error_shutdown_c(label, msg);
screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD");
display_refresh(); display_refresh();
#else #else
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
@ -105,7 +133,7 @@ error_shutdown(const char *label, const char *msg) {
if (msg) { if (msg) {
display_printf("%s\n", msg); display_printf("%s\n", msg);
} }
display_printf("\nPlease unplug the device.\n"); display_printf("\nPLEASE VISIT TREZOR.IO/RSOD\n");
#endif #endif
display_backlight(255); display_backlight(255);
trezor_shutdown(); trezor_shutdown();
@ -141,7 +169,7 @@ void clear_otg_hs_memory(void) {
uint32_t __stack_chk_guard = 0; uint32_t __stack_chk_guard = 0;
void __attribute__((noreturn)) __stack_chk_fail(void) { void __attribute__((noreturn)) __stack_chk_fail(void) {
error_shutdown("Internal error", "(SS)"); error_shutdown("INTERNAL ERROR", "(SS)");
} }
uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
@ -183,11 +211,10 @@ void ensure_compatible_settings(void) {
} }
void show_wipe_code_screen(void) { void show_wipe_code_screen(void) {
error_shutdown( error_uni("WIPE CODE ENTERED", "All data has been erased from the device",
"DEVICE WIPED!", "PLEASE RECONNECT\nTHE DEVICE");
"You have entered the wipe code. All private data has been erased.");
} }
void show_pin_too_many_screen(void) { void show_pin_too_many_screen(void) {
error_shutdown("DEVICE WIPED!", error_uni("TOO MANY PIN ATTEMPTS", "All data has been erased from the device",
"Too many wrong PIN attempts. Storage has been wiped."); "PLEASE RECONNECT\nTHE DEVICE");
} }

@ -48,6 +48,32 @@ void __attribute__((noreturn)) trezor_shutdown(void) {
#define COLOR_FATAL_ERROR 0x0000 #define COLOR_FATAL_ERROR 0x0000
#endif #endif
void __attribute__((noreturn))
error_uni(const char *label, const char *msg, const char *footer) {
display_orientation(0);
#ifdef FANCY_FATAL_ERROR
screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD");
display_refresh();
#else
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
if (label) {
display_printf("%s\n", label);
}
if (msg) {
display_printf("%s\n", msg);
}
if (footer) {
display_printf("\n%s\n", footer);
}
#endif
display_backlight(255);
display_refresh();
hal_delay(3000);
trezor_shutdown();
}
void __attribute__((noreturn)) void __attribute__((noreturn))
__fatal_error(const char *expr, const char *msg, const char *file, int line, __fatal_error(const char *expr, const char *msg, const char *file, int line,
const char *func) { const char *func) {
@ -55,9 +81,15 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line,
display_backlight(255); display_backlight(255);
#ifdef FANCY_FATAL_ERROR #ifdef FANCY_FATAL_ERROR
if (msg == NULL) {
msg = "Unknown error";
char buf[256] = {0}; char buf[256] = {0};
snprintf(buf, sizeof(buf), "%s: %d", file, line); snprintf(buf, sizeof(buf), "%s: %d", file, line);
screen_fatal_error_c(msg, buf); screen_fatal_error_rust("FATAL ERROR", buf, "PLEASE VISIT\nTREZOR.IO/RSOD");
} else {
screen_fatal_error_rust("FATAL ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD");
}
display_refresh(); display_refresh();
#else #else
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
@ -96,7 +128,7 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line,
void __attribute__((noreturn)) void __attribute__((noreturn))
error_shutdown(const char *label, const char *msg) { error_shutdown(const char *label, const char *msg) {
#ifdef FANCY_FATAL_ERROR #ifdef FANCY_FATAL_ERROR
screen_error_shutdown_c(label, msg); screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD");
display_refresh(); display_refresh();
#else #else
display_clear(); display_clear();
@ -176,11 +208,10 @@ uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
void collect_hw_entropy(void) { memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); } void collect_hw_entropy(void) { memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); }
void show_wipe_code_screen(void) { void show_wipe_code_screen(void) {
error_shutdown( error_uni("WIPE CODE ENTERED", "All data has been erased from the device",
"DEVICE WIPED!", "PLEASE RECONNECT\nTHE DEVICE");
"You have entered the wipe code. All private data has been erased.");
} }
void show_pin_too_many_screen(void) { void show_pin_too_many_screen(void) {
error_shutdown("DEVICE WIPED!", error_uni("TOO MANY PIN ATTEMPTS", "All data has been erased from the device",
"Too many wrong PIN attempts. Storage has been wiped."); "PLEASE RECONNECT\nTHE DEVICE");
} }

Loading…
Cancel
Save