You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
395 lines
11 KiB
395 lines
11 KiB
use crate::{
|
|
trezorhal::io::io_button_read,
|
|
ui::{
|
|
component::{Component, Never},
|
|
display::{self, Font},
|
|
geometry::Point,
|
|
},
|
|
};
|
|
|
|
mod confirm;
|
|
mod intro;
|
|
mod menu;
|
|
mod theme;
|
|
mod title;
|
|
|
|
use crate::ui::{
|
|
component::{
|
|
text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt},
|
|
Event, EventCtx,
|
|
},
|
|
constant::{screen, WIDTH},
|
|
display::{Color, Icon, TextOverlay},
|
|
event::ButtonEvent,
|
|
geometry::{LinearPlacement, Offset, Rect, CENTER},
|
|
util::{from_c_array, from_c_str},
|
|
};
|
|
|
|
use super::{
|
|
component::{Button, ButtonPos, ResultScreen},
|
|
constant,
|
|
theme::{ICON_FAIL, ICON_SUCCESS, LOGO_EMPTY},
|
|
};
|
|
|
|
use confirm::Confirm;
|
|
use intro::Intro;
|
|
use menu::Menu;
|
|
use theme::{bld_button_cancel, bld_button_default, BLD_BG, BLD_FG};
|
|
|
|
const SCREEN_ADJ: Rect = screen().split_top(64).0;
|
|
|
|
pub trait ReturnToC {
|
|
fn return_to_c(self) -> u32;
|
|
}
|
|
|
|
impl ReturnToC for Never {
|
|
fn return_to_c(self) -> u32 {
|
|
unreachable!()
|
|
}
|
|
}
|
|
|
|
impl ReturnToC for () {
|
|
fn return_to_c(self) -> u32 {
|
|
0
|
|
}
|
|
}
|
|
|
|
fn button_eval() -> Option<ButtonEvent> {
|
|
let event = io_button_read();
|
|
if event == 0 {
|
|
return None;
|
|
}
|
|
|
|
let event_type = event >> 24;
|
|
let event_btn = event & 0xFFFFFF;
|
|
|
|
let event = ButtonEvent::new(event_type, event_btn);
|
|
|
|
if let Ok(event) = event {
|
|
return Some(event);
|
|
}
|
|
None
|
|
}
|
|
|
|
fn run<F>(frame: &mut F) -> u32
|
|
where
|
|
F: Component,
|
|
F::Msg: ReturnToC,
|
|
{
|
|
frame.place(SCREEN_ADJ);
|
|
frame.paint();
|
|
|
|
while button_eval().is_some() {}
|
|
|
|
loop {
|
|
let event = button_eval();
|
|
if let Some(e) = event {
|
|
let mut ctx = EventCtx::new();
|
|
let msg = frame.event(&mut ctx, Event::Button(e));
|
|
|
|
if let Some(message) = msg {
|
|
return message.return_to_c();
|
|
}
|
|
|
|
frame.paint();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn show<F>(frame: &mut F)
|
|
where
|
|
F: Component,
|
|
{
|
|
frame.place(SCREEN_ADJ);
|
|
display::sync();
|
|
frame.paint();
|
|
display::refresh();
|
|
}
|
|
|
|
#[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,
|
|
downgrade: bool,
|
|
vendor: bool,
|
|
) -> u32 {
|
|
let text = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) });
|
|
let version = unwrap!(unsafe { from_c_str(version) });
|
|
|
|
let icon: Option<Icon> = None;
|
|
|
|
let msg = if downgrade {
|
|
"Downgrade firmware by"
|
|
} else if vendor {
|
|
"Change vendor to"
|
|
} else {
|
|
"Update firmware by"
|
|
};
|
|
|
|
let mut message = ParagraphVecShort::new();
|
|
|
|
message.add(Paragraph::new(&theme::TEXT_NORMAL, msg).centered());
|
|
message.add(Paragraph::new(&theme::TEXT_NORMAL, text).centered());
|
|
message.add(Paragraph::new(&theme::TEXT_NORMAL, version).centered());
|
|
|
|
if vendor || downgrade {
|
|
message.add(Paragraph::new(&theme::TEXT_BOLD, "Seed will be erased!").centered());
|
|
}
|
|
|
|
// TODO: this relies on StrBuffer support for bootloader, decide what to do
|
|
let left = Button::with_text(ButtonPos::Left, "CANCEL", bld_button_cancel());
|
|
let right = Button::with_text(ButtonPos::Right, "INSTALL", bld_button_default());
|
|
|
|
let mut frame = Confirm::new(
|
|
BLD_BG,
|
|
icon,
|
|
Paragraphs::new(message).with_placement(LinearPlacement::vertical().align_at_center()),
|
|
left,
|
|
right,
|
|
false,
|
|
);
|
|
|
|
run(&mut frame)
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_wipe_confirm() -> u32 {
|
|
let icon: Option<Icon> = None; //Some(ERASE_BIG);
|
|
|
|
let mut messages = ParagraphVecShort::new();
|
|
|
|
messages.add(
|
|
Paragraph::new(
|
|
&theme::TEXT_NORMAL,
|
|
"Do you really want to wipe the device?",
|
|
)
|
|
.centered(),
|
|
);
|
|
messages.add(Paragraph::new(&theme::TEXT_BOLD, "Seed will be erased!").centered());
|
|
|
|
let message =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
// TODO: this relies on StrBuffer support for bootloader, decide what to do
|
|
let left = Button::with_text(ButtonPos::Left, "WIPE", bld_button_default());
|
|
let right = Button::with_text(ButtonPos::Right, "CANCEL", bld_button_cancel());
|
|
|
|
let mut frame = Confirm::new(BLD_BG, icon, message, left, right, true);
|
|
|
|
run(&mut frame)
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_menu(bld_version: *const cty::c_char) -> u32 {
|
|
let bld_version = unwrap!(unsafe { from_c_str(bld_version) });
|
|
|
|
run(&mut Menu::new(bld_version))
|
|
}
|
|
|
|
#[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,
|
|
) -> 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) });
|
|
|
|
run(&mut Intro::new(bld_version, vendor, version))
|
|
}
|
|
|
|
fn screen_progress(
|
|
text: &str,
|
|
progress: u16,
|
|
initialize: bool,
|
|
fg_color: Color,
|
|
bg_color: Color,
|
|
_icon: Option<(&[u8], Color)>,
|
|
) {
|
|
if initialize {
|
|
display::rect_fill(constant::screen(), bg_color);
|
|
}
|
|
|
|
let loader_area = Rect::new(Point::new(5, 24), Point::new(WIDTH - 5, 24 + 16));
|
|
|
|
let mut text = TextOverlay::new(text, Font::NORMAL);
|
|
text.place(loader_area.center() + Offset::y(Font::NORMAL.text_height() / 2));
|
|
|
|
let fill_to = (loader_area.width() as u32 * progress as u32) / 1000;
|
|
|
|
display::bar_with_text_and_fill(
|
|
loader_area,
|
|
Some(&text),
|
|
fg_color,
|
|
bg_color,
|
|
0,
|
|
fill_to as _,
|
|
);
|
|
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,
|
|
None,
|
|
)
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) {
|
|
screen_progress(
|
|
"WIPING DEVICE",
|
|
progress,
|
|
initialize,
|
|
theme::BLD_FG,
|
|
BLD_BG,
|
|
None,
|
|
)
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_connect() {
|
|
let mut messages = ParagraphVecShort::new();
|
|
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "Waiting for host...").centered());
|
|
|
|
let mut frame =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
show(&mut frame);
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_wipe_success() {
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "Device wiped").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "successfully.").centered());
|
|
|
|
let m_top =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "PLEASE RECONNECT").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "THE DEVICE").centered());
|
|
|
|
let m_bottom =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SUCCESS, m_top, m_bottom, true);
|
|
show(&mut frame);
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_wipe_fail() {
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "Device wipe was").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "not successful.").centered());
|
|
|
|
let m_top =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "PLEASE RECONNECT").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "THE DEVICE").centered());
|
|
|
|
let m_bottom =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_FAIL, m_top, m_bottom, true);
|
|
show(&mut frame);
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_boot_empty(_firmware_present: bool, _fading: bool) {
|
|
Icon::new(LOGO_EMPTY).draw(SCREEN_ADJ.center(), CENTER, BLD_FG, BLD_BG);
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_install_fail() {
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "Firmware installation was").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "not successful.").centered());
|
|
let m_top =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "PLEASE RECONNECT").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "THE DEVICE").centered());
|
|
|
|
let m_bottom =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_FAIL, m_top, m_bottom, true);
|
|
show(&mut frame);
|
|
}
|
|
|
|
fn screen_install_success_bld(msg: &'static str, complete_draw: bool) {
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "Firmware installed").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "successfully.").centered());
|
|
|
|
let m_top =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, msg).centered());
|
|
|
|
let m_bottom =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SUCCESS, m_top, m_bottom, complete_draw);
|
|
show(&mut frame);
|
|
}
|
|
|
|
fn screen_install_success_initial(msg: &'static str, complete_draw: bool) {
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "Firmware installed").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, "successfully.").centered());
|
|
|
|
let m_top =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_NORMAL, msg).centered());
|
|
|
|
let m_bottom =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
|
|
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SUCCESS, m_top, m_bottom, complete_draw);
|
|
show(&mut frame);
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_install_success(
|
|
reboot_msg: *const cty::c_char,
|
|
initial_setup: bool,
|
|
complete_draw: bool,
|
|
) {
|
|
let msg = unwrap!(unsafe { from_c_str(reboot_msg) });
|
|
if initial_setup {
|
|
screen_install_success_initial(msg, complete_draw)
|
|
} else {
|
|
screen_install_success_bld(msg, complete_draw)
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
extern "C" fn screen_welcome() {
|
|
let mut messages = ParagraphVecShort::new();
|
|
messages.add(Paragraph::new(&theme::TEXT_BOLD, "Get started with").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_BOLD, "your trezor at").centered());
|
|
messages.add(Paragraph::new(&theme::TEXT_BOLD, "trezor.io/start").centered());
|
|
let mut frame =
|
|
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
|
show(&mut frame);
|
|
}
|