diff --git a/core/embed/rust/rust_ui.h b/core/embed/rust/rust_ui.h index 5f2ff97e1c..d2cc626f99 100644 --- a/core/embed/rust/rust_ui.h +++ b/core/embed/rust/rust_ui.h @@ -1,34 +1,5 @@ #include #include "common.h" - -uint32_t screen_install_confirm(const char* vendor_str, uint8_t vendor_str_len, - const char* version_str, - const uint8_t* fingerprint, - bool should_keep_seed, bool is_newvendor, - int version_cmp); -uint32_t screen_wipe_confirm(void); -void screen_install_progress(int16_t progress, bool initialize, - bool initial_setup); -void screen_wipe_progress(int16_t progress, bool initialize); -uint32_t screen_intro(const char* bld_version_str, const char* vendor_str, - uint8_t vendor_str_len, const char* version_str, - bool fw_ok); -uint32_t screen_menu(secbool firmware_present); -void screen_connect(bool initial_setup); -void screen_fatal_error_rust(const char* title, const char* msg, - const char* footer); -void screen_wipe_success(void); -void screen_wipe_fail(void); -uint32_t screen_install_success(uint8_t restart_seconds, bool initial_setup, - bool complete_draw); -uint32_t screen_install_fail(void); -void screen_welcome(void); -void screen_boot_empty(bool fading); -void screen_boot_full(void); -uint32_t screen_unlock_bootloader_confirm(void); -void screen_unlock_bootloader_success(void); -void display_image(int16_t x, int16_t y, const uint8_t* data, uint32_t datalen); -void display_icon(int16_t x, int16_t y, const uint8_t* data, uint32_t datalen, - uint16_t fg_color, uint16_t bg_color); -void bld_continue_label(uint16_t bg_color); +#include "rust_ui_bootloader.h" +#include "rust_ui_common.h" diff --git a/core/embed/rust/rust_ui_bootloader.h b/core/embed/rust/rust_ui_bootloader.h new file mode 100644 index 0000000000..e016591e23 --- /dev/null +++ b/core/embed/rust/rust_ui_bootloader.h @@ -0,0 +1,26 @@ +#include "common.h" + +uint32_t screen_install_confirm(const char* vendor_str, uint8_t vendor_str_len, + const char* version_str, + const uint8_t* fingerprint, + bool should_keep_seed, bool is_newvendor, + int version_cmp); +uint32_t screen_wipe_confirm(void); +void screen_install_progress(int16_t progress, bool initialize, + bool initial_setup); +void screen_wipe_progress(int16_t progress, bool initialize); +uint32_t screen_intro(const char* bld_version_str, const char* vendor_str, + uint8_t vendor_str_len, const char* version_str, + bool fw_ok); +uint32_t screen_menu(secbool firmware_present); +void screen_connect(bool initial_setup); +void screen_wipe_success(void); +void screen_wipe_fail(void); +uint32_t screen_install_success(uint8_t restart_seconds, bool initial_setup, + bool complete_draw); +uint32_t screen_install_fail(void); +void screen_welcome(void); +void screen_boot_empty(bool fading); +uint32_t screen_unlock_bootloader_confirm(void); +void screen_unlock_bootloader_success(void); +void bld_continue_label(uint16_t bg_color); diff --git a/core/embed/rust/rust_ui_common.h b/core/embed/rust/rust_ui_common.h new file mode 100644 index 0000000000..4569f4c6c8 --- /dev/null +++ b/core/embed/rust/rust_ui_common.h @@ -0,0 +1,10 @@ +#include "common.h" + +void screen_fatal_error_rust(const char* title, const char* msg, + const char* footer); + +void screen_boot_full(void); + +void display_image(int16_t x, int16_t y, const uint8_t* data, uint32_t datalen); +void display_icon(int16_t x, int16_t y, const uint8_t* data, uint32_t datalen, + uint16_t fg_color, uint16_t bg_color); diff --git a/core/embed/rust/src/trezorhal/fatal_error.rs b/core/embed/rust/src/trezorhal/fatal_error.rs index b5ba27bf49..b9227bc220 100644 --- a/core/embed/rust/src/trezorhal/fatal_error.rs +++ b/core/embed/rust/src/trezorhal/fatal_error.rs @@ -5,7 +5,7 @@ mod ffi { } } -use crate::ui::screens::screen_fatal_error; +use crate::ui::ui_features::{ModelUI, UIFeaturesCommon}; fn shutdown() -> ! { unsafe { ffi::trezor_shutdown() } @@ -13,13 +13,13 @@ fn shutdown() -> ! { #[cfg(feature = "bootloader")] pub fn __fatal_error(_expr: &str, _msg: &str, _file: &str, _line: u32, _func: &str) -> ! { - screen_fatal_error("BL.rs", "BL.rs", "PLEASE VISIT\nTREZOR.IO/RSOD"); + ModelUI::screen_fatal_error("BL.rs", "BL.rs", "PLEASE VISIT\nTREZOR.IO/RSOD"); shutdown() } #[cfg(not(feature = "bootloader"))] pub fn __fatal_error(_expr: &str, msg: &str, _file: &str, _line: u32, _func: &str) -> ! { - screen_fatal_error("INTERNAL_ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + ModelUI::screen_fatal_error("INTERNAL_ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); shutdown() } diff --git a/core/embed/rust/src/ui/api/bootloader_c.rs b/core/embed/rust/src/ui/api/bootloader_c.rs new file mode 100644 index 0000000000..2117b464ee --- /dev/null +++ b/core/embed/rust/src/ui/api/bootloader_c.rs @@ -0,0 +1,127 @@ +use crate::{ + strutil::hexlify, + trezorhal::secbool::secbool, + ui::{ + ui_features::{ModelUI, UIFeaturesBootloader}, + util::{from_c_array, from_c_str}, + }, +}; + +#[no_mangle] +extern "C" fn screen_welcome() { + ModelUI::screen_welcome(); +} + +#[no_mangle] +extern "C" fn bld_continue_label(bg_color: cty::uint16_t) { + ModelUI::bld_continue_label(bg_color.into()); +} + +#[no_mangle] +extern "C" fn screen_install_success( + restart_seconds: u8, + initial_setup: bool, + complete_draw: bool, +) { + ModelUI::screen_install_success(restart_seconds, initial_setup, complete_draw); +} + +#[no_mangle] +extern "C" fn screen_install_fail() { + ModelUI::screen_install_fail(); +} + +#[no_mangle] +extern "C" fn screen_install_confirm( + vendor_str: *const cty::c_char, + vendor_str_len: u8, + version: *const cty::c_char, + fingerprint: *const cty::uint8_t, + should_keep_seed: bool, + is_newvendor: bool, + version_cmp: cty::c_int, +) -> u32 { + let text = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) }); + let version = unwrap!(unsafe { from_c_str(version) }); + + let mut fingerprint_buffer: [u8; 64] = [0; 64]; + let fingerprint_str = unsafe { + let fingerprint_slice = core::slice::from_raw_parts(fingerprint, 32); + hexlify(fingerprint_slice, &mut fingerprint_buffer); + core::str::from_utf8_unchecked(fingerprint_buffer.as_ref()) + }; + + ModelUI::screen_install_confirm( + text, + version, + fingerprint_str, + should_keep_seed, + is_newvendor, + version_cmp, + ) +} + +#[no_mangle] +extern "C" fn screen_wipe_confirm() -> u32 { + ModelUI::screen_wipe_confirm() +} + +#[no_mangle] +extern "C" fn screen_unlock_bootloader_confirm() -> u32 { + ModelUI::screen_unlock_bootloader_confirm() +} + +#[no_mangle] +extern "C" fn screen_unlock_bootloader_success() { + ModelUI::screen_unlock_bootloader_success(); +} + +#[no_mangle] +extern "C" fn screen_menu(firmware_present: secbool) -> u32 { + ModelUI::screen_menu(firmware_present) +} + +#[no_mangle] +extern "C" fn screen_intro( + bld_version: *const cty::c_char, + vendor_str: *const cty::c_char, + vendor_str_len: u8, + version: *const cty::c_char, + fw_ok: bool, +) -> u32 { + let vendor = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) }); + let version = unwrap!(unsafe { from_c_str(version) }); + let bld_version = unwrap!(unsafe { from_c_str(bld_version) }); + + ModelUI::screen_intro(bld_version, vendor, version, fw_ok) +} + +#[no_mangle] +extern "C" fn screen_boot_empty(fading: bool) { + ModelUI::screen_boot_empty(fading) +} + +#[no_mangle] +extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) { + ModelUI::screen_wipe_progress(progress, initialize) +} + +#[no_mangle] +extern "C" fn screen_install_progress(progress: u16, initialize: bool, initial_setup: bool) { + ModelUI::screen_install_progress(progress, initialize, initial_setup) +} + +#[no_mangle] +extern "C" fn screen_connect(initial_setup: bool) { + ModelUI::screen_connect(initial_setup) +} + +#[no_mangle] +extern "C" fn screen_wipe_success() { + ModelUI::screen_wipe_success() +} + +#[no_mangle] +extern "C" fn screen_wipe_fail() { + ModelUI::screen_wipe_fail() +} diff --git a/core/embed/rust/src/ui/api/common_c.rs b/core/embed/rust/src/ui/api/common_c.rs new file mode 100644 index 0000000000..748b02a605 --- /dev/null +++ b/core/embed/rust/src/ui/api/common_c.rs @@ -0,0 +1,60 @@ +//! Reexporting the `screens` module according to the +//! current feature (Trezor model) + +use crate::ui::{ + component::image::Image, + display::{Color, Icon}, + geometry::{Alignment2D, Point}, + ui_features::{ModelUI, UIFeaturesCommon}, +}; + +use crate::ui::util::from_c_str; + +#[no_mangle] +extern "C" fn screen_fatal_error_rust( + title: *const cty::c_char, + msg: *const cty::c_char, + footer: *const cty::c_char, +) { + let title = unsafe { from_c_str(title) }.unwrap_or(""); + let msg = unsafe { from_c_str(msg) }.unwrap_or(""); + let footer = unsafe { from_c_str(footer) }.unwrap_or(""); + + ModelUI::screen_fatal_error(title, msg, footer); +} + +#[no_mangle] +extern "C" fn screen_boot_full() { + ModelUI::screen_boot_full(); +} + +#[no_mangle] +extern "C" fn display_icon( + x: cty::int16_t, + y: cty::int16_t, + data: *const cty::uint8_t, + data_len: cty::uint32_t, + fg_color: cty::uint16_t, + bg_color: cty::uint16_t, +) { + let data_slice = unsafe { core::slice::from_raw_parts(data, data_len as usize) }; + let icon = Icon::new(data_slice); + icon.draw( + Point::new(x, y), + Alignment2D::TOP_LEFT, + Color::from_u16(fg_color), + Color::from_u16(bg_color), + ); +} + +#[no_mangle] +extern "C" fn display_image( + x: cty::int16_t, + y: cty::int16_t, + data: *const cty::uint8_t, + data_len: cty::uint32_t, +) { + let data_slice = unsafe { core::slice::from_raw_parts(data, data_len as usize) }; + let image = Image::new(data_slice); + image.draw(Point::new(x, y), Alignment2D::TOP_LEFT); +} diff --git a/core/embed/rust/src/ui/api/mod.rs b/core/embed/rust/src/ui/api/mod.rs new file mode 100644 index 0000000000..52ae91db0b --- /dev/null +++ b/core/embed/rust/src/ui/api/mod.rs @@ -0,0 +1,4 @@ +pub mod common_c; + +#[cfg(feature = "bootloader")] +pub mod bootloader_c; diff --git a/core/embed/rust/src/ui/display/toif.rs b/core/embed/rust/src/ui/display/toif.rs index 1f2bcff8d6..150394573b 100644 --- a/core/embed/rust/src/ui/display/toif.rs +++ b/core/embed/rust/src/ui/display/toif.rs @@ -117,18 +117,6 @@ pub fn render_toif(toif: &Toif, center: Point, fg_color: Color, bg_color: Color) pixeldata_dirty(); } -#[no_mangle] -extern "C" fn display_image( - x: cty::int16_t, - y: cty::int16_t, - data: *const cty::uint8_t, - data_len: cty::uint32_t, -) { - let data_slice = unsafe { core::slice::from_raw_parts(data, data_len as usize) }; - let image = Image::new(data_slice); - image.draw(Point::new(x, y), Alignment2D::TOP_LEFT); -} - #[cfg(feature = "dma2d")] pub fn image(image: &Image, center: Point) { let r = Rect::from_center_and_size(center, image.toif.size()); @@ -303,25 +291,6 @@ impl<'i> Toif<'i> { } } -#[no_mangle] -extern "C" fn display_icon( - x: cty::int16_t, - y: cty::int16_t, - data: *const cty::uint8_t, - data_len: cty::uint32_t, - fg_color: cty::uint16_t, - bg_color: cty::uint16_t, -) { - let data_slice = unsafe { core::slice::from_raw_parts(data, data_len as usize) }; - let icon = Icon::new(data_slice); - icon.draw( - Point::new(x, y), - Alignment2D::TOP_LEFT, - Color::from_u16(fg_color), - Color::from_u16(bg_color), - ); -} - #[derive(PartialEq, Eq, Clone, Copy)] pub struct Icon { pub toif: Toif<'static>, diff --git a/core/embed/rust/src/ui/layout/simplified.rs b/core/embed/rust/src/ui/layout/simplified.rs index e6c9a11fb6..412d644444 100644 --- a/core/embed/rust/src/ui/layout/simplified.rs +++ b/core/embed/rust/src/ui/layout/simplified.rs @@ -9,22 +9,11 @@ use crate::ui::event::TouchEvent; use crate::ui::{ component::{Component, Event, EventCtx, Never}, display, - geometry::Rect, + ui_features::ModelUI, + UIFeaturesCommon, }; use num_traits::ToPrimitive; -pub trait SimplifiedFeatures { - fn fadein() {} - fn fadeout() {} - - const SCREEN: Rect; -} - -#[cfg(all(feature = "model_tr", not(feature = "model_tt")))] -pub type ModelFeatures = crate::ui::model_tr::ModelTRFeatures; -#[cfg(feature = "model_tt")] -pub type ModelFeatures = crate::ui::model_tt::ModelTTFeatures; - pub trait ReturnToC { fn return_to_c(self) -> u32; } @@ -79,12 +68,12 @@ where F: Component, F::Msg: ReturnToC, { - frame.place(ModelFeatures::SCREEN); - ModelFeatures::fadeout(); + frame.place(ModelUI::SCREEN); + ModelUI::fadeout(); display::sync(); frame.paint(); display::refresh(); - ModelFeatures::fadein(); + ModelUI::fadein(); #[cfg(feature = "button")] while button_eval().is_some() {} @@ -115,14 +104,14 @@ pub fn show(frame: &mut F, fading: bool) where F: Component, { - frame.place(ModelFeatures::SCREEN); + frame.place(ModelUI::SCREEN); if fading { - ModelFeatures::fadeout() + ModelUI::fadeout() }; display::sync(); frame.paint(); display::refresh(); if fading { - ModelFeatures::fadein() + ModelUI::fadein() }; } diff --git a/core/embed/rust/src/ui/mod.rs b/core/embed/rust/src/ui/mod.rs index 1838eef23f..9152755bc5 100644 --- a/core/embed/rust/src/ui/mod.rs +++ b/core/embed/rust/src/ui/mod.rs @@ -8,13 +8,16 @@ pub mod display; pub mod event; pub mod geometry; pub mod lerp; -pub mod screens; #[macro_use] pub mod util; pub mod layout; +mod api; #[cfg(feature = "model_tr")] pub mod model_tr; #[cfg(feature = "model_tt")] pub mod model_tt; +pub mod ui_features; + +pub use ui_features::UIFeaturesCommon; diff --git a/core/embed/rust/src/ui/model_tr/bootloader/mod.rs b/core/embed/rust/src/ui/model_tr/bootloader/mod.rs index 04eae0d2e6..3941e067e9 100644 --- a/core/embed/rust/src/ui/model_tr/bootloader/mod.rs +++ b/core/embed/rust/src/ui/model_tr/bootloader/mod.rs @@ -1,7 +1,6 @@ use heapless::String; use crate::{ - strutil::hexlify, trezorhal::secbool::secbool, ui::{ component::{connect::Connect, Label, LineBreaking::BreakWordsNoHyphen}, @@ -10,7 +9,6 @@ use crate::{ display::{self, Color, Font, Icon}, geometry::{Alignment2D, Offset, Point, Rect}, layout::simplified::{run, show, ReturnToC}, - util::{from_c_array, from_c_str}, }, }; @@ -23,12 +21,14 @@ use super::{ bootloader::{BLD_BG, BLD_FG, ICON_ALERT, ICON_SPINNER, ICON_SUCCESS}, ICON_ARM_LEFT, ICON_ARM_RIGHT, TEXT_BOLD, TEXT_NORMAL, WHITE, }, + ModelTRFeatures, }; mod intro; mod menu; mod welcome; +use crate::ui::ui_features::UIFeaturesBootloader; use intro::Intro; use menu::Menu; use welcome::Welcome; @@ -41,285 +41,249 @@ impl ReturnToC for ConfirmMsg { } } -#[no_mangle] -extern "C" fn screen_install_confirm( - vendor_str: *const cty::c_char, - vendor_str_len: u8, - version: *const cty::c_char, - fingerprint: *const cty::uint8_t, - should_keep_seed: bool, - is_newvendor: bool, - version_cmp: cty::c_int, -) -> u32 { - let text = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) }); - let version = unwrap!(unsafe { from_c_str(version) }); +impl ModelTRFeatures { + fn screen_progress( + text: &str, + text2: &str, + progress: u16, + initialize: bool, + fg_color: Color, + bg_color: Color, + icon: Option<(Icon, Color)>, + ) { + if initialize { + display::rect_fill(SCREEN, bg_color); + } - let mut fingerprint_buffer: [u8; 64] = [0; 64]; - let fingerprint_str = unsafe { - let fingerprint_slice = core::slice::from_raw_parts(fingerprint, 32); - hexlify(fingerprint_slice, &mut fingerprint_buffer); - core::str::from_utf8_unchecked(fingerprint_buffer.as_ref()) - }; + let progress = if progress < 20 { 20 } else { progress }; - let mut version_str: BootloaderString = String::new(); - unwrap!(version_str.push_str("Firmware version ")); - unwrap!(version_str.push_str(version)); - unwrap!(version_str.push_str("\nby ")); - unwrap!(version_str.push_str(text)); + display::rect_rounded2_partial( + Rect::new( + SCREEN.top_center() + Offset::new(-9, 3), + SCREEN.top_center() + Offset::new(9, 18 + 3), + ), + fg_color, + bg_color, + ((100_u32 * progress as u32) / 1000) as _, + icon, + ); + display::text_center( + SCREEN.center() + Offset::y(8), + text, + Font::BOLD, + fg_color, + bg_color, + ); + display::text_center( + SCREEN.center() + Offset::y(20), + text2, + Font::BOLD, + fg_color, + bg_color, + ); - let title_str = if is_newvendor { - "CHANGE FW VENDOR" - } else if version_cmp > 0 { - "UPDATE FIRMWARE" - } else if version_cmp == 0 { - "REINSTALL FW" - } else { - "DOWNGRADE FW" - }; - - let message = Label::left_aligned(version_str.as_str(), TEXT_NORMAL).vertically_centered(); - let fingerprint = Label::left_aligned( - fingerprint_str, - TEXT_NORMAL.with_line_breaking(BreakWordsNoHyphen), - ) - .vertically_centered(); - - let alert = - (!should_keep_seed).then_some(Label::left_aligned("Seed will be erased!", TEXT_NORMAL)); - - let mut frame = Confirm::new(BLD_BG, title_str, message, alert, "INSTALL", false) - .with_info_screen("FW FINGERPRINT", fingerprint); - run(&mut frame) + display::refresh(); + } } -#[no_mangle] -extern "C" fn screen_wipe_confirm() -> u32 { - let message = - Label::left_aligned("Seed and firmware will be erased!", TEXT_NORMAL).vertically_centered(); - - let mut frame = Confirm::new(BLD_BG, "FACTORY RESET", message, None, "RESET", false); - - run(&mut frame) -} - -#[no_mangle] -extern "C" fn screen_unlock_bootloader_confirm() -> u32 { - let message = - Label::left_aligned("This action cannot be undone!", TEXT_NORMAL).vertically_centered(); - - let mut frame = Confirm::new(BLD_BG, "UNLOCK BOOTLOADER?", message, None, "UNLOCK", true); - - run(&mut frame) -} - -#[no_mangle] -extern "C" fn screen_unlock_bootloader_success() { - let title = Label::centered("Bootloader unlocked", TEXT_BOLD).vertically_centered(); - - let content = - Label::centered("Please reconnect the\ndevice", TEXT_NORMAL).vertically_centered(); - - let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SPINNER, title, content, true); - show(&mut frame, false); -} - -#[no_mangle] -extern "C" fn screen_menu(firmware_present: secbool) -> u32 { - run(&mut Menu::new(firmware_present)) -} - -#[no_mangle] -extern "C" fn screen_intro( - bld_version: *const cty::c_char, - vendor_str: *const cty::c_char, - vendor_str_len: u8, - version: *const cty::c_char, - fw_ok: bool, -) -> u32 { - let vendor = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) }); - let version = unwrap!(unsafe { from_c_str(version) }); - let bld_version = unwrap!(unsafe { from_c_str(bld_version) }); - - let mut title_str: BootloaderString = String::new(); - unwrap!(title_str.push_str("BOOTLOADER ")); - unwrap!(title_str.push_str(bld_version)); - - let mut version_str: BootloaderString = String::new(); - unwrap!(version_str.push_str("Firmware version ")); - unwrap!(version_str.push_str(version)); - unwrap!(version_str.push_str("\nby ")); - unwrap!(version_str.push_str(vendor)); - - let mut frame = Intro::new(title_str.as_str(), version_str.as_str(), fw_ok); - run(&mut frame) -} - -fn screen_progress( - text: &str, - text2: &str, - progress: u16, - initialize: bool, - fg_color: Color, - bg_color: Color, - icon: Option<(Icon, Color)>, -) { - if initialize { - display::rect_fill(SCREEN, bg_color); +impl UIFeaturesBootloader for ModelTRFeatures { + fn screen_welcome() { + let mut frame = Welcome::new(); + show(&mut frame, true); } - let progress = if progress < 20 { 20 } else { progress }; - - display::rect_rounded2_partial( - Rect::new( - SCREEN.top_center() + Offset::new(-9, 3), - SCREEN.top_center() + Offset::new(9, 18 + 3), - ), - fg_color, - bg_color, - ((100_u32 * progress as u32) / 1000) as _, - icon, - ); - display::text_center( - SCREEN.center() + Offset::y(8), - text, - Font::BOLD, - fg_color, - bg_color, - ); - display::text_center( - SCREEN.center() + Offset::y(20), - text2, - Font::BOLD, - fg_color, - bg_color, - ); - - display::refresh(); -} - -#[no_mangle] -extern "C" fn screen_install_progress(progress: u16, initialize: bool, _initial_setup: bool) { - screen_progress( - "Installing", - "firmware", - progress, - initialize, - BLD_FG, - BLD_BG, - Some((ICON_SUCCESS, BLD_FG)), - ); -} - -#[no_mangle] -extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) { - screen_progress( - "Resetting", - "Trezor", - progress, - initialize, - BLD_FG, - BLD_BG, - Some((ICON_SUCCESS, BLD_FG)), - ); -} - -#[no_mangle] -extern "C" fn screen_connect(_initial_setup: bool) { - let mut frame = Connect::new("Waiting for host...", BLD_FG, BLD_BG); - show(&mut frame, false); -} - -#[no_mangle] -extern "C" fn screen_wipe_success() { - let title = Label::centered("Trezor Reset", TEXT_BOLD).vertically_centered(); - - let content = - Label::centered("Please reconnect\nthe device", TEXT_NORMAL).vertically_centered(); - - let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SPINNER, title, content, true); - show(&mut frame, false); -} - -#[no_mangle] -extern "C" fn screen_wipe_fail() { - let title = Label::centered("Reset failed", TEXT_BOLD).vertically_centered(); - - let content = - Label::centered("Please reconnect\nthe device", TEXT_NORMAL).vertically_centered(); - - let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_ALERT, title, content, true); - show(&mut frame, false); -} - -#[no_mangle] -extern "C" fn screen_boot_empty(_fading: bool) { - display::rect_fill(SCREEN, BLD_BG); - - let mut frame = WelcomeScreen::new(true); - show(&mut frame, false); -} - -#[no_mangle] -extern "C" fn screen_install_fail() { - let title = Label::centered("Install failed", TEXT_BOLD).vertically_centered(); - - let content = - Label::centered("Please reconnect\nthe device", TEXT_NORMAL).vertically_centered(); - - let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_ALERT, title, content, true); - show(&mut frame, false); -} - -#[no_mangle] -extern "C" fn screen_install_success( - restart_seconds: u8, - _initial_setup: bool, - complete_draw: bool, -) { - let mut reboot_msg = BootloaderString::new(); - - if restart_seconds >= 1 { - unwrap!(reboot_msg.push_str("Restarting in ")); - // in practice, restart_seconds is 5 or less so this is fine - let seconds_char = b'0' + restart_seconds % 10; - unwrap!(reboot_msg.push(seconds_char as char)); - } else { - unwrap!(reboot_msg.push_str("Reconnect the device")); + fn bld_continue_label(bg_color: Color) { + display::text_center( + Point::new(constant::WIDTH / 2, HEIGHT - 2), + "CONTINUE", + Font::NORMAL, + WHITE, + bg_color, + ); + ICON_ARM_LEFT.draw( + Point::new(constant::WIDTH / 2 - 36, HEIGHT - 6), + Alignment2D::TOP_LEFT, + WHITE, + bg_color, + ); + ICON_ARM_RIGHT.draw( + Point::new(constant::WIDTH / 2 + 25, HEIGHT - 6), + Alignment2D::TOP_LEFT, + WHITE, + bg_color, + ); } - let title = Label::centered("Firmware installed", TEXT_BOLD).vertically_centered(); + fn screen_install_success(restart_seconds: u8, _initial_setup: bool, complete_draw: bool) { + let mut reboot_msg = BootloaderString::new(); - let content = Label::centered(reboot_msg.as_str(), TEXT_NORMAL).vertically_centered(); + if restart_seconds >= 1 { + unwrap!(reboot_msg.push_str("Restarting in ")); + // in practice, restart_seconds is 5 or less so this is fine + let seconds_char = b'0' + restart_seconds % 10; + unwrap!(reboot_msg.push(seconds_char as char)); + } else { + unwrap!(reboot_msg.push_str("Reconnect the device")); + } - let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SPINNER, title, content, complete_draw); - show(&mut frame, false); -} - -#[no_mangle] -extern "C" fn screen_welcome() { - let mut frame = Welcome::new(); - show(&mut frame, false); -} - -#[no_mangle] -extern "C" fn bld_continue_label(bg_color: cty::uint16_t) { - display::text_center( - Point::new(constant::WIDTH / 2, HEIGHT - 2), - "CONTINUE", - Font::NORMAL, - WHITE, - Color::from_u16(bg_color), - ); - ICON_ARM_LEFT.draw( - Point::new(constant::WIDTH / 2 - 36, HEIGHT - 6), - Alignment2D::TOP_LEFT, - WHITE, - Color::from_u16(bg_color), - ); - ICON_ARM_RIGHT.draw( - Point::new(constant::WIDTH / 2 + 25, HEIGHT - 6), - Alignment2D::TOP_LEFT, - WHITE, - Color::from_u16(bg_color), - ); + let title = Label::centered("Firmware installed", TEXT_BOLD).vertically_centered(); + + let content = Label::centered(reboot_msg.as_str(), TEXT_NORMAL).vertically_centered(); + + let mut frame = + ResultScreen::new(BLD_FG, BLD_BG, ICON_SPINNER, title, content, complete_draw); + show(&mut frame, false); + } + + fn screen_install_fail() { + let title = Label::centered("Install failed", TEXT_BOLD).vertically_centered(); + + let content = + Label::centered("Please reconnect\nthe device", TEXT_NORMAL).vertically_centered(); + + let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_ALERT, title, content, true); + show(&mut frame, false); + } + + fn screen_install_confirm( + vendor: &str, + version: &str, + fingerprint: &str, + should_keep_seed: bool, + is_newvendor: bool, + version_cmp: i32, + ) -> u32 { + let mut version_str: BootloaderString = String::new(); + unwrap!(version_str.push_str("Firmware version ")); + unwrap!(version_str.push_str(version)); + unwrap!(version_str.push_str("\nby ")); + unwrap!(version_str.push_str(vendor)); + + let title_str = if is_newvendor { + "CHANGE FW VENDOR" + } else if version_cmp > 0 { + "UPDATE FIRMWARE" + } else if version_cmp == 0 { + "REINSTALL FW" + } else { + "DOWNGRADE FW" + }; + + let message = Label::left_aligned(version_str.as_str(), TEXT_NORMAL).vertically_centered(); + let fingerprint = Label::left_aligned( + fingerprint, + TEXT_NORMAL.with_line_breaking(BreakWordsNoHyphen), + ) + .vertically_centered(); + + let alert = + (!should_keep_seed).then_some(Label::left_aligned("Seed will be erased!", TEXT_NORMAL)); + + let mut frame = Confirm::new(BLD_BG, title_str, message, alert, "INSTALL", false) + .with_info_screen("FW FINGERPRINT", fingerprint); + run(&mut frame) + } + + fn screen_wipe_confirm() -> u32 { + let message = Label::left_aligned("Seed and firmware will be erased!", TEXT_NORMAL) + .vertically_centered(); + + let mut frame = Confirm::new(BLD_BG, "FACTORY RESET", message, None, "RESET", false); + + run(&mut frame) + } + + fn screen_unlock_bootloader_confirm() -> u32 { + let message = + Label::left_aligned("This action cannot be undone!", TEXT_NORMAL).vertically_centered(); + + let mut frame = Confirm::new(BLD_BG, "UNLOCK BOOTLOADER?", message, None, "UNLOCK", true); + + run(&mut frame) + } + + fn screen_unlock_bootloader_success() { + let title = Label::centered("Bootloader unlocked", TEXT_BOLD).vertically_centered(); + + let content = + Label::centered("Please reconnect the\ndevice", TEXT_NORMAL).vertically_centered(); + + let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SPINNER, title, content, true); + show(&mut frame, false); + } + + fn screen_menu(firmware_present: secbool) -> u32 { + run(&mut Menu::new(firmware_present)) + } + + fn screen_intro(bld_version: &str, vendor: &str, version: &str, fw_ok: bool) -> u32 { + let mut title_str: BootloaderString = String::new(); + unwrap!(title_str.push_str("BOOTLOADER ")); + unwrap!(title_str.push_str(bld_version)); + + let mut version_str: BootloaderString = String::new(); + unwrap!(version_str.push_str("Firmware version ")); + unwrap!(version_str.push_str(version)); + unwrap!(version_str.push_str("\nby ")); + unwrap!(version_str.push_str(vendor)); + + let mut frame = Intro::new(title_str.as_str(), version_str.as_str(), fw_ok); + run(&mut frame) + } + + fn screen_boot_empty(_fading: bool) { + display::rect_fill(SCREEN, BLD_BG); + + let mut frame = WelcomeScreen::new(true); + show(&mut frame, false); + } + + fn screen_wipe_progress(progress: u16, initialize: bool) { + ModelTRFeatures::screen_progress( + "Resetting", + "Trezor", + progress, + initialize, + BLD_FG, + BLD_BG, + Some((ICON_SUCCESS, BLD_FG)), + ); + } + + fn screen_install_progress(progress: u16, initialize: bool, _initial_setup: bool) { + ModelTRFeatures::screen_progress( + "Installing", + "firmware", + progress, + initialize, + BLD_FG, + BLD_BG, + Some((ICON_SUCCESS, BLD_FG)), + ); + } + + fn screen_connect(_initial_setup: bool) { + let mut frame = Connect::new("Waiting for host...", BLD_FG, BLD_BG); + show(&mut frame, false); + } + + fn screen_wipe_success() { + let title = Label::centered("Trezor Reset", TEXT_BOLD).vertically_centered(); + + let content = + Label::centered("Please reconnect\nthe device", TEXT_NORMAL).vertically_centered(); + + let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SPINNER, title, content, true); + show(&mut frame, false); + } + + fn screen_wipe_fail() { + let title = Label::centered("Reset failed", TEXT_BOLD).vertically_centered(); + + let content = + Label::centered("Please reconnect\nthe device", TEXT_NORMAL).vertically_centered(); + + let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_ALERT, title, content, true); + show(&mut frame, false); + } } diff --git a/core/embed/rust/src/ui/model_tr/mod.rs b/core/embed/rust/src/ui/model_tr/mod.rs index c986209201..da51b42c5a 100644 --- a/core/embed/rust/src/ui/model_tr/mod.rs +++ b/core/embed/rust/src/ui/model_tr/mod.rs @@ -1,4 +1,4 @@ -use super::{geometry::Rect, layout::simplified::SimplifiedFeatures}; +use super::{geometry::Rect, UIFeaturesCommon}; #[cfg(feature = "bootloader")] pub mod bootloader; @@ -7,11 +7,19 @@ pub mod component; pub mod constant; #[cfg(feature = "micropython")] pub mod layout; -pub mod screens; +mod screens; pub mod theme; pub struct ModelTRFeatures {} -impl SimplifiedFeatures for ModelTRFeatures { +impl UIFeaturesCommon for ModelTRFeatures { const SCREEN: Rect = constant::SCREEN; + + fn screen_fatal_error(title: &str, msg: &str, footer: &str) { + screens::screen_fatal_error(title, msg, footer); + } + + fn screen_boot_full() { + screens::screen_boot_full(); + } } diff --git a/core/embed/rust/src/ui/model_tr/screens.rs b/core/embed/rust/src/ui/model_tr/screens.rs index efce223541..a9e45db7cb 100644 --- a/core/embed/rust/src/ui/model_tr/screens.rs +++ b/core/embed/rust/src/ui/model_tr/screens.rs @@ -30,8 +30,7 @@ pub fn screen_fatal_error(title: &str, msg: &str, footer: &str) { frame.paint(); } -#[no_mangle] -extern "C" fn screen_boot_full() { +pub fn screen_boot_full() { let mut frame = WelcomeScreen::new(false); frame.place(screen()); display::sync(); diff --git a/core/embed/rust/src/ui/model_tt/bootloader/mod.rs b/core/embed/rust/src/ui/model_tt/bootloader/mod.rs index a8b1646104..a60f16c68f 100644 --- a/core/embed/rust/src/ui/model_tt/bootloader/mod.rs +++ b/core/embed/rust/src/ui/model_tt/bootloader/mod.rs @@ -1,14 +1,12 @@ use heapless::String; use crate::{ - strutil::hexlify, trezorhal::secbool::secbool, ui::{ component::{connect::Connect, Label}, display::{self, Color, Font, Icon}, geometry::{Point, Rect}, - layout::simplified::{run, show, SimplifiedFeatures as _}, - util::{from_c_array, from_c_str}, + layout::simplified::{run, show}, }, }; @@ -30,6 +28,7 @@ use super::{ ModelTTFeatures, }; +use crate::ui::{ui_features::UIFeaturesBootloader, UIFeaturesCommon}; use intro::Intro; use menu::Menu; @@ -43,296 +42,267 @@ const RECONNECT_MESSAGE: &str = "PLEASE RECONNECT\nTHE DEVICE"; const SCREEN: Rect = ModelTTFeatures::SCREEN; -#[no_mangle] -extern "C" fn screen_install_confirm( - vendor_str: *const cty::c_char, - vendor_str_len: u8, - version: *const cty::c_char, - fingerprint: *const cty::uint8_t, - should_keep_seed: bool, - is_newvendor: bool, - version_cmp: cty::c_int, -) -> u32 { - let text = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) }); - let version = unwrap!(unsafe { from_c_str(version) }); +impl ModelTTFeatures { + fn screen_progress( + text: &str, + progress: u16, + initialize: bool, + fg_color: Color, + bg_color: Color, + icon: Option<(Icon, Color)>, + ) { + if initialize { + ModelTTFeatures::fadeout(); + display::rect_fill(SCREEN, bg_color); + } - let mut fingerprint_buffer: [u8; 64] = [0; 64]; - let fingerprint_str = unsafe { - let fingerprint_slice = core::slice::from_raw_parts(fingerprint, 32); - hexlify(fingerprint_slice, &mut fingerprint_buffer); - core::str::from_utf8_unchecked(fingerprint_buffer.as_ref()) - }; - - let mut version_str: BootloaderString = String::new(); - unwrap!(version_str.push_str("Firmware version ")); - unwrap!(version_str.push_str(version)); - unwrap!(version_str.push_str("\nby ")); - unwrap!(version_str.push_str(text)); - - let title_str = if is_newvendor { - "CHANGE FW\nVENDOR" - } else if version_cmp > 0 { - "UPDATE FIRMWARE" - } else if version_cmp == 0 { - "REINSTALL FW" - } else { - "DOWNGRADE FW" - }; - let title = Label::left_aligned(title_str, TEXT_BOLD).vertically_centered(); - let msg = Label::left_aligned(version_str.as_ref(), TEXT_NORMAL); - let alert = - (!should_keep_seed).then_some(Label::left_aligned("SEED WILL BE ERASED!", TEXT_BOLD)); - - let (left, right) = if should_keep_seed { - let l = Button::with_text("CANCEL").styled(button_bld()); - let r = Button::with_text("INSTALL").styled(button_confirm()); - (l, r) - } else { - let l = Button::with_icon(Icon::new(X24)).styled(button_bld()); - let r = Button::with_icon(Icon::new(CHECK24)).styled(button_confirm()); - (l, r) - }; - - let mut frame = Confirm::new(BLD_BG, left, right, ConfirmTitle::Text(title), msg).with_info( - "FW FINGERPRINT", - fingerprint_str, - button_bld_menu(), - ); - - if let Some(alert) = alert { - frame = frame.with_alert(alert); + display::text_center( + Point::new(SCREEN.width() / 2, SCREEN.height() - 45), + text, + Font::NORMAL, + fg_color, + bg_color, + ); + display::loader(progress, -20, fg_color, bg_color, icon); + display::refresh(); + if initialize { + ModelTTFeatures::fadein(); + } } - run(&mut frame) -} - -#[no_mangle] -extern "C" fn screen_wipe_confirm() -> u32 { - let icon = Icon::new(FIRE40); - - let msg = Label::centered( - "Are you sure you want to factory reset the device?", - TEXT_WIPE_NORMAL, - ); - let alert = Label::centered("SEED AND FIRMWARE\nWILL BE ERASED!", TEXT_WIPE_BOLD); - - let right = Button::with_text("RESET").styled(button_wipe_confirm()); - let left = Button::with_text("CANCEL").styled(button_wipe_cancel()); - - let mut frame = - Confirm::new(BLD_WIPE_COLOR, left, right, ConfirmTitle::Icon(icon), msg).with_alert(alert); - - run(&mut frame) -} - -#[no_mangle] -extern "C" fn screen_menu(firmware_present: secbool) -> u32 { - run(&mut Menu::new(firmware_present)) -} - -#[no_mangle] -extern "C" fn screen_intro( - bld_version: *const cty::c_char, - vendor_str: *const cty::c_char, - vendor_str_len: u8, - version: *const cty::c_char, - fw_ok: bool, -) -> u32 { - let vendor = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) }); - let version = unwrap!(unsafe { from_c_str(version) }); - let bld_version = unwrap!(unsafe { from_c_str(bld_version) }); - - let mut title_str: BootloaderString = String::new(); - unwrap!(title_str.push_str("BOOTLOADER ")); - unwrap!(title_str.push_str(bld_version)); - - let mut version_str: BootloaderString = String::new(); - unwrap!(version_str.push_str("Firmware version ")); - unwrap!(version_str.push_str(version)); - unwrap!(version_str.push_str("\nby ")); - unwrap!(version_str.push_str(vendor)); - - let mut frame = Intro::new(title_str.as_str(), version_str.as_str(), fw_ok); - - run(&mut frame) -} - -fn screen_progress( - text: &str, - progress: u16, - initialize: bool, - fg_color: Color, - bg_color: Color, - icon: Option<(Icon, Color)>, -) { - if initialize { - ModelTTFeatures::fadeout(); - display::rect_fill(SCREEN, bg_color); + fn screen_install_success_bld(msg: &str, complete_draw: bool) { + let mut frame = ResultScreen::new( + &RESULT_FW_INSTALL, + Icon::new(CHECK40), + "Firmware installed\nsuccessfully", + Label::centered(msg, RESULT_FW_INSTALL.title_style()).vertically_centered(), + complete_draw, + ); + show(&mut frame, complete_draw); } - display::text_center( - Point::new(SCREEN.width() / 2, SCREEN.height() - 45), - text, - Font::NORMAL, - fg_color, - bg_color, - ); - display::loader(progress, -20, fg_color, bg_color, icon); - display::refresh(); - if initialize { - ModelTTFeatures::fadein(); + fn screen_install_success_initial(msg: &str, complete_draw: bool) { + let mut frame = ResultScreen::new( + &RESULT_INITIAL, + Icon::new(CHECK40), + "Firmware installed\nsuccessfully", + Label::centered(msg, RESULT_INITIAL.title_style()).vertically_centered(), + complete_draw, + ); + show(&mut frame, complete_draw); } } -#[no_mangle] -extern "C" fn screen_install_progress(progress: u16, initialize: bool, initial_setup: bool) { - let bg_color = if initial_setup { WELCOME_COLOR } else { BLD_BG }; - let fg_color = if initial_setup { FG } else { BLD_FG }; - - screen_progress( - "Installing firmware", - progress, - initialize, - fg_color, - bg_color, - Some((Icon::new(DOWNLOAD32), fg_color)), - ) -} - -#[no_mangle] -extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) { - screen_progress( - "Resetting Trezor", - progress, - initialize, - BLD_FG, - BLD_WIPE_COLOR, - Some((Icon::new(FIRE32), BLD_FG)), - ) -} - -#[no_mangle] -extern "C" fn screen_connect(initial_setup: bool) { - let bg = if initial_setup { WELCOME_COLOR } else { BLD_BG }; - let mut frame = Connect::new("Waiting for host...", BLD_TITLE_COLOR, bg); - show(&mut frame, true); -} - -#[no_mangle] -extern "C" fn screen_wipe_success() { - let mut frame = ResultScreen::new( - &RESULT_WIPE, - Icon::new(CHECK40), - "Trezor reset\nsuccessfully", - Label::centered(RECONNECT_MESSAGE, RESULT_WIPE.title_style()).vertically_centered(), - true, - ); - show(&mut frame, true); -} - -#[no_mangle] -extern "C" fn screen_wipe_fail() { - let mut frame = ResultScreen::new( - &RESULT_WIPE, - Icon::new(WARNING40), - "Trezor reset was\nnot successful", - Label::centered(RECONNECT_MESSAGE, RESULT_WIPE.title_style()).vertically_centered(), - true, - ); - show(&mut frame, true); -} - -#[no_mangle] -extern "C" fn screen_boot_empty(fading: bool) { - if fading { - ModelTTFeatures::fadeout(); +impl UIFeaturesBootloader for ModelTTFeatures { + fn screen_welcome() { + let mut frame = Welcome::new(); + show(&mut frame, true); } - display::rect_fill(SCREEN, BLACK); - - let mut frame = WelcomeScreen::new(true); - show(&mut frame, false); - - if fading { - ModelTTFeatures::fadein(); - } else { - display::set_backlight(BACKLIGHT_NORMAL); - } - display::refresh(); -} - -#[no_mangle] -extern "C" fn screen_install_fail() { - let mut frame = ResultScreen::new( - &RESULT_FW_INSTALL, - Icon::new(WARNING40), - "Firmware installation was not successful", - Label::centered(RECONNECT_MESSAGE, RESULT_FW_INSTALL.title_style()).vertically_centered(), - true, - ); - show(&mut frame, true); -} - -fn screen_install_success_bld(msg: &str, complete_draw: bool) { - let mut frame = ResultScreen::new( - &RESULT_FW_INSTALL, - Icon::new(CHECK40), - "Firmware installed\nsuccessfully", - Label::centered(msg, RESULT_FW_INSTALL.title_style()).vertically_centered(), - complete_draw, - ); - show(&mut frame, complete_draw); -} - -fn screen_install_success_initial(msg: &str, complete_draw: bool) { - let mut frame = ResultScreen::new( - &RESULT_INITIAL, - Icon::new(CHECK40), - "Firmware installed\nsuccessfully", - Label::centered(msg, RESULT_INITIAL.title_style()).vertically_centered(), - complete_draw, - ); - show(&mut frame, complete_draw); -} - -#[no_mangle] -extern "C" fn screen_install_success( - restart_seconds: u8, - initial_setup: bool, - complete_draw: bool, -) { - let mut reboot_msg = BootloaderString::new(); - - if restart_seconds >= 1 { - unwrap!(reboot_msg.push_str("RESTARTING IN ")); - // in practice, restart_seconds is 5 or less so this is fine - let seconds_char = b'0' + restart_seconds % 10; - unwrap!(reboot_msg.push(seconds_char as char)); - } else { - unwrap!(reboot_msg.push_str(RECONNECT_MESSAGE)); + fn bld_continue_label(bg_color: Color) { + display::text_center( + Point::new(SCREEN.width() / 2, SCREEN.height() - 5), + "click to continue ...", + Font::NORMAL, + WHITE, + bg_color, + ); } - if initial_setup { - screen_install_success_initial(reboot_msg.as_str(), complete_draw) - } else { - screen_install_success_bld(reboot_msg.as_str(), complete_draw) + fn screen_install_success(restart_seconds: u8, initial_setup: bool, complete_draw: bool) { + let mut reboot_msg = BootloaderString::new(); + + if restart_seconds >= 1 { + unwrap!(reboot_msg.push_str("RESTARTING IN ")); + // in practice, restart_seconds is 5 or less so this is fine + let seconds_char = b'0' + restart_seconds % 10; + unwrap!(reboot_msg.push(seconds_char as char)); + } else { + unwrap!(reboot_msg.push_str(RECONNECT_MESSAGE)); + } + + if initial_setup { + ModelTTFeatures::screen_install_success_initial(reboot_msg.as_str(), complete_draw) + } else { + ModelTTFeatures::screen_install_success_bld(reboot_msg.as_str(), complete_draw) + } + display::refresh(); } - display::refresh(); -} -#[no_mangle] -extern "C" fn screen_welcome() { - let mut frame = Welcome::new(); - show(&mut frame, true); -} + fn screen_install_fail() { + let mut frame = ResultScreen::new( + &RESULT_FW_INSTALL, + Icon::new(WARNING40), + "Firmware installation was not successful", + Label::centered(RECONNECT_MESSAGE, RESULT_FW_INSTALL.title_style()) + .vertically_centered(), + true, + ); + show(&mut frame, true); + } -#[no_mangle] -extern "C" fn bld_continue_label(bg_color: cty::uint16_t) { - display::text_center( - Point::new(SCREEN.width() / 2, SCREEN.height() - 5), - "click to continue ...", - Font::NORMAL, - WHITE, - Color::from_u16(bg_color), - ); + fn screen_install_confirm( + vendor: &str, + version: &str, + fingerprint: &str, + should_keep_seed: bool, + is_newvendor: bool, + version_cmp: i32, + ) -> u32 { + let mut version_str: BootloaderString = String::new(); + unwrap!(version_str.push_str("Firmware version ")); + unwrap!(version_str.push_str(version)); + unwrap!(version_str.push_str("\nby ")); + unwrap!(version_str.push_str(vendor)); + + let title_str = if is_newvendor { + "CHANGE FW\nVENDOR" + } else if version_cmp > 0 { + "UPDATE FIRMWARE" + } else if version_cmp == 0 { + "REINSTALL FW" + } else { + "DOWNGRADE FW" + }; + let title = Label::left_aligned(title_str, TEXT_BOLD).vertically_centered(); + let msg = Label::left_aligned(version_str.as_ref(), TEXT_NORMAL); + let alert = + (!should_keep_seed).then_some(Label::left_aligned("SEED WILL BE ERASED!", TEXT_BOLD)); + + let (left, right) = if should_keep_seed { + let l = Button::with_text("CANCEL").styled(button_bld()); + let r = Button::with_text("INSTALL").styled(button_confirm()); + (l, r) + } else { + let l = Button::with_icon(Icon::new(X24)).styled(button_bld()); + let r = Button::with_icon(Icon::new(CHECK24)).styled(button_confirm()); + (l, r) + }; + + let mut frame = Confirm::new(BLD_BG, left, right, ConfirmTitle::Text(title), msg) + .with_info("FW FINGERPRINT", fingerprint, button_bld_menu()); + + if let Some(alert) = alert { + frame = frame.with_alert(alert); + } + + run(&mut frame) + } + + fn screen_wipe_confirm() -> u32 { + let icon = Icon::new(FIRE40); + + let msg = Label::centered( + "Are you sure you want to factory reset the device?", + TEXT_WIPE_NORMAL, + ); + let alert = Label::centered("SEED AND FIRMWARE\nWILL BE ERASED!", TEXT_WIPE_BOLD); + + let right = Button::with_text("RESET").styled(button_wipe_confirm()); + let left = Button::with_text("CANCEL").styled(button_wipe_cancel()); + + let mut frame = Confirm::new(BLD_WIPE_COLOR, left, right, ConfirmTitle::Icon(icon), msg) + .with_alert(alert); + + run(&mut frame) + } + + fn screen_unlock_bootloader_confirm() -> u32 { + unimplemented!(); + } + + fn screen_unlock_bootloader_success() { + unimplemented!(); + } + + fn screen_menu(firmware_present: secbool) -> u32 { + run(&mut Menu::new(firmware_present)) + } + + fn screen_intro(bld_version: &str, vendor: &str, version: &str, fw_ok: bool) -> u32 { + let mut title_str: BootloaderString = String::new(); + unwrap!(title_str.push_str("BOOTLOADER ")); + unwrap!(title_str.push_str(bld_version)); + + let mut version_str: BootloaderString = String::new(); + unwrap!(version_str.push_str("Firmware version ")); + unwrap!(version_str.push_str(version)); + unwrap!(version_str.push_str("\nby ")); + unwrap!(version_str.push_str(vendor)); + + let mut frame = Intro::new(title_str.as_str(), version_str.as_str(), fw_ok); + + run(&mut frame) + } + + fn screen_boot_empty(fading: bool) { + if fading { + ModelTTFeatures::fadeout(); + } + + display::rect_fill(SCREEN, BLACK); + + let mut frame = WelcomeScreen::new(true); + show(&mut frame, false); + + if fading { + ModelTTFeatures::fadein(); + } else { + display::set_backlight(BACKLIGHT_NORMAL); + } + display::refresh(); + } + + fn screen_wipe_progress(progress: u16, initialize: bool) { + ModelTTFeatures::screen_progress( + "Resetting Trezor", + progress, + initialize, + BLD_FG, + BLD_WIPE_COLOR, + Some((Icon::new(FIRE32), BLD_FG)), + ) + } + + fn screen_install_progress(progress: u16, initialize: bool, initial_setup: bool) { + let bg_color = if initial_setup { WELCOME_COLOR } else { BLD_BG }; + let fg_color = if initial_setup { FG } else { BLD_FG }; + + ModelTTFeatures::screen_progress( + "Installing firmware", + progress, + initialize, + fg_color, + bg_color, + Some((Icon::new(DOWNLOAD32), fg_color)), + ) + } + + fn screen_connect(initial_setup: bool) { + let bg = if initial_setup { WELCOME_COLOR } else { BLD_BG }; + let mut frame = Connect::new("Waiting for host...", BLD_TITLE_COLOR, bg); + show(&mut frame, true); + } + + fn screen_wipe_success() { + let mut frame = ResultScreen::new( + &RESULT_WIPE, + Icon::new(CHECK40), + "Trezor reset\nsuccessfully", + Label::centered(RECONNECT_MESSAGE, RESULT_WIPE.title_style()).vertically_centered(), + true, + ); + show(&mut frame, true); + } + + fn screen_wipe_fail() { + let mut frame = ResultScreen::new( + &RESULT_WIPE, + Icon::new(WARNING40), + "Trezor reset was\nnot successful", + Label::centered(RECONNECT_MESSAGE, RESULT_WIPE.title_style()).vertically_centered(), + true, + ); + show(&mut frame, true); + } } diff --git a/core/embed/rust/src/ui/model_tt/mod.rs b/core/embed/rust/src/ui/model_tt/mod.rs index ead5186834..866f07dc8c 100644 --- a/core/embed/rust/src/ui/model_tt/mod.rs +++ b/core/embed/rust/src/ui/model_tt/mod.rs @@ -1,4 +1,4 @@ -use super::{geometry::Rect, layout::simplified::SimplifiedFeatures}; +use super::{geometry::Rect, UIFeaturesCommon}; #[cfg(feature = "bootloader")] pub mod bootloader; @@ -8,11 +8,11 @@ pub mod theme; #[cfg(feature = "micropython")] pub mod layout; -pub mod screens; +mod screens; -pub struct ModelTTFeatures {} +pub struct ModelTTFeatures; -impl SimplifiedFeatures for ModelTTFeatures { +impl UIFeaturesCommon for ModelTTFeatures { fn fadein() { #[cfg(feature = "backlight")] crate::ui::display::fade_backlight_duration(theme::BACKLIGHT_NORMAL, 150); @@ -24,4 +24,12 @@ impl SimplifiedFeatures for ModelTTFeatures { } const SCREEN: Rect = constant::SCREEN; + + fn screen_fatal_error(title: &str, msg: &str, footer: &str) { + screens::screen_fatal_error(title, msg, footer); + } + + fn screen_boot_full() { + screens::screen_boot_full(); + } } diff --git a/core/embed/rust/src/ui/model_tt/screens.rs b/core/embed/rust/src/ui/model_tt/screens.rs index 5f25e00c1f..381569d25f 100644 --- a/core/embed/rust/src/ui/model_tt/screens.rs +++ b/core/embed/rust/src/ui/model_tt/screens.rs @@ -34,8 +34,7 @@ pub fn screen_fatal_error(title: &str, msg: &str, footer: &str) { frame.paint(); } -#[no_mangle] -extern "C" fn screen_boot_full() { +pub fn screen_boot_full() { let mut frame = WelcomeScreen::new(false); frame.place(screen()); display::sync(); diff --git a/core/embed/rust/src/ui/screens.rs b/core/embed/rust/src/ui/screens.rs deleted file mode 100644 index fa3c2cf5d8..0000000000 --- a/core/embed/rust/src/ui/screens.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Reexporting the `screens` module according to the -//! current feature (Trezor model) - -#[cfg(all(feature = "model_tr", not(feature = "model_tt")))] -pub use super::model_tr::screens::*; -#[cfg(feature = "model_tt")] -pub use super::model_tt::screens::*; -use crate::ui::util::from_c_str; - -#[no_mangle] -extern "C" fn screen_fatal_error_rust( - title: *const cty::c_char, - msg: *const cty::c_char, - footer: *const cty::c_char, -) { - let title = unsafe { from_c_str(title) }.unwrap_or(""); - let msg = unsafe { from_c_str(msg) }.unwrap_or(""); - let footer = unsafe { from_c_str(footer) }.unwrap_or(""); - - screen_fatal_error(title, msg, footer); -} diff --git a/core/embed/rust/src/ui/ui_features.rs b/core/embed/rust/src/ui/ui_features.rs new file mode 100644 index 0000000000..0f17a3fa77 --- /dev/null +++ b/core/embed/rust/src/ui/ui_features.rs @@ -0,0 +1,62 @@ +use crate::ui::geometry::Rect; +#[cfg(feature = "bootloader")] +use crate::{trezorhal::secbool::secbool, ui::display::Color}; + +pub trait UIFeaturesCommon { + fn fadein() {} + fn fadeout() {} + + const SCREEN: Rect; + + fn screen_fatal_error(title: &str, msg: &str, footer: &str); + + fn screen_boot_full(); +} + +#[cfg(feature = "bootloader")] +pub trait UIFeaturesBootloader { + fn screen_welcome(); + + fn bld_continue_label(bg_color: Color); + + fn screen_install_success(restart_seconds: u8, initial_setup: bool, complete_draw: bool); + + fn screen_install_fail(); + + fn screen_install_confirm( + vendor: &str, + version: &str, + fingerprint: &str, + should_keep_seed: bool, + is_newvendor: bool, + version_cmp: i32, + ) -> u32; + + fn screen_wipe_confirm() -> u32; + + fn screen_unlock_bootloader_confirm() -> u32; + + fn screen_unlock_bootloader_success(); + + fn screen_menu(firmware_present: secbool) -> u32; + + fn screen_intro(bld_version: &str, vendor: &str, version: &str, fw_ok: bool) -> u32; + + fn screen_boot_empty(fading: bool); + + fn screen_wipe_progress(progress: u16, initialize: bool); + + fn screen_install_progress(progress: u16, initialize: bool, initial_setup: bool); + + fn screen_connect(initial_setup: bool); + + fn screen_wipe_success(); + + fn screen_wipe_fail(); +} + +#[cfg(all(feature = "model_tr", not(feature = "model_tt")))] +pub type ModelUI = crate::ui::model_tr::ModelTRFeatures; + +#[cfg(feature = "model_tt")] +pub type ModelUI = crate::ui::model_tt::ModelTTFeatures;