mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-27 00:28:10 +00:00
feat(core/rust): bootloader implementation in rust
This commit is contained in:
parent
f9612898ab
commit
5a991f3244
1
core/.changelog.d/1049.added
Normal file
1
core/.changelog.d/1049.added
Normal file
@ -0,0 +1 @@
|
||||
Error screens redesign
|
@ -32,10 +32,10 @@ if TREZOR_MODEL in ('1', 'R'):
|
||||
FONT_BOLD=None
|
||||
FONT_MONO='Font_PixelOperatorMono_Regular_8'
|
||||
if TREZOR_MODEL in ('T', ):
|
||||
FONT_NORMAL='Font_Roboto_Regular_20'
|
||||
FONT_NORMAL='Font_TTHoves_Regular_18'
|
||||
FONT_DEMIBOLD=None
|
||||
FONT_BOLD=None
|
||||
FONT_MONO='Font_RobotoMono_Regular_20'
|
||||
FONT_BOLD='Font_TTHoves_Bold_16'
|
||||
FONT_MONO=None
|
||||
|
||||
# modtrezorcrypto
|
||||
CCFLAGS_MOD += '-Wno-sequence-point '
|
||||
@ -47,6 +47,9 @@ CPPDEFINES_MOD += [
|
||||
'AES_192',
|
||||
'USE_KECCAK',
|
||||
'ED25519_NO_PRECOMP',
|
||||
'TREZOR_UI2',
|
||||
'USE_RUST_LOADER',
|
||||
'FANCY_FATAL_ERROR'
|
||||
]
|
||||
SOURCE_MOD += [
|
||||
'vendor/trezor-crypto/blake2s.c',
|
||||
|
@ -192,6 +192,11 @@ CPPDEFINES_MOD += [
|
||||
'USE_RUST_LOADER'
|
||||
]
|
||||
|
||||
if TREZOR_MODEL not in ('1', ):
|
||||
CPPDEFINES_MOD += [
|
||||
'FANCY_FATAL_ERROR',
|
||||
]
|
||||
|
||||
# modtrezorutils
|
||||
SOURCE_MOD += [
|
||||
'embed/extmod/modtrezorutils/modtrezorutils.c',
|
||||
|
@ -184,6 +184,11 @@ CPPDEFINES_MOD += [
|
||||
'TREZOR_UI2',
|
||||
'USE_RUST_LOADER'
|
||||
]
|
||||
if TREZOR_MODEL not in ('1', ):
|
||||
CPPDEFINES_MOD += [
|
||||
'FANCY_FATAL_ERROR',
|
||||
]
|
||||
|
||||
if FROZEN:
|
||||
CPPDEFINES_MOD += ['TREZOR_EMULATOR_FROZEN']
|
||||
if RASPI:
|
||||
|
BIN
core/assets/close.png
Normal file
BIN
core/assets/close.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
BIN
core/assets/erase_big.png
Normal file
BIN
core/assets/erase_big.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.3 KiB |
BIN
core/assets/info_small.png
Normal file
BIN
core/assets/info_small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.4 KiB |
BIN
core/assets/menu.png
Normal file
BIN
core/assets/menu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
BIN
core/assets/success_bld.png
Normal file
BIN
core/assets/success_bld.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
BIN
core/assets/warn_bld.png
Normal file
BIN
core/assets/warn_bld.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
1
core/embed/bootloader/.changelog.d/1049.added
Normal file
1
core/embed/bootloader/.changelog.d/1049.added
Normal file
@ -0,0 +1 @@
|
||||
Bootloader redesign
|
@ -21,27 +21,10 @@
|
||||
|
||||
#include "bootui.h"
|
||||
#include "display.h"
|
||||
#include "icon_cancel.h"
|
||||
#include "icon_confirm.h"
|
||||
#include "icon_done.h"
|
||||
#include "icon_fail.h"
|
||||
#include "icon_info.h"
|
||||
#include "icon_install.h"
|
||||
#include "icon_logo.h"
|
||||
#include "icon_safeplace.h"
|
||||
#include "icon_welcome.h"
|
||||
#include "icon_wipe.h"
|
||||
#include "mini_printf.h"
|
||||
#include "rust_ui.h"
|
||||
#include "version.h"
|
||||
|
||||
#if defined USE_TOUCH
|
||||
#include "touch/touch.h"
|
||||
#elif defined USE_BUTTON
|
||||
#include "button.h"
|
||||
#else
|
||||
#error No input method defined
|
||||
#endif
|
||||
|
||||
#define BACKLIGHT_NORMAL 150
|
||||
|
||||
#define COLOR_BL_BG COLOR_WHITE // background
|
||||
@ -59,34 +42,22 @@
|
||||
#define COLOR_BL_GRAY COLOR_BL_FG
|
||||
#endif
|
||||
|
||||
#define COLOR_WELCOME_BG COLOR_WHITE // welcome background
|
||||
#define COLOR_WELCOME_FG COLOR_BLACK // welcome foreground
|
||||
|
||||
// common shared functions
|
||||
|
||||
static void ui_confirm_cancel_buttons(void) {
|
||||
display_bar_radius(9, 184, 108, 50, COLOR_BL_FAIL, COLOR_BL_BG, 4);
|
||||
display_icon(9 + (108 - 16) / 2, 184 + (50 - 16) / 2, 16, 16,
|
||||
toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_BL_BG,
|
||||
COLOR_BL_FAIL);
|
||||
display_bar_radius(123, 184, 108, 50, COLOR_BL_DONE, COLOR_BL_BG, 4);
|
||||
display_icon(123 + (108 - 19) / 2, 184 + (50 - 16) / 2, 20, 16,
|
||||
toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12,
|
||||
COLOR_BL_BG, COLOR_BL_DONE);
|
||||
}
|
||||
|
||||
static const char *format_ver(const char *format, uint32_t version) {
|
||||
static char ver_str[64];
|
||||
mini_snprintf(ver_str, sizeof(ver_str), format, (int)(version & 0xFF),
|
||||
static void format_ver(const char *format, uint32_t version, char *buffer,
|
||||
size_t buffer_len) {
|
||||
mini_snprintf(buffer, buffer_len, format, (int)(version & 0xFF),
|
||||
(int)((version >> 8) & 0xFF), (int)((version >> 16) & 0xFF)
|
||||
// ignore build field (int)((version >> 24) & 0xFF)
|
||||
);
|
||||
return ver_str;
|
||||
}
|
||||
|
||||
// boot UI
|
||||
|
||||
static uint16_t boot_background;
|
||||
static bool initial_setup = true;
|
||||
|
||||
void ui_set_initial_setup(bool initial) { initial_setup = initial; }
|
||||
|
||||
void ui_screen_boot(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
@ -112,10 +83,11 @@ void ui_screen_boot(const vendor_header *const vhdr,
|
||||
}
|
||||
|
||||
if (show_string) {
|
||||
char ver_str[64];
|
||||
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5 - 50, vhdr->vstr,
|
||||
vhdr->vstr_len, FONT_NORMAL, COLOR_BL_BG,
|
||||
boot_background);
|
||||
const char *ver_str = format_ver("%d.%d.%d", fw_version);
|
||||
format_ver("%d.%d.%d", fw_version, ver_str, sizeof(ver_str));
|
||||
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 5 - 25, ver_str, -1,
|
||||
FONT_NORMAL, COLOR_BL_BG, boot_background);
|
||||
}
|
||||
@ -145,187 +117,75 @@ void ui_screen_boot_click(void) {
|
||||
|
||||
// welcome UI
|
||||
|
||||
void ui_screen_welcome_first(void) {
|
||||
display_icon(0, 0, 240, 240, toi_icon_logo + 12, sizeof(toi_icon_logo) - 12,
|
||||
COLOR_WELCOME_FG, COLOR_WELCOME_BG);
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
void ui_screen_welcome(void) { screen_welcome(); }
|
||||
|
||||
uint32_t ui_screen_intro(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
char bld_ver[32];
|
||||
char ver_str[64];
|
||||
format_ver("%d.%d.%d", VERSION_UINT32, bld_ver, sizeof(bld_ver));
|
||||
format_ver("%d.%d.%d", hdr->version, ver_str, sizeof(ver_str));
|
||||
|
||||
return screen_intro(bld_ver, vhdr->vstr, vhdr->vstr_len, ver_str);
|
||||
}
|
||||
|
||||
void ui_screen_welcome_second(void) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WELCOME_BG);
|
||||
display_icon((DISPLAY_RESX - 200) / 2, (DISPLAY_RESY - 60) / 2, 200, 60,
|
||||
toi_icon_safeplace + 12, sizeof(toi_icon_safeplace) - 12,
|
||||
COLOR_WELCOME_FG, COLOR_WELCOME_BG);
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
}
|
||||
|
||||
void ui_screen_welcome_third(void) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WELCOME_BG);
|
||||
display_icon((DISPLAY_RESX - 180) / 2, (DISPLAY_RESY - 30) / 2 - 5, 180, 30,
|
||||
toi_icon_welcome + 12, sizeof(toi_icon_welcome) - 12,
|
||||
COLOR_WELCOME_FG, COLOR_WELCOME_BG);
|
||||
display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL,
|
||||
COLOR_WELCOME_FG, COLOR_WELCOME_BG);
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
}
|
||||
|
||||
// info UI
|
||||
|
||||
static int display_vendor_string(const char *text, int textlen,
|
||||
uint16_t fgcolor) {
|
||||
int split = display_text_split(text, textlen, FONT_NORMAL, DISPLAY_RESX - 55);
|
||||
if (split >= textlen) {
|
||||
display_text(55, 95, text, textlen, FONT_NORMAL, fgcolor, COLOR_BL_BG);
|
||||
return 120;
|
||||
} else {
|
||||
display_text(55, 95, text, split, FONT_NORMAL, fgcolor, COLOR_BL_BG);
|
||||
if (text[split] == ' ') {
|
||||
split++;
|
||||
}
|
||||
display_text(55, 120, text + split, textlen - split, FONT_NORMAL, fgcolor,
|
||||
COLOR_BL_BG);
|
||||
return 145;
|
||||
}
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
}
|
||||
|
||||
void ui_screen_firmware_info(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
const char *ver_str = format_ver("Bootloader %d.%d.%d", VERSION_UINT32);
|
||||
display_text(16, 32, ver_str, -1, FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG);
|
||||
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG);
|
||||
display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12,
|
||||
COLOR_BL_GRAY, COLOR_BL_BG);
|
||||
if (vhdr && hdr) {
|
||||
ver_str = format_ver("Firmware %d.%d.%d by", (hdr->version));
|
||||
display_text(55, 70, ver_str, -1, FONT_NORMAL, COLOR_BL_GRAY, COLOR_BL_BG);
|
||||
display_vendor_string(vhdr->vstr, vhdr->vstr_len, COLOR_BL_GRAY);
|
||||
} else {
|
||||
display_text(55, 70, "No Firmware", -1, FONT_NORMAL, COLOR_BL_GRAY,
|
||||
COLOR_BL_BG);
|
||||
}
|
||||
display_text_center(120, 220, "Go to trezor.io/start", -1, FONT_NORMAL,
|
||||
COLOR_BL_FG, COLOR_BL_BG);
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
uint32_t ui_screen_menu(void) {
|
||||
char bld_ver[32];
|
||||
format_ver("%d.%d.%d", VERSION_UINT32, bld_ver, sizeof(bld_ver));
|
||||
return screen_menu(bld_ver);
|
||||
}
|
||||
|
||||
// install UI
|
||||
|
||||
void ui_screen_install_confirm_upgrade(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
display_text(16, 32, "Firmware update", -1, FONT_NORMAL, COLOR_BL_FG,
|
||||
COLOR_BL_BG);
|
||||
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG);
|
||||
display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12,
|
||||
COLOR_BL_FG, COLOR_BL_BG);
|
||||
display_text(55, 70, "Update firmware by", -1, FONT_NORMAL, COLOR_BL_FG,
|
||||
COLOR_BL_BG);
|
||||
int next_y = display_vendor_string(vhdr->vstr, vhdr->vstr_len, COLOR_BL_FG);
|
||||
const char *ver_str = format_ver("to version %d.%d.%d?", hdr->version);
|
||||
display_text(55, next_y, ver_str, -1, FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG);
|
||||
ui_confirm_cancel_buttons();
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
uint32_t ui_screen_install_confirm_upgrade(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
uint8_t fingerprint[32];
|
||||
char ver_str[64];
|
||||
get_image_fingerprint(hdr, fingerprint);
|
||||
format_ver("%d.%d.%d", hdr->version, ver_str, sizeof(ver_str));
|
||||
return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str,
|
||||
fingerprint, false, false);
|
||||
}
|
||||
|
||||
void ui_screen_install_confirm_newvendor_or_downgrade_wipe(
|
||||
uint32_t ui_screen_install_confirm_newvendor_or_downgrade_wipe(
|
||||
const vendor_header *const vhdr, const image_header *const hdr,
|
||||
secbool downgrade_wipe) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
display_text(
|
||||
16, 32,
|
||||
(sectrue == downgrade_wipe) ? "Firmware downgrade" : "Vendor change", -1,
|
||||
FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG);
|
||||
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG);
|
||||
display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12,
|
||||
COLOR_BL_FG, COLOR_BL_BG);
|
||||
display_text(55, 70, "Install firmware by", -1, FONT_NORMAL, COLOR_BL_FG,
|
||||
COLOR_BL_BG);
|
||||
int next_y = display_vendor_string(vhdr->vstr, vhdr->vstr_len, COLOR_BL_FG);
|
||||
const char *ver_str = format_ver("(version %d.%d.%d)?", hdr->version);
|
||||
display_text(55, next_y, ver_str, -1, FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG);
|
||||
display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL,
|
||||
COLOR_BL_FAIL, COLOR_BL_BG);
|
||||
ui_confirm_cancel_buttons();
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
uint8_t fingerprint[32];
|
||||
char ver_str[64];
|
||||
get_image_fingerprint(hdr, fingerprint);
|
||||
format_ver("%d.%d.%d", hdr->version, ver_str, sizeof(ver_str));
|
||||
if (downgrade_wipe) {
|
||||
return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str,
|
||||
fingerprint, true, false);
|
||||
} else {
|
||||
return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str,
|
||||
fingerprint, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ui_screen_install_start(void) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
display_loader(0, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG, toi_icon_install,
|
||||
sizeof(toi_icon_install), COLOR_BL_FG);
|
||||
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24,
|
||||
"Installing firmware", -1, FONT_NORMAL, COLOR_BL_FG,
|
||||
COLOR_BL_BG);
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
void ui_screen_install_start() {
|
||||
screen_install_progress(0, true, initial_setup);
|
||||
}
|
||||
|
||||
void ui_screen_install_progress_erase(int pos, int len) {
|
||||
display_loader(250 * pos / len, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG,
|
||||
toi_icon_install, sizeof(toi_icon_install), COLOR_BL_FG);
|
||||
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
screen_install_progress(250 * pos / len, false, initial_setup);
|
||||
}
|
||||
|
||||
void ui_screen_install_progress_upload(int pos) {
|
||||
display_loader(pos, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG,
|
||||
toi_icon_install, sizeof(toi_icon_install), COLOR_BL_FG);
|
||||
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
screen_install_progress(pos, false, initial_setup);
|
||||
}
|
||||
|
||||
// wipe UI
|
||||
|
||||
void ui_screen_wipe_confirm(void) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
display_text(16, 32, "Wipe device", -1, FONT_NORMAL, COLOR_BL_FG,
|
||||
COLOR_BL_BG);
|
||||
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG);
|
||||
display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12,
|
||||
COLOR_BL_FG, COLOR_BL_BG);
|
||||
display_text(55, 70, "Do you want to", -1, FONT_NORMAL, COLOR_BL_FG,
|
||||
COLOR_BL_BG);
|
||||
display_text(55, 95, "wipe the device?", -1, FONT_NORMAL, COLOR_BL_FG,
|
||||
COLOR_BL_BG);
|
||||
uint32_t ui_screen_wipe_confirm(void) { return screen_wipe_confirm(); }
|
||||
|
||||
display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL,
|
||||
COLOR_BL_FAIL, COLOR_BL_BG);
|
||||
ui_confirm_cancel_buttons();
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
}
|
||||
|
||||
void ui_screen_wipe(void) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
display_loader(0, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG, toi_icon_wipe,
|
||||
sizeof(toi_icon_wipe), COLOR_BL_FG);
|
||||
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, "Wiping device", -1,
|
||||
FONT_NORMAL, COLOR_BL_FG, COLOR_BL_BG);
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
}
|
||||
void ui_screen_wipe(void) { screen_wipe_progress(0, true); }
|
||||
|
||||
void ui_screen_wipe_progress(int pos, int len) {
|
||||
display_loader(1000 * pos / len, false, -20, COLOR_BL_PROCESS, COLOR_BL_BG,
|
||||
toi_icon_wipe, sizeof(toi_icon_wipe), COLOR_BL_FG);
|
||||
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
screen_wipe_progress(1000 * pos / len, false);
|
||||
}
|
||||
|
||||
// done UI
|
||||
|
||||
void ui_screen_done(int restart_seconds, secbool full_redraw) {
|
||||
const char *str;
|
||||
char count_str[24];
|
||||
@ -336,34 +196,16 @@ void ui_screen_done(int restart_seconds, secbool full_redraw) {
|
||||
} else {
|
||||
str = "Done! Unplug the device.";
|
||||
}
|
||||
if (sectrue == full_redraw) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
}
|
||||
display_loader(1000, false, -20, COLOR_BL_DONE, COLOR_BL_BG, toi_icon_done,
|
||||
sizeof(toi_icon_done), COLOR_BL_FG);
|
||||
if (secfalse == full_redraw) {
|
||||
display_bar(0, DISPLAY_RESY - 24 - 18, 240, 23, COLOR_BL_BG);
|
||||
}
|
||||
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24, str, -1, FONT_NORMAL,
|
||||
COLOR_BL_FG, COLOR_BL_BG);
|
||||
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
screen_install_success(str, initial_setup, full_redraw);
|
||||
}
|
||||
|
||||
void ui_screen_boot_empty(bool firmware_present, bool fading) {
|
||||
screen_boot_empty(firmware_present, fading);
|
||||
}
|
||||
|
||||
// error UI
|
||||
|
||||
void ui_screen_fail(void) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
display_loader(1000, false, -20, COLOR_BL_FAIL, COLOR_BL_BG, toi_icon_fail,
|
||||
sizeof(toi_icon_fail), COLOR_BL_FG);
|
||||
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 24,
|
||||
"Failed! Please, reconnect.", -1, FONT_NORMAL,
|
||||
COLOR_BL_FG, COLOR_BL_BG);
|
||||
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
}
|
||||
void ui_screen_fail(void) { screen_install_fail(); }
|
||||
|
||||
// general functions
|
||||
|
||||
@ -373,43 +215,3 @@ void ui_fadeout(void) {
|
||||
display_fade(BACKLIGHT_NORMAL, 0, 500);
|
||||
display_clear();
|
||||
}
|
||||
|
||||
int ui_user_input(int zones) {
|
||||
for (;;) {
|
||||
#if defined USE_TOUCH
|
||||
uint32_t evt = touch_click();
|
||||
uint16_t x = touch_unpack_x(evt);
|
||||
uint16_t y = touch_unpack_y(evt);
|
||||
// clicked on Cancel button
|
||||
if ((zones & INPUT_CANCEL) && x >= 9 && x < 9 + 108 && y > 184 &&
|
||||
y < 184 + 50) {
|
||||
return INPUT_CANCEL;
|
||||
}
|
||||
// clicked on Confirm button
|
||||
if ((zones & INPUT_CONFIRM) && x >= 123 && x < 123 + 108 && y > 184 &&
|
||||
y < 184 + 50) {
|
||||
return INPUT_CONFIRM;
|
||||
}
|
||||
// clicked on Long Confirm button
|
||||
if ((zones & INPUT_LONG_CONFIRM) && x >= 9 && x < 9 + 222 && y > 184 &&
|
||||
y < 184 + 50) {
|
||||
return INPUT_LONG_CONFIRM;
|
||||
}
|
||||
// clicked on Info icon
|
||||
if ((zones & INPUT_INFO) && x >= 16 && x < 16 + 32 && y > 54 &&
|
||||
y < 54 + 32) {
|
||||
return INPUT_INFO;
|
||||
}
|
||||
#elif defined USE_BUTTON
|
||||
uint32_t evt = button_read();
|
||||
if (evt == (BTN_LEFT | BTN_EVT_DOWN)) {
|
||||
return INPUT_CANCEL;
|
||||
}
|
||||
if (evt == (BTN_RIGHT | BTN_EVT_DOWN)) {
|
||||
return INPUT_CONFIRM;
|
||||
}
|
||||
#else
|
||||
#error No input method defined
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -22,29 +22,38 @@
|
||||
|
||||
#include "image.h"
|
||||
#include "secbool.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
typedef enum {
|
||||
SCREEN_INTRO = 0,
|
||||
SCREEN_MENU = 1,
|
||||
SCREEN_WIPE_CONFIRM = 2,
|
||||
SCREEN_FINGER_PRINT = 3,
|
||||
SCREEN_WAIT_FOR_HOST = 4,
|
||||
} screen_t;
|
||||
|
||||
void ui_screen_boot(const vendor_header* const vhdr,
|
||||
const image_header* const hdr);
|
||||
void ui_screen_boot_wait(int wait_seconds);
|
||||
void ui_screen_boot_click(void);
|
||||
|
||||
void ui_screen_welcome_first(void);
|
||||
void ui_screen_welcome_second(void);
|
||||
void ui_screen_welcome_third(void);
|
||||
void ui_screen_welcome(void);
|
||||
|
||||
void ui_screen_firmware_info(const vendor_header* const vhdr,
|
||||
const image_header* const hdr);
|
||||
uint32_t ui_screen_intro(const vendor_header* const vhdr,
|
||||
const image_header* const hdr);
|
||||
|
||||
void ui_screen_install_confirm_upgrade(const vendor_header* const vhdr,
|
||||
const image_header* const hdr);
|
||||
void ui_screen_install_confirm_newvendor_or_downgrade_wipe(
|
||||
uint32_t ui_screen_menu(void);
|
||||
|
||||
uint32_t ui_screen_install_confirm_upgrade(const vendor_header* const vhdr,
|
||||
const image_header* const hdr);
|
||||
uint32_t ui_screen_install_confirm_newvendor_or_downgrade_wipe(
|
||||
const vendor_header* const vhdr, const image_header* const hdr,
|
||||
secbool downgrade_wipe);
|
||||
void ui_screen_install_start(void);
|
||||
void ui_screen_install_start();
|
||||
void ui_screen_install_progress_erase(int pos, int len);
|
||||
void ui_screen_install_progress_upload(int pos);
|
||||
|
||||
void ui_screen_wipe_confirm(void);
|
||||
uint32_t ui_screen_wipe_confirm(void);
|
||||
void ui_screen_wipe(void);
|
||||
void ui_screen_wipe_progress(int pos, int len);
|
||||
|
||||
@ -54,6 +63,9 @@ void ui_screen_fail(void);
|
||||
|
||||
void ui_fadein(void);
|
||||
void ui_fadeout(void);
|
||||
void ui_set_initial_setup(bool initial);
|
||||
|
||||
void ui_screen_boot_empty(bool firmware_present, bool fading);
|
||||
|
||||
// clang-format off
|
||||
#define INPUT_CANCEL 0x01 // Cancel button
|
||||
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_cancel[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x10, 0x00, 0x10, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x52, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x45, 0x4d, 0xc1, 0x09, 0x80, 0x30, 0x10, 0x4b, 0xcf, 0x05, 0xba, 0x80, 0xd0, 0x01, 0x2c, 0xb8, 0xff, 0x47, 0x70, 0x01, 0xb1, 0x0b, 0xdc, 0x20, 0xb6, 0xc4, 0x48, 0x5b, 0x0c, 0x1c, 0x09, 0xe1, 0x92, 0xe0, 0x0c, 0x40, 0xdc, 0x90, 0x5a, 0x06, 0x8a, 0x5b, 0xa1, 0x5b, 0x6a, 0xcc, 0x0f, 0xb9, 0xde, 0xe4, 0xa1, 0xf3, 0x26, 0x9d, 0x2a, 0x85, 0xcb, 0x50, 0x3e, 0xd6, 0x6f, 0x94, 0xeb, 0xe1, 0xe7, 0xe1, 0x2b, 0x2b, 0xb8, 0xcd, 0x5c, 0xed, 0x3d, 0xd7, 0xec, 0xdd, 0xfb, 0xce, 0x82, 0xb1, 0xfb, 0x02,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_confirm[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x14, 0x00, 0x10, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x69, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x63, 0x60, 0x80, 0x80, 0x48, 0x28, 0xcd, 0x30, 0xe1, 0x3f, 0x2b, 0x94, 0xf5, 0xe3, 0x7f, 0x3c, 0x84, 0xd1, 0xf0, 0xff, 0xff, 0x7a, 0x08, 0xeb, 0xfb, 0xff, 0xff, 0xdc, 0x60, 0x46, 0xc1, 0xff, 0xff, 0xfb, 0x19, 0x18, 0x1c, 0x38, 0x19, 0x18, 0xbe, 0x81, 0x85, 0xbe, 0xcc, 0x67, 0x48, 0x00, 0x0a, 0x31, 0x32, 0x38, 0xfc, 0xff, 0x2f, 0xf1, 0xec, 0xff, 0x7f, 0x69, 0x06, 0x86, 0x05, 0x40, 0xfe, 0x3f, 0x90, 0x10, 0x83, 0xc0, 0xef, 0xff, 0x40, 0xa0, 0x0d, 0xd2, 0xb7, 0x11, 0xc8, 0xd8, 0xcf, 0x04, 0x62, 0x81, 0x04, 0x75, 0x20, 0xa6, 0x6e, 0xfa, 0x7f, 0x9e, 0x19, 0xc2, 0x52, 0xf8, 0x6d, 0x03, 0x73, 0xc7, 0x62, 0x16, 0x30, 0x05, 0x00,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_done[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x40, 0x00, 0x40, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0xce, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x63, 0x60, 0x18, 0x05, 0x23, 0x0f, 0x4c, 0xe0, 0xc6, 0x2f, 0xff, 0xfb, 0x3e, 0x7e, 0xed, 0xff, 0xff, 0x4b, 0xe3, 0x93, 0xff, 0xf5, 0xff, 0xff, 0x79, 0xfc, 0xda, 0xff, 0xff, 0xe7, 0xc1, 0x2d, 0xff, 0x03, 0x24, 0xbf, 0x1f, 0xa7, 0xf4, 0x82, 0xff, 0x60, 0xc0, 0x89, 0x57, 0xfb, 0xff, 0xfb, 0x78, 0x6d, 0xff, 0xff, 0x5f, 0x17, 0xbf, 0xf6, 0xf7, 0x8c, 0x38, 0xa4, 0x1b, 0x88, 0xd3, 0xce, 0x84, 0x5f, 0xbb, 0x2c, 0x86, 0xab, 0xa4, 0xf1, 0x6b, 0x87, 0xc6, 0x08, 0xd4, 0xf1, 0x72, 0x58, 0x3c, 0x25, 0x03, 0xa2, 0xbf, 0x43, 0xfc, 0x8e, 0xa1, 0xfd, 0x27, 0x24, 0x46, 0xa0, 0xb6, 0xeb, 0x61, 0x0d, 0x52, 0x59, 0x98, 0xf6, 0xf7, 0xd8, 0xb4, 0x83, 0x62, 0xa4, 0x00, 0x87, 0xdf, 0xa1, 0xc6, 0xf2, 0x7d, 0x83, 0xd0, 0xcc, 0xe8, 0xf2, 0x06, 0xff, 0x20, 0xce, 0xc2, 0x61, 0x3b, 0x03, 0xc3, 0xe7, 0xff, 0x48, 0x80, 0x19, 0x53, 0xde, 0x00, 0x49, 0x5a, 0x1e, 0x5b, 0xb0, 0x3e, 0x86, 0x4b, 0xbf, 0x67, 0xc6, 0x26, 0x8f, 0x30, 0x40, 0x1f, 0x7b, 0xbc, 0x3c, 0xc5, 0xab, 0x1d, 0x61, 0x80, 0x3d, 0xae, 0x78, 0xff, 0x8a, 0xd3, 0xf1, 0xc8, 0x06, 0xd8, 0xe3, 0x4e, 0xf5, 0x9f, 0xf1, 0x6a, 0x67, 0x60, 0x08, 0x00, 0x4a, 0xfb, 0x33, 0xe0, 0x01, 0x4f, 0xfe, 0xff, 0x67, 0xc1, 0x27, 0x9f, 0x80, 0x5f, 0x3b, 0x03, 0xc3, 0x15, 0x16, 0x86, 0x51, 0x30, 0xc2, 0x00, 0x00,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_fail[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x40, 0x00, 0x40, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x21, 0x01, 0x00, 0x00,
|
||||
// compressed data
|
||||
0xed, 0x52, 0x39, 0x12, 0x82, 0x40, 0x10, 0x44, 0x17, 0x88, 0x7d, 0x82, 0x1f, 0xd0, 0xe2, 0x05, 0x2e, 0x0f, 0xb0, 0x84, 0x1f, 0xc0, 0x0f, 0x7c, 0xa2, 0x89, 0xb9, 0x55, 0xfe, 0xc0, 0x23, 0xdf, 0xc0, 0x23, 0xd1, 0x62, 0x14, 0xd8, 0x65, 0xf6, 0xe8, 0x22, 0x36, 0xb0, 0xa3, 0xae, 0x69, 0x66, 0xd8, 0x9e, 0xe9, 0x28, 0xfa, 0xe3, 0x27, 0x30, 0x5f, 0x33, 0xdf, 0x4f, 0x43, 0xfd, 0x44, 0xa9, 0xa1, 0x35, 0x2d, 0xc3, 0xf6, 0x86, 0x0a, 0xc3, 0xef, 0xa4, 0x82, 0x01, 0x47, 0x22, 0x4a, 0x7a, 0x5a, 0x7e, 0xe9, 0x22, 0x6c, 0x27, 0xaa, 0x7a, 0xfe, 0xf8, 0x52, 0x7f, 0x40, 0xdb, 0x4e, 0x14, 0xb7, 0x34, 0xef, 0xa8, 0x3b, 0x60, 0xd6, 0x74, 0xc5, 0x6d, 0xcb, 0x9f, 0x1d, 0x55, 0x13, 0x5b, 0x3f, 0x13, 0x99, 0x01, 0xb9, 0xa6, 0x8e, 0x85, 0x97, 0x2e, 0x16, 0xed, 0xe3, 0x7b, 0xec, 0x6c, 0xfd, 0xa6, 0x8b, 0x94, 0xd6, 0x86, 0x49, 0x5b, 0x37, 0x43, 0xa9, 0x30, 0xed, 0xfd, 0x5b, 0x07, 0x5c, 0x74, 0x55, 0x35, 0x9a, 0xac, 0x5c, 0x7f, 0x19, 0x79, 0x10, 0xde, 0x82, 0xae, 0xae, 0xbc, 0xf1, 0xf7, 0x9b, 0x8d, 0xb7, 0xb3, 0x2f, 0xe3, 0x33, 0x18, 0xd0, 0xb0, 0xac, 0x04, 0x08, 0xc8, 0x8d, 0x75, 0x89, 0x02, 0x94, 0x0f, 0x03, 0x54, 0x0c, 0x13, 0x66, 0x76, 0xe0, 0x7b, 0x0f, 0x2c, 0x6e, 0xa0, 0x5c, 0xf3, 0xff, 0x53, 0xa4, 0xdf, 0x47, 0xed, 0xf1, 0x89, 0xc2, 0xe3, 0x44, 0x1c, 0x1b, 0x8d, 0xed, 0x78, 0x3b, 0x18, 0xf0, 0x70, 0xf5, 0xca, 0x93, 0x4b, 0xff, 0xbe, 0x31, 0x5e, 0xee, 0x90, 0x0f, 0x89, 0xdb, 0xe5, 0x70, 0x85, 0x04, 0x7a, 0x4f, 0x4a, 0xb8, 0x83, 0x77, 0x98, 0xef, 0x03, 0xfa, 0xbd, 0xe0, 0x20, 0x49, 0x90, 0xae, 0xca, 0x72, 0x2a, 0xc0, 0x6d, 0x05, 0x7f, 0x8b, 0xf2, 0x5d, 0x59, 0xab, 0x12, 0x20, 0x1c, 0x31, 0xaf, 0x7a, 0x05, 0xf2, 0x2d, 0xad, 0xd7, 0x0a, 0x10, 0xcf, 0x84, 0xb7, 0x05, 0x02, 0x9a, 0xad, 0x99, 0xef, 0x45, 0xf4, 0xc7, 0x6f, 0xe0, 0x03,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_info[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x20, 0x00, 0x20, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0xde, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x7d, 0x91, 0x3d, 0x0a, 0xc2, 0x40, 0x10, 0x85, 0x27, 0x10, 0xfc, 0x05, 0xe3, 0x0d, 0xbc, 0x82, 0xa0, 0x07, 0x10, 0x3c, 0x80, 0xde, 0x20, 0xf6, 0x22, 0xd8, 0x5b, 0xc4, 0xde, 0x42, 0x6f, 0x60, 0x67, 0x91, 0x46, 0x4b, 0x3b, 0xc5, 0x0b, 0xe4, 0x06, 0xba, 0x17, 0x10, 0x21, 0x10, 0x45, 0x89, 0x3e, 0x37, 0x3b, 0xbb, 0xa8, 0xab, 0x38, 0xc5, 0xce, 0x7e, 0x30, 0x3b, 0xb3, 0xf3, 0x1e, 0x91, 0x8c, 0xfa, 0xfa, 0xb8, 0x9f, 0xb8, 0x64, 0x62, 0x0c, 0x15, 0x45, 0x8d, 0x3d, 0xe8, 0x28, 0x30, 0xa7, 0xc0, 0xa8, 0xd9, 0x5e, 0x00, 0x07, 0x85, 0x02, 0xc8, 0xeb, 0xb2, 0x5a, 0x96, 0x1f, 0x28, 0x73, 0xdd, 0x0c, 0x70, 0x88, 0x56, 0x08, 0x4c, 0xdf, 0x04, 0x15, 0xa2, 0xb3, 0xaa, 0x4e, 0x96, 0xf2, 0xe8, 0x62, 0x4a, 0x84, 0x8d, 0xbc, 0x55, 0x81, 0x9c, 0x4c, 0x57, 0x38, 0x43, 0x78, 0xf2, 0xd2, 0xe2, 0xe9, 0x02, 0x45, 0xc1, 0x53, 0x01, 0x57, 0x3d, 0xf0, 0x62, 0xa8, 0x56, 0xbb, 0x81, 0x4a, 0xf0, 0x2f, 0x11, 0xbd, 0xc5, 0x6d, 0x7e, 0x0b, 0xde, 0x39, 0x89, 0x52, 0x9f, 0x5e, 0xfd, 0x29, 0x3e, 0xdd, 0x3b, 0xff, 0xd9, 0xae, 0xe7, 0x7e, 0x86, 0x93, 0x88, 0xe7, 0x19, 0xbe, 0xce, 0xf9, 0x3f, 0x86, 0xe1, 0x0b, 0xb5, 0x9e, 0x66, 0xf9, 0x5f, 0xde, 0x47, 0xb3, 0x40, 0xc9, 0xde, 0x57, 0xeb, 0x11, 0x86, 0xae, 0xd6, 0x63, 0x6b, 0xe9, 0x65, 0xeb, 0xf9, 0xa5, 0x77, 0xe6, 0x47, 0xbf, 0xd9, 0x90, 0x7e, 0x9c, 0x9c, 0x9f, 0x7e, 0xd9, 0x7e, 0x7e, 0xf8, 0xfd, 0x04,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_install[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x40, 0x00, 0x40, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0xb8, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x63, 0x60, 0x18, 0x05, 0xa3, 0x80, 0x58, 0xe0, 0xec, 0xe2, 0x62, 0x82, 0x4f, 0xfe, 0xcf, 0xff, 0xff, 0xe7, 0x47, 0xe5, 0xc9, 0x93, 0x3f, 0x85, 0x90, 0x5f, 0x83, 0x45, 0x7a, 0xc1, 0x7f, 0x5e, 0x98, 0xfc, 0x85, 0xff, 0x5c, 0x98, 0xf2, 0xbf, 0xfe, 0xef, 0x87, 0xc9, 0xff, 0xfe, 0xbf, 0x1e, 0x43, 0xfa, 0xc0, 0xff, 0xff, 0x40, 0x03, 0xc0, 0xf2, 0x17, 0x80, 0x4c, 0x1e, 0x74, 0x79, 0x07, 0xa0, 0xe0, 0x79, 0x46, 0x90, 0xbc, 0x00, 0x90, 0xf8, 0xcf, 0x82, 0x61, 0xc0, 0x17, 0xa0, 0xa8, 0x2e, 0x48, 0xfe, 0x12, 0x90, 0xe1, 0x8f, 0x69, 0xbf, 0x02, 0x50, 0xf8, 0xfd, 0x3f, 0x08, 0xfe, 0xcf, 0x84, 0xc5, 0x03, 0x20, 0x03, 0xa0, 0xc0, 0x1f, 0x9b, 0xff, 0x15, 0x10, 0xf2, 0x4c, 0x58, 0x03, 0xe8, 0x13, 0x4c, 0x5a, 0x1f, 0x7b, 0x00, 0x1a, 0xc0, 0xe4, 0x99, 0x71, 0x84, 0xf0, 0x63, 0x88, 0xb4, 0x1e, 0xae, 0x18, 0x50, 0x00, 0x39, 0xfd, 0xff, 0x7b, 0x26, 0x9c, 0xd1, 0x77, 0x11, 0x24, 0x2f, 0x8b, 0x3b, 0x7a, 0x05, 0xfe, 0xfe, 0xff, 0x7f, 0x9f, 0x11, 0x4f, 0xfc, 0x1f, 0xfc, 0xff, 0x5f, 0x86, 0x01, 0x6f, 0x02, 0xc1, 0x9b, 0x7c, 0x80, 0x06, 0xe0, 0xd7, 0xce, 0x20, 0xc0, 0xc8, 0x30, 0x0a, 0x46, 0x01, 0xf1, 0x00, 0x00,
|
||||
};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_welcome[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0xb4, 0x00, 0x1e, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x32, 0x03, 0x00, 0x00,
|
||||
// compressed data
|
||||
0xc5, 0x52, 0xc1, 0x4e, 0x13, 0x51, 0x14, 0xbd, 0x50, 0xa0, 0x50, 0x2c, 0x74, 0xa7, 0x0b, 0x11, 0xbe, 0x80, 0xf2, 0x07, 0xf0, 0x07, 0xfa, 0x03, 0x06, 0x56, 0x6c, 0xdb, 0xb8, 0xc2, 0x15, 0x26, 0x2e, 0xd8, 0x90, 0x40, 0x22, 0x89, 0x1b, 0x05, 0x34, 0x26, 0xec, 0x6c, 0xf5, 0x03, 0x04, 0x75, 0xe1, 0xb2, 0xc4, 0x95, 0x3b, 0x4a, 0xe2, 0xc6, 0x28, 0x4e, 0x29, 0x50, 0x5a, 0xa0, 0x73, 0x3c, 0xf7, 0xbe, 0xe9, 0x74, 0x3a, 0x40, 0x62, 0xa4, 0x89, 0x77, 0x31, 0x73, 0xdf, 0x7b, 0xf7, 0x9c, 0x77, 0xdf, 0xb9, 0x47, 0xe4, 0x3f, 0x05, 0x30, 0x7b, 0x13, 0xf8, 0x11, 0xd0, 0xc7, 0xdf, 0x05, 0xb2, 0xfc, 0x56, 0x80, 0xc1, 0x9b, 0x31, 0x47, 0x30, 0x24, 0x4b, 0x86, 0x3b, 0x55, 0xa0, 0xbf, 0x6b, 0xcc, 0x3b, 0x40, 0x4a, 0x64, 0x06, 0xd8, 0xe0, 0xe2, 0x04, 0xe8, 0xe9, 0x1a, 0xf3, 0x2a, 0x90, 0x16, 0xc9, 0x03, 0x25, 0x2e, 0xea, 0xf0, 0xa4, 0x6b, 0xcc, 0x73, 0xc0, 0xa8, 0x48, 0x11, 0x00, 0x17, 0xe7, 0x28, 0x74, 0x8f, 0x79, 0x02, 0x98, 0x16, 0x29, 0x93, 0x39, 0x21, 0xe2, 0x63, 0xb1, 0x7b, 0xcc, 0xcc, 0x73, 0x36, 0x3a, 0x0e, 0x32, 0x63, 0xb7, 0x74, 0x8d, 0xf9, 0x5c, 0x67, 0xc7, 0xd1, 0x61, 0x58, 0xe7, 0x48, 0x65, 0xe4, 0xe9, 0x2f, 0x6f, 0x39, 0xd1, 0xae, 0x5a, 0x3b, 0xf0, 0x5e, 0x24, 0xac, 0x94, 0x07, 0x96, 0xd1, 0x4f, 0x3d, 0x6f, 0x9a, 0x7b, 0x77, 0x24, 0xf3, 0xc5, 0x7f, 0x1b, 0x1e, 0x45, 0x31, 0x16, 0x75, 0x9d, 0x5d, 0x83, 0xcc, 0x23, 0x3a, 0x47, 0x4e, 0xf3, 0x15, 0x73, 0xd3, 0xdb, 0x55, 0x7d, 0xb2, 0xa5, 0x5a, 0xe6, 0x9d, 0x66, 0xdb, 0x3d, 0xc6, 0xfc, 0x9a, 0xa9, 0x97, 0xd0, 0x86, 0x56, 0x94, 0x24, 0x86, 0x71, 0x71, 0xac, 0xb3, 0x6b, 0xa2, 0x89, 0xac, 0x6c, 0x02, 0x43, 0x92, 0x69, 0x6a, 0x15, 0xee, 0x06, 0x55, 0x53, 0xbe, 0x2d, 0xc7, 0x38, 0x11, 0x97, 0x4d, 0x1a, 0xb3, 0xe5, 0x0f, 0x6d, 0x63, 0x40, 0xe2, 0x98, 0x20, 0x0e, 0x81, 0x5e, 0x6e, 0xd4, 0xb8, 0xb5, 0xab, 0x65, 0xbb, 0x56, 0xa4, 0x0d, 0x58, 0xd5, 0xbe, 0x5b, 0x6e, 0x4b, 0xeb, 0x60, 0xcf, 0x98, 0x23, 0x31, 0x22, 0x71, 0x4c, 0x10, 0xb4, 0x45, 0x3f, 0x05, 0xfe, 0x4a, 0xb9, 0x2b, 0x7a, 0x49, 0x1d, 0x58, 0x5f, 0xf2, 0xd5, 0x2a, 0x56, 0x45, 0x9d, 0x96, 0xb7, 0x88, 0xea, 0xd3, 0x6c, 0xfd, 0xb9, 0xaf, 0xcf, 0x52, 0xe6, 0xc7, 0x3f, 0x54, 0x8f, 0x85, 0x33, 0xe0, 0xbe, 0xc4, 0x31, 0x41, 0x50, 0x82, 0xc1, 0x3c, 0xbc, 0x55, 0x36, 0x53, 0x55, 0x61, 0xac, 0xbf, 0x1d, 0x20, 0x65, 0x55, 0xb4, 0xcb, 0x86, 0x29, 0x96, 0x62, 0xc6, 0x81, 0x7c, 0x04, 0xc6, 0x95, 0x79, 0x52, 0x15, 0xc4, 0x2d, 0x99, 0x82, 0x1a, 0xb5, 0x13, 0xd3, 0x0a, 0x8e, 0x2d, 0x55, 0x44, 0xe1, 0x01, 0x59, 0x4f, 0x88, 0x9d, 0x53, 0xa8, 0x02, 0x46, 0xad, 0x2a, 0x6f, 0x76, 0xe1, 0xed, 0x69, 0x1e, 0x64, 0xed, 0x20, 0xa7, 0xcc, 0x14, 0xf7, 0x54, 0x5f, 0x48, 0xfe, 0x95, 0x38, 0xa6, 0x15, 0xdc, 0x48, 0x97, 0x91, 0x63, 0x4b, 0x7d, 0x75, 0x56, 0x6d, 0xea, 0xcd, 0xda, 0x45, 0xd6, 0xaa, 0x8a, 0xea, 0x46, 0x85, 0x8e, 0x6c, 0x6a, 0x8b, 0xca, 0x54, 0x50, 0xe6, 0x7e, 0x91, 0x9a, 0xbe, 0xd0, 0x4c, 0x1b, 0xc3, 0x44, 0xcc, 0x3d, 0x5a, 0xc5, 0xb4, 0xf8, 0x48, 0x9e, 0xbb, 0x29, 0xba, 0xb8, 0x6f, 0x55, 0x9c, 0xc2, 0xa0, 0x2b, 0xdb, 0x75, 0x59, 0x9d, 0xaa, 0x39, 0xe6, 0x93, 0x80, 0xb9, 0x10, 0xc7, 0x84, 0x71, 0x81, 0xe9, 0x1a, 0xdf, 0x71, 0x86, 0x61, 0x9f, 0x8f, 0x2a, 0xb7, 0xaa, 0x66, 0xad, 0xca, 0x3d, 0x5c, 0x83, 0x59, 0x52, 0x4c, 0x83, 0x4b, 0xcc, 0x31, 0x4c, 0x18, 0x0d, 0xe4, 0x1a, 0x7c, 0x72, 0x0d, 0xf7, 0xd4, 0x41, 0x95, 0x4b, 0xcc, 0xfd, 0x21, 0xb3, 0x66, 0x27, 0x57, 0x30, 0x57, 0xae, 0x61, 0xae, 0x61, 0xa3, 0xc9, 0x76, 0xaa, 0x58, 0x54, 0xb9, 0x2a, 0xff, 0xd0, 0xf3, 0x75, 0xcc, 0x55, 0xec, 0xa9, 0x5d, 0xcb, 0xfa, 0x4b, 0xea, 0xcb, 0x86, 0xc2, 0x01, 0xfc, 0xa5, 0xce, 0x11, 0x4c, 0x47, 0xd8, 0x8d, 0xa2, 0x2e, 0xd0, 0x0b, 0x8a, 0x2a, 0x49, 0x9b, 0xd9, 0x79, 0x63, 0x62, 0x7e, 0x7e, 0xa0, 0xe8, 0xbc, 0x71, 0x11, 0x7a, 0xa3, 0xcd, 0x1c, 0xc1, 0x74, 0x84, 0x52, 0x96, 0xcc, 0xd7, 0x5a, 0x9a, 0x57, 0xc3, 0x92, 0x6b, 0x40, 0x22, 0x7e, 0x7e, 0x42, 0x68, 0xde, 0xfc, 0x3c, 0x01, 0x2c, 0x5e, 0x62, 0x8e, 0x60, 0x3a, 0x82, 0x30, 0xfa, 0x58, 0x7d, 0xcd, 0x87, 0x4a, 0xc6, 0x3a, 0x97, 0xef, 0xb3, 0x8e, 0x39, 0x63, 0x67, 0x47, 0xec, 0x3c, 0x63, 0xf7, 0xef, 0x80, 0xfe, 0x89, 0x33, 0x47, 0x30, 0xab, 0xbf, 0x23, 0xba, 0xcc, 0xc0, 0xc9, 0xce, 0xdf, 0x86, 0x09, 0x89, 0xd2, 0xc2, 0x37, 0x2d, 0xb5, 0xed, 0x33, 0x60, 0x79, 0x0b, 0x4a, 0xd5, 0x00, 0xd6, 0x97, 0x7c, 0x95, 0x34, 0xce, 0x1c, 0xc1, 0x34, 0x8c, 0x23, 0x08, 0xbd, 0x71, 0xdc, 0x14, 0xb4, 0x37, 0xb5, 0x6c, 0x9f, 0x72, 0xcc, 0xfb, 0x6e, 0x55, 0x0a, 0x0f, 0x3c, 0xb9, 0xcc, 0xdc, 0xc6, 0xf8, 0x7a, 0x1e, 0x06, 0xfb, 0x48, 0xbb, 0x66, 0xa7, 0xf5, 0xa2, 0xa6, 0x15, 0x6d, 0x3b, 0x35, 0x4c, 0x24, 0xc6, 0x18, 0x65, 0xf4, 0x2d, 0x9b, 0xbc, 0x82, 0xb9, 0x8d, 0xe9, 0x64, 0x3e, 0x73, 0xa6, 0x39, 0xb6, 0x61, 0x51, 0x2a, 0xab, 0x4a, 0x06, 0xcc, 0xf2, 0x59, 0x57, 0x05, 0x3d, 0x78, 0x6f, 0xe8, 0xde, 0x2b, 0x98, 0xdb, 0x98, 0x0e, 0x35, 0xe4, 0x14, 0xd0, 0xa9, 0x1e, 0x3a, 0x5b, 0x89, 0x3c, 0xfa, 0x89, 0x0f, 0xb7, 0xa5, 0xc5, 0x2c, 0x6b, 0x07, 0xde, 0x72, 0xaf, 0x1d, 0x3c, 0x3b, 0xf0, 0x5e, 0xf6, 0xc9, 0x55, 0xcc, 0x21, 0x26, 0x98, 0xe0, 0x1f,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_wipe[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x40, 0x00, 0x40, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x2f, 0x01, 0x00, 0x00,
|
||||
// compressed data
|
||||
0xed, 0xd2, 0x31, 0x4e, 0x02, 0x41, 0x14, 0x06, 0xe0, 0xc7, 0x62, 0x58, 0x41, 0x5d, 0x48, 0xac, 0x35, 0x14, 0xf6, 0x5a, 0x98, 0x58, 0xe2, 0x0d, 0xc6, 0x1b, 0x48, 0x6d, 0x21, 0x5a, 0xd8, 0x99, 0xc8, 0x0d, 0xbc, 0x82, 0x37, 0xc0, 0x23, 0x10, 0x2f, 0x00, 0x89, 0x85, 0xa5, 0xdb, 0x6b, 0x82, 0x80, 0x68, 0x24, 0xe0, 0x73, 0xde, 0xcc, 0x12, 0x27, 0xd9, 0x7f, 0x86, 0x9a, 0x84, 0x3f, 0xd9, 0xc9, 0x66, 0xbf, 0xec, 0xec, 0xec, 0x7b, 0x8f, 0x68, 0x9d, 0xd5, 0xc9, 0xf5, 0x12, 0x1f, 0xb6, 0xc2, 0x3e, 0xe2, 0x4a, 0xd0, 0x3f, 0xb9, 0x13, 0xf4, 0x6f, 0xe6, 0xcd, 0x90, 0x4f, 0x99, 0xd5, 0x6e, 0xc0, 0x67, 0xcc, 0xbd, 0xb4, 0xe8, 0xe5, 0x3a, 0xeb, 0xdc, 0x28, 0x8f, 0x46, 0xd4, 0x14, 0x4f, 0xd8, 0xb3, 0xc1, 0x09, 0x75, 0xc5, 0xd5, 0x6c, 0x0f, 0xfb, 0x05, 0x0d, 0xc5, 0x5f, 0xa7, 0xf7, 0xd8, 0xdf, 0xe4, 0xf8, 0x3a, 0xbf, 0x9e, 0x0f, 0xf0, 0x01, 0x67, 0xd9, 0x41, 0x5c, 0xe3, 0xdb, 0x85, 0xc3, 0x3f, 0x68, 0xf3, 0x60, 0xe1, 0xb0, 0xc8, 0x7d, 0xfe, 0x4f, 0x01, 0xf8, 0xd8, 0xf1, 0x18, 0xf8, 0x8f, 0xe3, 0xdb, 0xe8, 0xf8, 0x4e, 0xaa, 0x79, 0x6e, 0xba, 0x7e, 0x98, 0xf7, 0xae, 0xeb, 0xe0, 0x07, 0x3f, 0xac, 0x5c, 0x9a, 0xb5, 0x85, 0x46, 0xcf, 0x24, 0x99, 0xc8, 0x7a, 0x97, 0xf7, 0x49, 0x56, 0xda, 0x07, 0x59, 0xcf, 0xe1, 0xe8, 0x49, 0xb6, 0x8e, 0x64, 0x6d, 0xe4, 0xfd, 0x4b, 0x9e, 0xbf, 0xf3, 0x86, 0x69, 0x62, 0x15, 0x8d, 0xb6, 0xce, 0xf3, 0xc0, 0xde, 0x80, 0x06, 0xca, 0x6c, 0x74, 0xfa, 0xca, 0xde, 0xc4, 0xb8, 0x3d, 0x8d, 0x54, 0x17, 0x36, 0xc5, 0xfd, 0x91, 0xfa, 0x25, 0xa3, 0x82, 0x71, 0x38, 0x60, 0x73, 0xe6, 0xf2, 0x31, 0x19, 0xdf, 0x27, 0xdc, 0xdf, 0x52, 0x76, 0x90, 0x08, 0xf9, 0x55, 0x76, 0xac, 0x31, 0xaa, 0x8e, 0xad, 0x60, 0xc5, 0x16, 0xaa, 0x84, 0xfd, 0xcc, 0x96, 0x65, 0xae, 0xc8, 0x93, 0x27, 0xd9, 0xf8, 0xb4, 0x17, 0xf9, 0x9c, 0x5e, 0xf4, 0xf5, 0x18, 0x7b, 0x99, 0x6a, 0xfa, 0xd5, 0x3a, 0xad, 0xb3, 0x42, 0xf9, 0x03,
|
||||
};
|
@ -47,7 +47,7 @@
|
||||
|
||||
#include "bootui.h"
|
||||
#include "messages.h"
|
||||
// #include "mpu.h"
|
||||
#include "rust_ui.h"
|
||||
|
||||
const uint8_t BOOTLOADER_KEY_M = 2;
|
||||
const uint8_t BOOTLOADER_KEY_N = 3;
|
||||
@ -63,6 +63,12 @@ static const uint8_t * const BOOTLOADER_KEYS[] = {
|
||||
|
||||
#define USB_IFACE_NUM 0
|
||||
|
||||
typedef enum {
|
||||
CONTINUE = 0,
|
||||
RETURN = 1,
|
||||
SHUTDOWN = 2,
|
||||
} usb_result_t;
|
||||
|
||||
static void usb_init_all(secbool usb21_landing) {
|
||||
usb_dev_info_t dev_info = {
|
||||
.device_class = 0x00,
|
||||
@ -99,8 +105,8 @@ static void usb_init_all(secbool usb21_landing) {
|
||||
usb_start();
|
||||
}
|
||||
|
||||
static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
// if both are NULL, we don't have a firmware installed
|
||||
// let's show a webusb landing page in this case
|
||||
usb_init_all((vhdr == NULL && hdr == NULL) ? sectrue : secfalse);
|
||||
@ -115,6 +121,7 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
}
|
||||
uint16_t msg_id;
|
||||
uint32_t msg_size;
|
||||
uint32_t response;
|
||||
if (sectrue != msg_parse_header(buf, &msg_id, &msg_size)) {
|
||||
// invalid header -> discard
|
||||
continue;
|
||||
@ -127,35 +134,26 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
process_msg_Ping(USB_IFACE_NUM, msg_size, buf);
|
||||
break;
|
||||
case 5: // WipeDevice
|
||||
ui_fadeout();
|
||||
ui_screen_wipe_confirm();
|
||||
ui_fadein();
|
||||
int response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL);
|
||||
response = ui_screen_wipe_confirm();
|
||||
if (INPUT_CANCEL == response) {
|
||||
ui_fadeout();
|
||||
ui_screen_firmware_info(vhdr, hdr);
|
||||
ui_fadein();
|
||||
send_user_abort(USB_IFACE_NUM, "Wipe cancelled");
|
||||
break;
|
||||
hal_delay(100);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return RETURN;
|
||||
}
|
||||
ui_fadeout();
|
||||
ui_screen_wipe();
|
||||
ui_fadein();
|
||||
r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf);
|
||||
if (r < 0) { // error
|
||||
ui_fadeout();
|
||||
ui_screen_fail();
|
||||
ui_fadein();
|
||||
screen_wipe_fail();
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return secfalse; // shutdown
|
||||
} else { // success
|
||||
ui_fadeout();
|
||||
ui_screen_done(0, sectrue);
|
||||
ui_fadein();
|
||||
return SHUTDOWN;
|
||||
} else { // success
|
||||
screen_wipe_success();
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return secfalse; // shutdown
|
||||
return SHUTDOWN;
|
||||
}
|
||||
break;
|
||||
case 6: // FirmwareErase
|
||||
@ -164,17 +162,18 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
case 7: // FirmwareUpload
|
||||
r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf);
|
||||
if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort
|
||||
ui_fadeout();
|
||||
ui_screen_fail();
|
||||
ui_fadein();
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return secfalse; // shutdown
|
||||
return SHUTDOWN;
|
||||
} else if (r == UPLOAD_ERR_USER_ABORT) {
|
||||
hal_delay(100);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return RETURN;
|
||||
} else if (r == 0) { // last chunk received
|
||||
ui_screen_install_progress_upload(1000);
|
||||
ui_fadeout();
|
||||
ui_screen_done(4, sectrue);
|
||||
ui_fadein();
|
||||
ui_screen_done(3, secfalse);
|
||||
hal_delay(1000);
|
||||
ui_screen_done(2, secfalse);
|
||||
@ -183,8 +182,8 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
hal_delay(1000);
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
ui_fadeout();
|
||||
return sectrue; // jump to firmware
|
||||
ui_screen_boot_empty(true, true);
|
||||
return CONTINUE;
|
||||
}
|
||||
break;
|
||||
case 55: // GetFeatures
|
||||
@ -260,56 +259,8 @@ int main(void) {
|
||||
|
||||
display_reinit();
|
||||
|
||||
#if defined TREZOR_MODEL_T
|
||||
set_core_clock(CLOCK_180_MHZ);
|
||||
display_set_little_endian();
|
||||
#endif
|
||||
#ifdef USE_TOUCH
|
||||
touch_power_on();
|
||||
touch_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
button_init();
|
||||
#endif
|
||||
#ifdef USE_RGB_LED
|
||||
rgb_led_init();
|
||||
#endif
|
||||
|
||||
mpu_config_bootloader();
|
||||
|
||||
#if PRODUCTION
|
||||
check_bootloader_version();
|
||||
#endif
|
||||
|
||||
display_clear();
|
||||
|
||||
// was there reboot with request to stay in bootloader?
|
||||
secbool stay_in_bootloader = secfalse;
|
||||
if (stay_in_bootloader_flag == STAY_IN_BOOTLOADER_FLAG) {
|
||||
stay_in_bootloader = sectrue;
|
||||
}
|
||||
|
||||
// delay to detect touch or skip if we know we are staying in bootloader
|
||||
// anyway
|
||||
uint32_t touched = 0;
|
||||
#ifdef USE_TOUCH
|
||||
if (stay_in_bootloader != sectrue) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
touched = touch_is_detected() | touch_read();
|
||||
if (touched) {
|
||||
break;
|
||||
}
|
||||
hal_delay(1);
|
||||
}
|
||||
}
|
||||
#elif defined USE_BUTTON
|
||||
button_read();
|
||||
if (button_state_left() == 1) {
|
||||
touched = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
const image_header *hdr = NULL;
|
||||
vendor_header vhdr;
|
||||
// detect whether the device contains a valid firmware
|
||||
@ -347,32 +298,73 @@ int main(void) {
|
||||
FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT);
|
||||
}
|
||||
|
||||
#if defined TREZOR_MODEL_T
|
||||
set_core_clock(CLOCK_180_MHZ);
|
||||
display_set_little_endian();
|
||||
#endif
|
||||
|
||||
ui_screen_boot_empty(firmware_present == sectrue, false);
|
||||
|
||||
#ifdef USE_TOUCH
|
||||
touch_power_on();
|
||||
touch_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
button_init();
|
||||
#endif
|
||||
#ifdef USE_RGB_LED
|
||||
rgb_led_init();
|
||||
#endif
|
||||
|
||||
#if PRODUCTION
|
||||
check_bootloader_version();
|
||||
#endif
|
||||
|
||||
// was there reboot with request to stay in bootloader?
|
||||
secbool stay_in_bootloader = secfalse;
|
||||
if (stay_in_bootloader_flag == STAY_IN_BOOTLOADER_FLAG) {
|
||||
stay_in_bootloader = sectrue;
|
||||
}
|
||||
|
||||
// delay to detect touch or skip if we know we are staying in bootloader
|
||||
// anyway
|
||||
uint32_t touched = 0;
|
||||
#ifdef USE_TOUCH
|
||||
if (stay_in_bootloader != sectrue) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
touched = touch_is_detected() | touch_read();
|
||||
if (touched) {
|
||||
break;
|
||||
}
|
||||
hal_delay(1);
|
||||
}
|
||||
}
|
||||
#elif defined USE_BUTTON
|
||||
button_read();
|
||||
if (button_state_left() == 1) {
|
||||
touched = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// start the bootloader if no or broken firmware found ...
|
||||
if (firmware_present != sectrue) {
|
||||
// ignore stay in bootloader
|
||||
stay_in_bootloader = secfalse;
|
||||
touched = false;
|
||||
|
||||
// show intro animation
|
||||
|
||||
// no ui_fadeout(); - we already start from black screen
|
||||
ui_screen_welcome_first();
|
||||
ui_fadein();
|
||||
ui_set_initial_setup(true);
|
||||
|
||||
hal_delay(1000);
|
||||
|
||||
ui_fadeout();
|
||||
ui_screen_welcome_second();
|
||||
ui_fadein();
|
||||
|
||||
hal_delay(1000);
|
||||
|
||||
ui_fadeout();
|
||||
ui_screen_welcome_third();
|
||||
ui_fadein();
|
||||
ui_screen_welcome();
|
||||
|
||||
// erase storage
|
||||
ensure(flash_erase_sectors(STORAGE_SECTORS, STORAGE_SECTORS_COUNT, NULL),
|
||||
NULL);
|
||||
|
||||
// and start the usb loop
|
||||
if (bootloader_usb_loop(NULL, NULL) != sectrue) {
|
||||
if (bootloader_usb_loop(NULL, NULL) != CONTINUE) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -380,13 +372,78 @@ int main(void) {
|
||||
// ... or if user touched the screen on start
|
||||
// ... or we have stay_in_bootloader flag to force it
|
||||
if (touched || stay_in_bootloader == sectrue) {
|
||||
// no ui_fadeout(); - we already start from black screen
|
||||
ui_screen_firmware_info(&vhdr, hdr);
|
||||
ui_fadein();
|
||||
ui_set_initial_setup(false);
|
||||
|
||||
// and start the usb loop
|
||||
if (bootloader_usb_loop(&vhdr, hdr) != sectrue) {
|
||||
return 1;
|
||||
screen_t screen = SCREEN_INTRO;
|
||||
|
||||
while (true) {
|
||||
bool continue_to_firmware = false;
|
||||
uint32_t ui_result = 0;
|
||||
|
||||
switch (screen) {
|
||||
case SCREEN_INTRO:
|
||||
ui_result = ui_screen_intro(&vhdr, hdr);
|
||||
if (ui_result == 1) {
|
||||
screen = SCREEN_MENU;
|
||||
}
|
||||
if (ui_result == 2) {
|
||||
screen = SCREEN_WAIT_FOR_HOST;
|
||||
}
|
||||
break;
|
||||
case SCREEN_MENU:
|
||||
ui_result = ui_screen_menu();
|
||||
if (ui_result == 1) { // exit menu
|
||||
screen = SCREEN_INTRO;
|
||||
}
|
||||
if (ui_result == 2) { // reboot
|
||||
ui_screen_boot_empty(true, true);
|
||||
continue_to_firmware = true;
|
||||
}
|
||||
if (ui_result == 3) { // wipe
|
||||
screen = SCREEN_WIPE_CONFIRM;
|
||||
}
|
||||
break;
|
||||
case SCREEN_WIPE_CONFIRM:
|
||||
ui_result = screen_wipe_confirm();
|
||||
if (ui_result == INPUT_CANCEL) {
|
||||
// canceled
|
||||
screen = SCREEN_MENU;
|
||||
}
|
||||
if (ui_result == INPUT_CONFIRM) {
|
||||
ui_screen_wipe();
|
||||
secbool r = bootloader_WipeDevice();
|
||||
if (r != sectrue) { // error
|
||||
screen_wipe_fail();
|
||||
return 1;
|
||||
} else { // success
|
||||
screen_wipe_success();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SCREEN_WAIT_FOR_HOST:
|
||||
screen_connect();
|
||||
switch (bootloader_usb_loop(&vhdr, hdr)) {
|
||||
case CONTINUE:
|
||||
continue_to_firmware = true;
|
||||
break;
|
||||
case RETURN:
|
||||
screen = SCREEN_INTRO;
|
||||
break;
|
||||
case SHUTDOWN:
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (continue_to_firmware) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,7 +473,7 @@ int main(void) {
|
||||
// if all VTRUST flags are unset = ultimate trust => skip the procedure
|
||||
|
||||
if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) {
|
||||
// ui_fadeout(); // no fadeout - we start from black screen
|
||||
ui_fadeout();
|
||||
ui_screen_boot(&vhdr, hdr);
|
||||
ui_fadein();
|
||||
|
||||
@ -466,3 +523,5 @@ int main(void) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(HF)"); }
|
||||
|
@ -23,7 +23,7 @@ ccmram_end = ORIGIN(CCMRAM) + LENGTH(CCMRAM);
|
||||
sram_start = ORIGIN(SRAM);
|
||||
sram_end = ORIGIN(SRAM) + LENGTH(SRAM);
|
||||
|
||||
_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.exidx) + SIZEOF(.align);
|
||||
_codelen = SIZEOF(.flash) + SIZEOF(.data);
|
||||
|
||||
SECTIONS {
|
||||
.header : ALIGN(4) {
|
||||
@ -36,15 +36,6 @@ SECTIONS {
|
||||
*(.text*);
|
||||
. = ALIGN(4);
|
||||
*(.rodata*);
|
||||
. = ALIGN(4);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
/* exception handling info generated by llvm which should consist of 8 bytes of "cantunwind" */
|
||||
.exidx : ALIGN(4) {
|
||||
*(.ARM.exidx*);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
.align : ALIGN(4) {
|
||||
. = ALIGN(512);
|
||||
} >FLASH AT>FLASH
|
||||
|
||||
@ -57,6 +48,10 @@ SECTIONS {
|
||||
. = ALIGN(512);
|
||||
} >CCMRAM AT>FLASH
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.ARM.exidx*);
|
||||
}
|
||||
|
||||
.bss : ALIGN(4) {
|
||||
*(.bss*);
|
||||
. = ALIGN(4);
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "bootui.h"
|
||||
#include "messages.h"
|
||||
#include "rust_ui.h"
|
||||
|
||||
#include "memzero.h"
|
||||
|
||||
@ -199,8 +200,8 @@ static void _usb_webusb_read_retry(uint8_t iface_num, uint8_t *buf) {
|
||||
// only timeout => let's try again
|
||||
} else {
|
||||
// error
|
||||
error_shutdown("Error reading", "from USB.", "Try different",
|
||||
"USB cable.");
|
||||
error_shutdown("USB ERROR",
|
||||
"Error reading from USB. Try different USB cable.");
|
||||
}
|
||||
}
|
||||
return; // success
|
||||
@ -559,33 +560,26 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
&is_upgrade, &is_downgrade_wipe);
|
||||
}
|
||||
|
||||
int response = INPUT_CANCEL;
|
||||
uint32_t response = INPUT_CANCEL;
|
||||
if (sectrue == is_new) {
|
||||
// new installation - auto confirm
|
||||
response = INPUT_CONFIRM;
|
||||
} else if (sectrue == is_upgrade) {
|
||||
// firmware upgrade
|
||||
ui_fadeout();
|
||||
ui_screen_install_confirm_upgrade(&vhdr, &hdr);
|
||||
ui_fadein();
|
||||
response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL);
|
||||
response = ui_screen_install_confirm_upgrade(&vhdr, &hdr);
|
||||
} else {
|
||||
// downgrade with wipe or new firmware vendor
|
||||
ui_fadeout();
|
||||
ui_screen_install_confirm_newvendor_or_downgrade_wipe(
|
||||
response = ui_screen_install_confirm_newvendor_or_downgrade_wipe(
|
||||
&vhdr, &hdr, is_downgrade_wipe);
|
||||
ui_fadein();
|
||||
response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL);
|
||||
}
|
||||
|
||||
if (INPUT_CANCEL == response) {
|
||||
ui_fadeout();
|
||||
ui_screen_firmware_info(¤t_vhdr, current_hdr);
|
||||
ui_fadein();
|
||||
send_user_abort(iface_num, "Firmware install cancelled");
|
||||
return UPLOAD_ERR_USER_ABORT;
|
||||
}
|
||||
|
||||
ui_screen_install_start();
|
||||
|
||||
headers_offset = IMAGE_HEADER_SIZE + vhdr.hdrlen;
|
||||
read_offset = IMAGE_INIT_CHUNK_SIZE;
|
||||
|
||||
@ -601,11 +595,6 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
} else {
|
||||
// first block with the headers parsed -> the first chunk is now complete
|
||||
read_offset = 0;
|
||||
|
||||
ui_fadeout();
|
||||
ui_screen_install_start();
|
||||
ui_fadein();
|
||||
|
||||
// if firmware is not upgrade, erase storage
|
||||
if (sectrue != is_upgrade) {
|
||||
ensure(
|
||||
@ -677,7 +666,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
return (int)firmware_remaining;
|
||||
}
|
||||
|
||||
int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) {
|
||||
secbool bootloader_WipeDevice(void) {
|
||||
static const uint8_t sectors[] = {
|
||||
FLASH_SECTOR_STORAGE_1,
|
||||
FLASH_SECTOR_STORAGE_2,
|
||||
@ -700,8 +689,12 @@ int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) {
|
||||
22,
|
||||
FLASH_SECTOR_FIRMWARE_EXTRA_END,
|
||||
};
|
||||
if (sectrue !=
|
||||
flash_erase_sectors(sectors, sizeof(sectors), ui_screen_wipe_progress)) {
|
||||
return flash_erase_sectors(sectors, sizeof(sectors), ui_screen_wipe_progress);
|
||||
}
|
||||
|
||||
int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) {
|
||||
secbool wipe_result = bootloader_WipeDevice();
|
||||
if (sectrue != wipe_result) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Could not erase flash");
|
||||
|
@ -66,4 +66,6 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
|
||||
void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
|
||||
|
||||
secbool bootloader_WipeDevice(void);
|
||||
|
||||
#endif
|
||||
|
1
core/embed/bootloader_ci/.changelog.d/1049.added
Normal file
1
core/embed/bootloader_ci/.changelog.d/1049.added
Normal file
@ -0,0 +1 @@
|
||||
Bootloader redesign
|
@ -199,8 +199,8 @@ static void _usb_webusb_read_retry(uint8_t iface_num, uint8_t *buf) {
|
||||
// only timeout => let's try again
|
||||
} else {
|
||||
// error
|
||||
error_shutdown("Error reading", "from USB.", "Try different",
|
||||
"USB cable.");
|
||||
error_shutdown("USB ERROR",
|
||||
"Error reading from USB. Try different USB cable.");
|
||||
}
|
||||
}
|
||||
return; // success
|
||||
|
@ -186,7 +186,7 @@ int main(void) {
|
||||
// MicroPython default exception handler
|
||||
|
||||
void __attribute__((noreturn)) nlr_jump_fail(void *val) {
|
||||
error_shutdown("Internal error", "(UE)", NULL, NULL);
|
||||
error_shutdown("INTERNAL ERROR!", "(UE)");
|
||||
}
|
||||
|
||||
// interrupt handlers
|
||||
@ -194,29 +194,19 @@ void __attribute__((noreturn)) nlr_jump_fail(void *val) {
|
||||
void NMI_Handler(void) {
|
||||
// Clock Security System triggered NMI
|
||||
if ((RCC->CIR & RCC_CIR_CSSF) != 0) {
|
||||
error_shutdown("Internal error", "(CS)", NULL, NULL);
|
||||
error_shutdown("INTERNAL ERROR!", "(CS)");
|
||||
}
|
||||
}
|
||||
|
||||
void HardFault_Handler(void) {
|
||||
error_shutdown("Internal error", "(HF)", NULL, NULL);
|
||||
}
|
||||
void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(HF)"); }
|
||||
|
||||
void MemManage_Handler_MM(void) {
|
||||
error_shutdown("Internal error", "(MM)", NULL, NULL);
|
||||
}
|
||||
void MemManage_Handler_MM(void) { error_shutdown("INTERNAL ERROR!", "(MM)"); }
|
||||
|
||||
void MemManage_Handler_SO(void) {
|
||||
error_shutdown("Internal error", "(SO)", NULL, NULL);
|
||||
}
|
||||
void MemManage_Handler_SO(void) { error_shutdown("INTERNAL ERROR!", "(SO)"); }
|
||||
|
||||
void BusFault_Handler(void) {
|
||||
error_shutdown("Internal error", "(BF)", NULL, NULL);
|
||||
}
|
||||
void BusFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(BF)"); }
|
||||
|
||||
void UsageFault_Handler(void) {
|
||||
error_shutdown("Internal error", "(UF)", NULL, NULL);
|
||||
}
|
||||
void UsageFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(UF)"); }
|
||||
|
||||
__attribute__((noreturn)) void reboot_to_bootloader() {
|
||||
jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE,
|
||||
|
@ -4,3 +4,25 @@ void loader_uncompress_r(int32_t y_offset, uint16_t fg_color, uint16_t bg_color,
|
||||
uint16_t icon_color, int32_t progress,
|
||||
int32_t indeterminate, const uint8_t* icon_data,
|
||||
uint32_t icon_data_size);
|
||||
|
||||
uint32_t screen_install_confirm(const char* vendor_str, uint8_t vendor_str_len,
|
||||
const char* version_str,
|
||||
const uint8_t* fingerprint, bool downgrade,
|
||||
bool vendor);
|
||||
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);
|
||||
uint32_t screen_menu(const char* bld_version_str);
|
||||
void screen_connect(void);
|
||||
void screen_fatal_error_c(const char* msg, const char* file);
|
||||
void screen_error_shutdown_c(const char* label, const char* msg);
|
||||
void screen_wipe_success(void);
|
||||
void screen_wipe_fail(void);
|
||||
uint32_t screen_install_success(const char* reboot_msg, bool initial_setup,
|
||||
bool complete_draw);
|
||||
uint32_t screen_install_fail(void);
|
||||
void screen_welcome(void);
|
||||
void screen_boot_empty(bool firmware_present, bool fading);
|
||||
|
@ -1,12 +1,11 @@
|
||||
use core::{
|
||||
convert::{Infallible, TryInto},
|
||||
num::TryFromIntError,
|
||||
};
|
||||
|
||||
use core::{convert::Infallible, num::TryFromIntError};
|
||||
use cstr_core::CStr;
|
||||
|
||||
#[cfg(feature = "micropython")]
|
||||
use crate::micropython::{ffi, obj::Obj, qstr::Qstr};
|
||||
use {
|
||||
crate::micropython::{ffi, obj::Obj, qstr::Qstr},
|
||||
core::convert::TryInto,
|
||||
};
|
||||
|
||||
#[allow(clippy::enum_variant_names)] // We mimic the Python exception classnames here.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@ -22,7 +21,6 @@ pub enum Error {
|
||||
KeyError(Obj),
|
||||
#[cfg(feature = "micropython")]
|
||||
AttributeError(Qstr),
|
||||
#[cfg(feature = "micropython")]
|
||||
ValueError(&'static CStr),
|
||||
#[cfg(feature = "micropython")]
|
||||
ValueErrorParam(&'static CStr, Obj),
|
||||
|
@ -26,6 +26,7 @@ mod trace;
|
||||
#[cfg(feature = "ui")]
|
||||
#[macro_use]
|
||||
pub mod ui;
|
||||
pub mod strutil;
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
#[panic_handler]
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::{convert::TryFrom, ops::Deref, ptr, slice, str};
|
||||
|
||||
use crate::{error::Error, micropython::obj::Obj};
|
||||
use crate::{error::Error, micropython::obj::Obj, strutil::hexlify};
|
||||
|
||||
use super::ffi;
|
||||
|
||||
@ -231,18 +231,6 @@ pub unsafe fn get_buffer_mut<'a>(obj: Obj) -> Result<&'a mut [u8], Error> {
|
||||
}
|
||||
}
|
||||
|
||||
fn hexlify(data: &[u8], buffer: &mut [u8]) {
|
||||
const HEX_LOWER: [u8; 16] = *b"0123456789abcdef";
|
||||
let mut i: usize = 0;
|
||||
for b in data.iter().take(buffer.len() / 2) {
|
||||
let hi: usize = ((b & 0xf0) >> 4).into();
|
||||
let lo: usize = (b & 0x0f).into();
|
||||
buffer[i] = HEX_LOWER[hi];
|
||||
buffer[i + 1] = HEX_LOWER[lo];
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hexlify_bytes(obj: Obj, offset: usize, max_len: usize) -> Result<StrBuffer, Error> {
|
||||
if !obj.is_bytes() {
|
||||
return Err(Error::TypeError);
|
||||
|
11
core/embed/rust/src/strutil.rs
Normal file
11
core/embed/rust/src/strutil.rs
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn hexlify(data: &[u8], buffer: &mut [u8]) {
|
||||
const HEX_LOWER: [u8; 16] = *b"0123456789abcdef";
|
||||
let mut i: usize = 0;
|
||||
for b in data.iter().take(buffer.len() / 2) {
|
||||
let hi: usize = ((b & 0xf0) >> 4).into();
|
||||
let lo: usize = (b & 0x0f).into();
|
||||
buffer[i] = HEX_LOWER[hi];
|
||||
buffer[i + 1] = HEX_LOWER[lo];
|
||||
i += 2;
|
||||
}
|
||||
}
|
@ -175,3 +175,9 @@ pub fn sync() {
|
||||
ffi::display_sync();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refresh() {
|
||||
unsafe {
|
||||
ffi::display_refresh();
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,13 @@ pub trait ParagraphStrType: AsRef<str> {
|
||||
fn skip_prefix(&self, bytes: usize) -> Self;
|
||||
}
|
||||
|
||||
#[cfg(feature = "bootloader")]
|
||||
impl ParagraphStrType for &str {
|
||||
fn skip_prefix(&self, chars: usize) -> Self {
|
||||
&self[chars..]
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParagraphSource {
|
||||
/// Determines the output type produced.
|
||||
type StrType: ParagraphStrType;
|
||||
@ -258,6 +265,8 @@ pub struct Paragraph<T> {
|
||||
/// Try to keep this and the next paragraph on the same page. NOTE: doesn't
|
||||
/// work if two or more subsequent paragraphs have this flag.
|
||||
no_break: bool,
|
||||
padding_top: i16,
|
||||
padding_bottom: i16,
|
||||
}
|
||||
|
||||
impl<T> Paragraph<T> {
|
||||
@ -268,6 +277,8 @@ impl<T> Paragraph<T> {
|
||||
align: Alignment::Start,
|
||||
break_after: false,
|
||||
no_break: false,
|
||||
padding_top: PARAGRAPH_TOP_SPACE,
|
||||
padding_bottom: PARAGRAPH_BOTTOM_SPACE,
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,6 +297,16 @@ impl<T> Paragraph<T> {
|
||||
self
|
||||
}
|
||||
|
||||
pub const fn with_top_padding(mut self, padding: i16) -> Self {
|
||||
self.padding_top = padding;
|
||||
self
|
||||
}
|
||||
|
||||
pub const fn with_bottom_padding(mut self, padding: i16) -> Self {
|
||||
self.padding_bottom = padding;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn content(&self) -> &T {
|
||||
&self.content
|
||||
}
|
||||
@ -302,13 +323,15 @@ impl<T> Paragraph<T> {
|
||||
align: self.align,
|
||||
break_after: self.break_after,
|
||||
no_break: self.no_break,
|
||||
padding_top: self.padding_top,
|
||||
padding_bottom: self.padding_bottom,
|
||||
}
|
||||
}
|
||||
|
||||
fn layout(&self, area: Rect) -> TextLayout {
|
||||
TextLayout {
|
||||
padding_top: PARAGRAPH_TOP_SPACE,
|
||||
padding_bottom: PARAGRAPH_BOTTOM_SPACE,
|
||||
padding_top: self.padding_top,
|
||||
padding_bottom: self.padding_bottom,
|
||||
..TextLayout::new(*self.style)
|
||||
.with_align(self.align)
|
||||
.with_bounds(area)
|
||||
@ -604,3 +627,42 @@ where
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType, const N: usize> ParagraphSource for Vec<Paragraph<T>, N> {
|
||||
type StrType = T;
|
||||
|
||||
fn at(&self, index: usize, offset: usize) -> Paragraph<Self::StrType> {
|
||||
let para = &self[index];
|
||||
para.map(|content| content.skip_prefix(offset))
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType, const N: usize> ParagraphSource for [Paragraph<T>; N] {
|
||||
type StrType = T;
|
||||
|
||||
fn at(&self, index: usize, offset: usize) -> Paragraph<Self::StrType> {
|
||||
let para = &self[index];
|
||||
para.map(|content| content.skip_prefix(offset))
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType> ParagraphSource for Paragraph<T> {
|
||||
type StrType = T;
|
||||
|
||||
fn at(&self, index: usize, offset: usize) -> Paragraph<Self::StrType> {
|
||||
assert_eq!(index, 0);
|
||||
self.map(|content| content.skip_prefix(offset))
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
@ -23,10 +23,12 @@ use crate::{
|
||||
error::Error,
|
||||
time::Duration,
|
||||
trezorhal::{buffers::get_text_buffer, display, qr, time, uzlib::UzlibContext},
|
||||
ui::{component::image::Image, lerp::Lerp},
|
||||
ui::lerp::Lerp,
|
||||
};
|
||||
use core::slice;
|
||||
|
||||
#[cfg(feature = "dma2d")]
|
||||
use crate::ui::component::image::Image;
|
||||
pub use crate::ui::display::toif::Icon;
|
||||
#[cfg(any(feature = "model_tt", feature = "model_tr"))]
|
||||
pub use loader::{loader, loader_indeterminate, LOADER_MAX, LOADER_MIN};
|
||||
@ -833,6 +835,19 @@ pub fn text_right(baseline: Point, text: &str, font: Font, fg_color: Color, bg_c
|
||||
);
|
||||
}
|
||||
|
||||
pub fn text_top_left(position: Point, text: &str, font: Font, fg_color: Color, bg_color: Color) {
|
||||
// let w = font.text_width(text);
|
||||
let h = font.text_height();
|
||||
display::text(
|
||||
position.x,
|
||||
position.y + h,
|
||||
text,
|
||||
font.into(),
|
||||
fg_color.into(),
|
||||
bg_color.into(),
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn pixeldata(color: Color) {
|
||||
display::pixeldata(color.into());
|
||||
@ -860,6 +875,10 @@ pub fn sync() {
|
||||
display::sync();
|
||||
}
|
||||
|
||||
pub fn refresh() {
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
pub fn get_color_table(fg_color: Color, bg_color: Color) -> [Color; 16] {
|
||||
let mut table: [Color; 16] = [Color::from_u16(0); 16];
|
||||
|
||||
|
@ -326,6 +326,15 @@ impl Rect {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn outset(&self, insets: Insets) -> Self {
|
||||
Self {
|
||||
x0: self.x0 - insets.left,
|
||||
y0: self.y0 - insets.top,
|
||||
x1: self.x1 + insets.right,
|
||||
y1: self.y1 + insets.bottom,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn cut_from_left(&self, width: i16) -> Self {
|
||||
Self {
|
||||
x0: self.x0,
|
||||
|
@ -197,45 +197,6 @@ impl ParagraphSource for PropsList {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType, const N: usize> ParagraphSource for Vec<Paragraph<T>, N> {
|
||||
type StrType = T;
|
||||
|
||||
fn at(&self, index: usize, offset: usize) -> Paragraph<Self::StrType> {
|
||||
let para = &self[index];
|
||||
para.map(|content| content.skip_prefix(offset))
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType, const N: usize> ParagraphSource for [Paragraph<T>; N] {
|
||||
type StrType = T;
|
||||
|
||||
fn at(&self, index: usize, offset: usize) -> Paragraph<Self::StrType> {
|
||||
let para = &self[index];
|
||||
para.map(|content| content.skip_prefix(offset))
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType> ParagraphSource for Paragraph<T> {
|
||||
type StrType = T;
|
||||
|
||||
fn at(&self, index: usize, offset: usize) -> Paragraph<Self::StrType> {
|
||||
assert_eq!(index, 0);
|
||||
self.map(|content| content.skip_prefix(offset))
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl ParagraphStrType for StrBuffer {
|
||||
fn skip_prefix(&self, chars: usize) -> Self {
|
||||
self.offset(chars)
|
||||
|
@ -8,7 +8,8 @@ pub mod display;
|
||||
pub mod event;
|
||||
pub mod geometry;
|
||||
pub mod lerp;
|
||||
mod util;
|
||||
pub mod screens;
|
||||
pub mod util;
|
||||
|
||||
#[cfg(feature = "micropython")]
|
||||
pub mod layout;
|
||||
|
195
core/embed/rust/src/ui/model_tt/bootloader/confirm.rs
Normal file
195
core/embed/rust/src/ui/model_tt/bootloader/confirm.rs
Normal file
@ -0,0 +1,195 @@
|
||||
use crate::ui::{
|
||||
component::{
|
||||
text::paragraphs::{ParagraphVecShort, Paragraphs},
|
||||
Child, Component, ComponentExt, Event, EventCtx, Label, Pad,
|
||||
},
|
||||
constant,
|
||||
constant::screen,
|
||||
display::{Color, Icon},
|
||||
geometry::{Alignment, Insets, Offset, Point, Rect, TOP_CENTER},
|
||||
model_tt::{
|
||||
bootloader::theme::{
|
||||
button_bld_menu, BUTTON_AREA_START, CLOSE, CONTENT_PADDING, CORNER_BUTTON_AREA,
|
||||
INFO_SMALL, TEXT_TITLE, TITLE_AREA,
|
||||
},
|
||||
component::{Button, ButtonMsg::Clicked},
|
||||
constant::WIDTH,
|
||||
theme::WHITE,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, ToPrimitive)]
|
||||
pub enum ConfirmMsg {
|
||||
Cancel = 1,
|
||||
Confirm = 2,
|
||||
}
|
||||
|
||||
pub struct Confirm<'a> {
|
||||
bg: Pad,
|
||||
content_pad: Pad,
|
||||
bg_color: Color,
|
||||
icon: Option<Icon>,
|
||||
title: Option<Child<Label<&'static str>>>,
|
||||
message: Child<Paragraphs<ParagraphVecShort<&'a str>>>,
|
||||
left: Child<Button<&'static str>>,
|
||||
right: Child<Button<&'static str>>,
|
||||
info_button: Option<Button<&'static str>>,
|
||||
close_button: Option<Button<&'static str>>,
|
||||
info_title: Option<Child<Label<&'static str>>>,
|
||||
info_text: Option<Paragraphs<ParagraphVecShort<&'a str>>>,
|
||||
show_info: bool,
|
||||
|
||||
confirm_left: bool,
|
||||
}
|
||||
|
||||
impl<'a> Confirm<'a> {
|
||||
pub fn new(
|
||||
bg_color: Color,
|
||||
icon: Option<Icon>,
|
||||
left: Button<&'static str>,
|
||||
right: Button<&'static str>,
|
||||
confirm_left: bool,
|
||||
confirm: (Option<&'static str>, Paragraphs<ParagraphVecShort<&'a str>>),
|
||||
info: Option<(&'static str, Paragraphs<ParagraphVecShort<&'a str>>)>,
|
||||
) -> Self {
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(bg_color),
|
||||
content_pad: Pad::with_background(bg_color),
|
||||
bg_color,
|
||||
icon,
|
||||
message: Child::new(confirm.1),
|
||||
left: Child::new(left),
|
||||
right: Child::new(right),
|
||||
close_button: None,
|
||||
info_button: None,
|
||||
info_title: None,
|
||||
info_text: None,
|
||||
confirm_left,
|
||||
show_info: false,
|
||||
title: confirm
|
||||
.0
|
||||
.map(|title| Child::new(Label::new(title, Alignment::Start, TEXT_TITLE))),
|
||||
};
|
||||
if let Some((title, text)) = info {
|
||||
instance.info_title = Some(Child::new(Label::new(title, Alignment::Start, TEXT_TITLE)));
|
||||
instance.info_text = Some(text);
|
||||
instance.info_button = Some(
|
||||
Button::with_icon(Icon::new(INFO_SMALL))
|
||||
.styled(button_bld_menu())
|
||||
.with_expanded_touch_area(Insets::uniform(13)),
|
||||
);
|
||||
instance.close_button = Some(
|
||||
Button::with_icon(Icon::new(CLOSE))
|
||||
.styled(button_bld_menu())
|
||||
.with_expanded_touch_area(Insets::uniform(13)),
|
||||
);
|
||||
}
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Component for Confirm<'a> {
|
||||
type Msg = ConfirmMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg.place(constant::screen());
|
||||
self.content_pad.place(Rect::new(
|
||||
Point::zero(),
|
||||
Point::new(WIDTH, BUTTON_AREA_START),
|
||||
));
|
||||
let icon_height = if let Some(icon) = self.icon {
|
||||
icon.toif.height()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
self.message.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, 32 + icon_height),
|
||||
Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START),
|
||||
));
|
||||
|
||||
let button_size = Offset::new(106, 38);
|
||||
self.left.place(Rect::from_top_left_and_size(
|
||||
Point::new(CONTENT_PADDING, BUTTON_AREA_START),
|
||||
button_size,
|
||||
));
|
||||
self.right.place(Rect::from_top_left_and_size(
|
||||
Point::new(124, BUTTON_AREA_START),
|
||||
button_size,
|
||||
));
|
||||
self.info_button.place(CORNER_BUTTON_AREA);
|
||||
self.close_button.place(CORNER_BUTTON_AREA);
|
||||
self.info_title.place(TITLE_AREA);
|
||||
self.title.place(TITLE_AREA);
|
||||
self.info_text.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, TITLE_AREA.y1),
|
||||
Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START),
|
||||
));
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
if self.show_info {
|
||||
if let Some(Clicked) = self.close_button.event(ctx, event) {
|
||||
self.show_info = false;
|
||||
self.content_pad.clear();
|
||||
self.title.request_complete_repaint(ctx);
|
||||
self.message.request_complete_repaint(ctx);
|
||||
return None;
|
||||
}
|
||||
} else if let Some(Clicked) = self.info_button.event(ctx, event) {
|
||||
self.show_info = true;
|
||||
self.info_text.request_complete_repaint(ctx);
|
||||
self.info_title.request_complete_repaint(ctx);
|
||||
self.content_pad.clear();
|
||||
return None;
|
||||
}
|
||||
if let Some(Clicked) = self.left.event(ctx, event) {
|
||||
return if self.confirm_left {
|
||||
Some(Self::Msg::Confirm)
|
||||
} else {
|
||||
Some(Self::Msg::Cancel)
|
||||
};
|
||||
};
|
||||
if let Some(Clicked) = self.right.event(ctx, event) {
|
||||
return if self.confirm_left {
|
||||
Some(Self::Msg::Cancel)
|
||||
} else {
|
||||
Some(Self::Msg::Confirm)
|
||||
};
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.content_pad.paint();
|
||||
|
||||
if self.show_info {
|
||||
self.close_button.paint();
|
||||
self.info_title.paint();
|
||||
self.info_text.paint();
|
||||
self.left.paint();
|
||||
self.right.paint();
|
||||
} else {
|
||||
self.info_button.paint();
|
||||
self.title.paint();
|
||||
self.message.paint();
|
||||
self.left.paint();
|
||||
self.right.paint();
|
||||
if let Some(icon) = self.icon {
|
||||
icon.draw(
|
||||
Point::new(screen().center().x, 32),
|
||||
TOP_CENTER,
|
||||
WHITE,
|
||||
self.bg_color,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
self.left.bounds(sink);
|
||||
self.right.bounds(sink);
|
||||
}
|
||||
}
|
50
core/embed/rust/src/ui/model_tt/bootloader/connect.rs
Normal file
50
core/embed/rust/src/ui/model_tt/bootloader/connect.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
constant::screen,
|
||||
display::{self, Font},
|
||||
geometry::{Offset, Rect},
|
||||
model_tt::bootloader::theme::{BLD_BG, BLD_TITLE_COLOR},
|
||||
};
|
||||
|
||||
pub struct Connect {
|
||||
bg: Pad,
|
||||
message: &'static str,
|
||||
}
|
||||
|
||||
impl Connect {
|
||||
pub fn new(message: &'static str) -> Self {
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
message,
|
||||
};
|
||||
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Connect {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg.place(screen());
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let font = Font::NORMAL;
|
||||
|
||||
self.bg.paint();
|
||||
display::text_center(
|
||||
screen().center() + Offset::y(font.text_height() / 2),
|
||||
self.message,
|
||||
Font::NORMAL,
|
||||
BLD_TITLE_COLOR,
|
||||
BLD_BG,
|
||||
);
|
||||
}
|
||||
}
|
100
core/embed/rust/src/ui/model_tt/bootloader/intro.rs
Normal file
100
core/embed/rust/src/ui/model_tt/bootloader/intro.rs
Normal file
@ -0,0 +1,100 @@
|
||||
use crate::ui::{
|
||||
component::{
|
||||
text::paragraphs::{ParagraphVecShort, Paragraphs},
|
||||
Child, Component, Event, EventCtx, Label, Pad,
|
||||
},
|
||||
constant::screen,
|
||||
display::Icon,
|
||||
geometry::{Alignment, Insets, Point, Rect},
|
||||
model_tt::{
|
||||
bootloader::theme::{button_bld_menu, button_bld_menu_item, BLD_BG, MENU},
|
||||
component::ButtonMsg::Clicked,
|
||||
},
|
||||
};
|
||||
use heapless::String;
|
||||
|
||||
use crate::ui::model_tt::{
|
||||
bootloader::theme::{CONTENT_PADDING, CORNER_BUTTON_AREA, TEXT_TITLE, TITLE_AREA},
|
||||
component::Button,
|
||||
constant::WIDTH,
|
||||
};
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, ToPrimitive)]
|
||||
pub enum IntroMsg {
|
||||
Menu = 1,
|
||||
Host = 2,
|
||||
}
|
||||
|
||||
pub struct Intro<'a> {
|
||||
bg: Pad,
|
||||
title: Child<Label<String<32>>>,
|
||||
menu: Child<Button<&'static str>>,
|
||||
host: Child<Button<&'static str>>,
|
||||
text: Child<Paragraphs<ParagraphVecShort<&'a str>>>,
|
||||
}
|
||||
|
||||
impl<'a> Intro<'a> {
|
||||
pub fn new(bld_version: &'static str, content: Paragraphs<ParagraphVecShort<&'a str>>) -> Self {
|
||||
let mut title: String<32> = String::new();
|
||||
unwrap!(title.push_str("BOOTLOADER "));
|
||||
unwrap!(title.push_str(bld_version));
|
||||
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
title: Child::new(Label::new(title, Alignment::Start, TEXT_TITLE)),
|
||||
menu: Child::new(
|
||||
Button::with_icon(Icon::new(MENU))
|
||||
.styled(button_bld_menu())
|
||||
.with_expanded_touch_area(Insets::uniform(13)),
|
||||
),
|
||||
host: Child::new(Button::with_text("INSTALL FIRMWARE").styled(button_bld_menu_item())),
|
||||
text: Child::new(content),
|
||||
};
|
||||
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Component for Intro<'a> {
|
||||
type Msg = IntroMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
const BUTTON_AREA_START: i16 = 188;
|
||||
self.bg.place(screen());
|
||||
self.title.place(TITLE_AREA);
|
||||
self.menu.place(CORNER_BUTTON_AREA);
|
||||
self.host.place(Rect::new(
|
||||
Point::new(10, BUTTON_AREA_START),
|
||||
Point::new(10 + 220, BUTTON_AREA_START + 38),
|
||||
));
|
||||
self.text.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, 75),
|
||||
Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START),
|
||||
));
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
if let Some(Clicked) = self.menu.event(ctx, event) {
|
||||
return Some(Self::Msg::Menu);
|
||||
};
|
||||
if let Some(Clicked) = self.host.event(ctx, event) {
|
||||
return Some(Self::Msg::Host);
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.title.paint();
|
||||
self.text.paint();
|
||||
self.host.paint();
|
||||
self.menu.paint();
|
||||
}
|
||||
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
self.menu.bounds(sink);
|
||||
}
|
||||
}
|
106
core/embed/rust/src/ui/model_tt/bootloader/menu.rs
Normal file
106
core/embed/rust/src/ui/model_tt/bootloader/menu.rs
Normal file
@ -0,0 +1,106 @@
|
||||
use crate::ui::{
|
||||
component::{Child, Component, Event, EventCtx, Label, Pad},
|
||||
constant::{screen, WIDTH},
|
||||
display::Icon,
|
||||
geometry::{Alignment, Insets, Point, Rect},
|
||||
model_tt::{
|
||||
bootloader::theme::{
|
||||
button_bld_menu, button_bld_menu_item, BLD_BG, CLOSE, CONTENT_PADDING,
|
||||
CORNER_BUTTON_AREA, ERASE, REBOOT, TEXT_TITLE, TITLE_AREA,
|
||||
},
|
||||
component::{Button, ButtonMsg::Clicked, IconText},
|
||||
},
|
||||
};
|
||||
use heapless::String;
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, ToPrimitive)]
|
||||
pub enum MenuMsg {
|
||||
Close = 1,
|
||||
Reboot = 2,
|
||||
FactoryReset = 3,
|
||||
}
|
||||
|
||||
pub struct Menu {
|
||||
bg: Pad,
|
||||
title: Child<Label<String<32>>>,
|
||||
close: Child<Button<&'static str>>,
|
||||
reboot: Child<Button<&'static str>>,
|
||||
reset: Child<Button<&'static str>>,
|
||||
}
|
||||
|
||||
impl Menu {
|
||||
pub fn new(bld_version: &'static str) -> Self {
|
||||
let content_reboot = IconText::new("REBOOT TREZOR", Icon::new(REBOOT));
|
||||
let content_reset = IconText::new("FACTORY RESET", Icon::new(ERASE));
|
||||
|
||||
let mut title: String<32> = String::new();
|
||||
unwrap!(title.push_str("BOOTLOADER "));
|
||||
unwrap!(title.push_str(bld_version));
|
||||
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
title: Child::new(Label::new(title, Alignment::Start, TEXT_TITLE)),
|
||||
close: Child::new(
|
||||
Button::with_icon(Icon::new(CLOSE))
|
||||
.styled(button_bld_menu())
|
||||
.with_expanded_touch_area(Insets::uniform(13)),
|
||||
),
|
||||
reboot: Child::new(
|
||||
Button::with_icon_and_text(content_reboot).styled(button_bld_menu_item()),
|
||||
),
|
||||
reset: Child::new(
|
||||
Button::with_icon_and_text(content_reset).styled(button_bld_menu_item()),
|
||||
),
|
||||
};
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Menu {
|
||||
type Msg = MenuMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg.place(screen());
|
||||
self.title.place(TITLE_AREA);
|
||||
self.close.place(CORNER_BUTTON_AREA);
|
||||
self.reboot.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, 64),
|
||||
Point::new(WIDTH - CONTENT_PADDING, 64 + 38),
|
||||
));
|
||||
self.reset.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, 110),
|
||||
Point::new(WIDTH - CONTENT_PADDING, 110 + 38),
|
||||
));
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
if let Some(Clicked) = self.close.event(ctx, event) {
|
||||
return Some(Self::Msg::Close);
|
||||
}
|
||||
if let Some(Clicked) = self.reboot.event(ctx, event) {
|
||||
return Some(Self::Msg::Reboot);
|
||||
}
|
||||
if let Some(Clicked) = self.reset.event(ctx, event) {
|
||||
return Some(Self::Msg::FactoryReset);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.title.paint();
|
||||
self.close.paint();
|
||||
self.reboot.paint();
|
||||
self.reset.paint();
|
||||
}
|
||||
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
self.close.bounds(sink);
|
||||
self.reboot.bounds(sink);
|
||||
self.reset.bounds(sink);
|
||||
}
|
||||
}
|
513
core/embed/rust/src/ui/model_tt/bootloader/mod.rs
Normal file
513
core/embed/rust/src/ui/model_tt/bootloader/mod.rs
Normal file
@ -0,0 +1,513 @@
|
||||
use crate::{
|
||||
trezorhal::io::io_touch_read,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display::{self, Font},
|
||||
event::TouchEvent,
|
||||
geometry::Point,
|
||||
model_tt::constant,
|
||||
},
|
||||
};
|
||||
use heapless::String;
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
pub mod confirm;
|
||||
mod connect;
|
||||
pub mod intro;
|
||||
pub mod menu;
|
||||
pub mod theme;
|
||||
|
||||
use crate::{
|
||||
strutil::hexlify,
|
||||
ui::{
|
||||
component::text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt},
|
||||
constant::screen,
|
||||
display::{Color, Icon},
|
||||
geometry::{LinearPlacement, CENTER},
|
||||
model_tt::{
|
||||
bootloader::{
|
||||
connect::Connect,
|
||||
theme::{
|
||||
button_install_cancel, button_install_confirm, button_wipe_cancel,
|
||||
button_wipe_confirm, BLD_BG, BLD_FG, BLD_WIPE_COLOR, ERASE_BIG, LOGO_EMPTY,
|
||||
RECEIVE, TEXT_WIPE_BOLD, WELCOME_COLOR,
|
||||
},
|
||||
},
|
||||
component::{Button, ResultScreen},
|
||||
theme::{
|
||||
BACKLIGHT_DIM, BACKLIGHT_NORMAL, BG, BLACK, FG, GREY_DARK, ICON_SUCCESS_SMALL,
|
||||
ICON_WARN_SMALL, TEXT_ERROR_BOLD, TEXT_ERROR_NORMAL, WHITE,
|
||||
},
|
||||
},
|
||||
util::{from_c_array, from_c_str},
|
||||
},
|
||||
};
|
||||
use confirm::Confirm;
|
||||
use intro::Intro;
|
||||
use menu::Menu;
|
||||
|
||||
pub trait ReturnToC {
|
||||
fn return_to_c(self) -> u32;
|
||||
}
|
||||
|
||||
impl ReturnToC for Never {
|
||||
fn return_to_c(self) -> u32 {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ReturnToC for T
|
||||
where
|
||||
T: ToPrimitive,
|
||||
{
|
||||
fn return_to_c(self) -> u32 {
|
||||
self.to_u32().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn fadein() {
|
||||
display::fade_backlight_duration(BACKLIGHT_NORMAL, 500);
|
||||
}
|
||||
|
||||
fn fadeout() {
|
||||
display::fade_backlight_duration(BACKLIGHT_DIM, 500);
|
||||
}
|
||||
|
||||
fn run<F>(frame: &mut F) -> u32
|
||||
where
|
||||
F: Component,
|
||||
F::Msg: ReturnToC,
|
||||
{
|
||||
frame.place(constant::screen());
|
||||
fadeout();
|
||||
display::sync();
|
||||
frame.paint();
|
||||
fadein();
|
||||
|
||||
loop {
|
||||
let event = touch_eval();
|
||||
if let Some(e) = event {
|
||||
let mut ctx = EventCtx::new();
|
||||
let msg = frame.event(&mut ctx, Event::Touch(e));
|
||||
|
||||
if let Some(message) = msg {
|
||||
return message.return_to_c();
|
||||
}
|
||||
display::sync();
|
||||
frame.paint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show<F>(frame: &mut F, fading: bool)
|
||||
where
|
||||
F: Component,
|
||||
{
|
||||
frame.place(screen());
|
||||
if fading {
|
||||
fadeout()
|
||||
};
|
||||
display::sync();
|
||||
frame.paint();
|
||||
if fading {
|
||||
fadein()
|
||||
};
|
||||
}
|
||||
|
||||
fn touch_eval() -> Option<TouchEvent> {
|
||||
let event = io_touch_read();
|
||||
if event == 0 {
|
||||
return None;
|
||||
}
|
||||
let event_type = event >> 24;
|
||||
let ex = ((event >> 12) & 0xFFF) as i16;
|
||||
let ey = (event & 0xFFF) as i16;
|
||||
|
||||
TouchEvent::new(event_type, ex as _, ey as _).ok()
|
||||
}
|
||||
|
||||
#[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 mut fingerprint_buffer: [u8; 64] = [0; 64];
|
||||
let fingerprint_str = unsafe {
|
||||
let fingerprint_slice = core::slice::from_raw_parts(fingerprint as *const u8, 32);
|
||||
hexlify(fingerprint_slice, &mut fingerprint_buffer);
|
||||
core::str::from_utf8_unchecked(fingerprint_buffer.as_ref())
|
||||
};
|
||||
|
||||
let mut version_str: String<64> = String::new();
|
||||
unwrap!(version_str.push_str("Firmware version "));
|
||||
unwrap!(version_str.push_str(version));
|
||||
|
||||
let mut vendor_str: String<64> = String::new();
|
||||
unwrap!(vendor_str.push_str("by "));
|
||||
unwrap!(vendor_str.push_str(text));
|
||||
|
||||
let title = if downgrade {
|
||||
"DOWNGRADE FW"
|
||||
} else if vendor {
|
||||
"CHANGE FW VENDOR"
|
||||
} else {
|
||||
"UPDATE FIRMWARE"
|
||||
};
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&theme::TEXT_NORMAL, version_str.as_ref()));
|
||||
messages.add(Paragraph::new(&theme::TEXT_NORMAL, vendor_str.as_ref()));
|
||||
|
||||
if vendor || downgrade {
|
||||
messages
|
||||
.add(Paragraph::new(&theme::TEXT_BOLD, "Seed will be erased!").with_top_padding(16));
|
||||
}
|
||||
|
||||
let message =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_FINGERPRINT, fingerprint_str));
|
||||
|
||||
let fingerprint =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let left = Button::with_text("CANCEL").styled(button_install_cancel());
|
||||
let right = Button::with_text("INSTALL").styled(button_install_confirm());
|
||||
|
||||
let mut frame = Confirm::new(
|
||||
BLD_BG,
|
||||
None,
|
||||
left,
|
||||
right,
|
||||
false,
|
||||
(Some(title), message),
|
||||
Some(("FW FINGERPRINT", fingerprint)),
|
||||
);
|
||||
|
||||
run(&mut frame)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_confirm() -> u32 {
|
||||
let icon = Some(Icon::new(ERASE_BIG));
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(
|
||||
Paragraph::new(
|
||||
&TEXT_ERROR_NORMAL,
|
||||
"Are you sure you want to factory reset the device?",
|
||||
)
|
||||
.centered(),
|
||||
);
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "Seed and firmware\nwill be erased!").centered());
|
||||
|
||||
let message =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let left = Button::with_text("RESET").styled(button_wipe_confirm());
|
||||
let right = Button::with_text("CANCEL").styled(button_wipe_cancel());
|
||||
|
||||
let mut frame = Confirm::new(
|
||||
BLD_WIPE_COLOR,
|
||||
icon,
|
||||
left,
|
||||
right,
|
||||
true,
|
||||
(None, message),
|
||||
None,
|
||||
);
|
||||
|
||||
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) });
|
||||
|
||||
let mut fw: String<64> = String::new();
|
||||
unwrap!(fw.push_str("Firmware "));
|
||||
unwrap!(fw.push_str(version));
|
||||
|
||||
let mut vendor_: String<64> = String::new();
|
||||
unwrap!(vendor_.push_str("by "));
|
||||
unwrap!(vendor_.push_str(vendor));
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&theme::TEXT_NORMAL, fw.as_ref()));
|
||||
messages.add(Paragraph::new(&theme::TEXT_NORMAL, vendor_.as_ref()));
|
||||
|
||||
let p = Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_start());
|
||||
|
||||
let mut frame = Intro::new(bld_version, p);
|
||||
|
||||
run(&mut frame)
|
||||
}
|
||||
|
||||
fn screen_progress(
|
||||
text: &str,
|
||||
progress: u16,
|
||||
initialize: bool,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
if initialize {
|
||||
fadeout();
|
||||
display::rect_fill(constant::screen(), bg_color);
|
||||
}
|
||||
|
||||
display::text_center(
|
||||
Point::new(constant::WIDTH / 2, 214),
|
||||
text,
|
||||
Font::NORMAL,
|
||||
fg_color,
|
||||
bg_color,
|
||||
);
|
||||
display::loader(progress, -20, fg_color, bg_color, icon);
|
||||
if initialize {
|
||||
fadein();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_progress(progress: u16, initialize: bool, initial_setup: bool) {
|
||||
let bg_color = if initial_setup { WELCOME_COLOR } else { BG };
|
||||
let fg_color = if initial_setup { FG } else { BLD_FG };
|
||||
|
||||
screen_progress(
|
||||
"Installing firmware...",
|
||||
progress,
|
||||
initialize,
|
||||
fg_color,
|
||||
bg_color,
|
||||
Some((Icon::new(RECEIVE), fg_color)),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) {
|
||||
screen_progress(
|
||||
"Resetting Trezor...",
|
||||
progress,
|
||||
initialize,
|
||||
theme::BLD_FG,
|
||||
BLD_WIPE_COLOR,
|
||||
Some((Icon::new(ERASE_BIG), theme::BLD_FG)),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_connect() {
|
||||
let mut frame = Connect::new("Waiting for host...");
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_success() {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "Trezor reset").centered());
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "successfully.").centered());
|
||||
|
||||
let m_top =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "PLEASE RECONNECT").centered());
|
||||
messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "THE DEVICE").centered());
|
||||
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
BLD_WIPE_COLOR,
|
||||
Icon::new(ICON_SUCCESS_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
true,
|
||||
);
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_fail() {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "Trezor reset was").centered());
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "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(&TEXT_WIPE_BOLD, "PLEASE RECONNECT").centered());
|
||||
messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "THE DEVICE").centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
BLD_WIPE_COLOR,
|
||||
Icon::new(ICON_WARN_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
true,
|
||||
);
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_boot_empty(firmware_present: bool, fading: bool) {
|
||||
if fading {
|
||||
fadeout();
|
||||
}
|
||||
|
||||
let fg = if firmware_present { GREY_DARK } else { WHITE };
|
||||
let bg = if firmware_present {
|
||||
BLACK
|
||||
} else {
|
||||
WELCOME_COLOR
|
||||
};
|
||||
display::rect_fill(constant::screen(), bg);
|
||||
let icon = Icon::new(LOGO_EMPTY);
|
||||
icon.draw(screen().center(), CENTER, fg, bg);
|
||||
|
||||
if fading {
|
||||
fadein();
|
||||
} else {
|
||||
display::set_backlight(BACKLIGHT_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_fail() {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_BOLD, "Firmware installation was").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_BOLD, "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_SUBMSG, "PLEASE RECONNECT").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_SUBMSG, "THE DEVICE").centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
BLD_BG,
|
||||
Icon::new(ICON_WARN_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
true,
|
||||
);
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
fn screen_install_success_bld(msg: &'static str, complete_draw: bool) {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_BOLD, "Firmware installed").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_BOLD, "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_SUBMSG, msg).centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
BLD_BG,
|
||||
Icon::new(ICON_SUCCESS_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
complete_draw,
|
||||
);
|
||||
show(&mut frame, complete_draw);
|
||||
}
|
||||
|
||||
fn screen_install_success_initial(msg: &'static str, complete_draw: bool) {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_WELCOME_BOLD, "Firmware installed").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_WELCOME_BOLD, "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_SUBMSG_INITIAL, msg).centered());
|
||||
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
FG,
|
||||
WELCOME_COLOR,
|
||||
Icon::new(ICON_SUCCESS_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
complete_draw,
|
||||
);
|
||||
show(&mut frame, complete_draw);
|
||||
}
|
||||
|
||||
#[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() {
|
||||
fadeout();
|
||||
display::rect_fill(screen(), WELCOME_COLOR);
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_WELCOME, "Get started with").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_WELCOME, "your trezor at").centered());
|
||||
messages.add(
|
||||
Paragraph::new(&theme::TEXT_WELCOME_BOLD, "trezor.io/start")
|
||||
.centered()
|
||||
.with_top_padding(2),
|
||||
);
|
||||
let mut frame =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
show(&mut frame, false);
|
||||
fadein();
|
||||
}
|
304
core/embed/rust/src/ui/model_tt/bootloader/theme.rs
Normal file
304
core/embed/rust/src/ui/model_tt/bootloader/theme.rs
Normal file
@ -0,0 +1,304 @@
|
||||
use crate::{
|
||||
alpha,
|
||||
ui::{
|
||||
component::{text::TextStyle, LineBreaking::BreakWordsNoHyphen},
|
||||
constant::WIDTH,
|
||||
display::{Color, Font},
|
||||
geometry::{Offset, Point, Rect},
|
||||
model_tt::{
|
||||
component::{ButtonStyle, ButtonStyleSheet},
|
||||
theme::{BLACK, FG, GREY_DARK, GREY_LIGHT, GREY_MEDIUM, WHITE},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub const BLD_BG: Color = Color::rgb(0x00, 0x17, 0xA3);
|
||||
pub const BLD_FG: Color = WHITE;
|
||||
pub const BLD_WIPE_COLOR: Color = Color::rgb(0xAD, 0x2B, 0x2B);
|
||||
pub const BLD_WIPE_TEXT_COLOR: Color = Color::rgb(0xD6, 0x95, 0x95);
|
||||
|
||||
pub const BLD_WIPE_BTN_COLOR: Color = Color::alpha(BLD_WIPE_COLOR, alpha!(0.3));
|
||||
pub const BLD_WIPE_BTN_COLOR_ACTIVE: Color = Color::rgb(0xB9, 0x4B, 0x4B);
|
||||
pub const BLD_WIPE_CANCEL_BTN_COLOR_ACTIVE: Color = Color::rgb(0xF3, 0xDF, 0xDF);
|
||||
|
||||
pub const BLD_INSTALL_BTN_COLOR: Color = Color::alpha(BLD_BG, alpha!(0.3));
|
||||
pub const BLD_INSTALL_BTN_COLOR_ACTIVE: Color = Color::rgb(0xD9, 0xDC, 0xF1);
|
||||
pub const BLD_INSTALL_CANCEL_BTN_COLOR_ACTIVE: Color = Color::rgb(0x26, 0x3A, 0xB1);
|
||||
|
||||
pub const BLD_COLOR_SUBMSG: Color = Color::rgb(0x80, 0x8B, 0xD1);
|
||||
|
||||
pub const BLD_BTN_MENU_COLOR: Color = Color::alpha(BLD_BG, alpha!(0.22));
|
||||
pub const BLD_BTN_MENU_COLOR_ACTIVE: Color = Color::alpha(BLD_BG, alpha!(0.11));
|
||||
pub const BLD_BTN_MENUITEM_COLOR: Color = Color::alpha(BLD_BG, alpha!(0.33));
|
||||
pub const BLD_BTN_MENUITEM_COLOR_ACTIVE: Color =
|
||||
Color::rgba(BLD_BG, 0xFF, 0xFF, 0xFF, alpha!(0.11));
|
||||
pub const BLD_TITLE_COLOR: Color = Color::rgba(BLD_BG, 0xFF, 0xFF, 0xFF, alpha!(0.75));
|
||||
|
||||
pub const WELCOME_COLOR: Color = BLACK;
|
||||
|
||||
// Commonly used corner radius (i.e. for buttons).
|
||||
pub const RADIUS: u8 = 2;
|
||||
|
||||
// Commonly used constants for UI elements.
|
||||
pub const CONTENT_PADDING: i16 = 10;
|
||||
pub const TITLE_AREA: Rect = Rect::new(Point::new(15, 14), Point::new(200, 30));
|
||||
pub const CORNER_BUTTON_SIZE: i16 = 32;
|
||||
pub const CORNER_BUTTON_PADDING: i16 = 8;
|
||||
pub const CORNER_BUTTON_AREA: Rect = Rect::from_top_left_and_size(
|
||||
Point::new(
|
||||
WIDTH - CORNER_BUTTON_SIZE - CORNER_BUTTON_PADDING,
|
||||
CORNER_BUTTON_PADDING,
|
||||
),
|
||||
Offset::uniform(CORNER_BUTTON_SIZE),
|
||||
);
|
||||
pub const TITLE_AREA_HEIGHT: i16 = 16;
|
||||
pub const TITLE_AREA_START_Y: i16 = 8;
|
||||
pub const BUTTON_AREA_START: i16 = 188;
|
||||
|
||||
// UI icons.
|
||||
pub const ICON_CANCEL: &[u8] = include_res!("model_tt/res/cancel.toif");
|
||||
pub const ICON_CONFIRM: &[u8] = include_res!("model_tt/res/confirm.toif");
|
||||
|
||||
// BLD icons
|
||||
pub const CLOSE: &[u8] = include_res!("model_tt/res/close.toif");
|
||||
pub const ERASE: &[u8] = include_res!("model_tt/res/erase.toif");
|
||||
pub const ERASE_BIG: &[u8] = include_res!("model_tt/res/erase_big.toif");
|
||||
pub const REBOOT: &[u8] = include_res!("model_tt/res/reboot.toif");
|
||||
pub const MENU: &[u8] = include_res!("model_tt/res/menu.toif");
|
||||
pub const RECEIVE: &[u8] = include_res!("model_tt/res/receive.toif");
|
||||
pub const LOGO_EMPTY: &[u8] = include_res!("model_tt/res/trezor_empty.toif");
|
||||
pub const INFO_SMALL: &[u8] = include_res!("model_tt/res/info_small.toif");
|
||||
|
||||
pub fn button_install_cancel() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: WHITE,
|
||||
button_color: BLD_BTN_MENUITEM_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: WHITE,
|
||||
button_color: BLD_INSTALL_CANCEL_BTN_COLOR_ACTIVE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: GREY_DARK,
|
||||
background_color: WHITE,
|
||||
border_color: WHITE,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_install_confirm() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_BG,
|
||||
button_color: WHITE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_BG,
|
||||
button_color: BLD_INSTALL_BTN_COLOR_ACTIVE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: FG,
|
||||
button_color: GREY_DARK,
|
||||
background_color: FG,
|
||||
border_color: FG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_wipe_cancel() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_WIPE_COLOR,
|
||||
button_color: WHITE,
|
||||
background_color: BLD_WIPE_COLOR,
|
||||
border_color: BLD_WIPE_COLOR,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_WIPE_COLOR,
|
||||
button_color: BLD_WIPE_CANCEL_BTN_COLOR_ACTIVE,
|
||||
background_color: BLD_WIPE_COLOR,
|
||||
border_color: BLD_WIPE_COLOR,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: GREY_DARK,
|
||||
background_color: WHITE,
|
||||
border_color: WHITE,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_wipe_confirm() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: WHITE,
|
||||
button_color: BLD_WIPE_BTN_COLOR,
|
||||
background_color: BLD_WIPE_COLOR,
|
||||
border_color: BLD_WIPE_COLOR,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: WHITE,
|
||||
button_color: BLD_WIPE_BTN_COLOR_ACTIVE,
|
||||
background_color: BLD_WIPE_COLOR,
|
||||
border_color: BLD_WIPE_COLOR,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: FG,
|
||||
button_color: GREY_DARK,
|
||||
background_color: FG,
|
||||
border_color: FG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_bld_menu() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_FG,
|
||||
button_color: BLD_BTN_MENU_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_FG,
|
||||
button_color: BLD_BTN_MENU_COLOR_ACTIVE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: BLD_BTN_MENU_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_bld_menu_item() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_FG,
|
||||
button_color: BLD_BTN_MENUITEM_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_FG,
|
||||
button_color: BLD_BTN_MENUITEM_COLOR_ACTIVE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: BLD_BTN_MENUITEM_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
pub const TEXT_WELCOME: TextStyle = TextStyle::new(
|
||||
Font::NORMAL,
|
||||
GREY_MEDIUM,
|
||||
WELCOME_COLOR,
|
||||
GREY_MEDIUM,
|
||||
GREY_MEDIUM,
|
||||
);
|
||||
pub const TEXT_WELCOME_BOLD: TextStyle = TextStyle::new(Font::BOLD, FG, WELCOME_COLOR, FG, FG);
|
||||
pub const TEXT_TITLE: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
BLD_TITLE_COLOR,
|
||||
BLD_BG,
|
||||
BLD_TITLE_COLOR,
|
||||
BLD_TITLE_COLOR,
|
||||
);
|
||||
pub const TEXT_SUBMSG_INITIAL: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
GREY_MEDIUM,
|
||||
WELCOME_COLOR,
|
||||
GREY_MEDIUM,
|
||||
GREY_MEDIUM,
|
||||
);
|
||||
|
||||
pub const TEXT_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
|
||||
pub const TEXT_FINGERPRINT: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG)
|
||||
.with_line_breaking(BreakWordsNoHyphen);
|
||||
pub const TEXT_BOLD: TextStyle = TextStyle::new(Font::BOLD, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
|
||||
pub const TEXT_WIPE_BOLD: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
BLD_WIPE_TEXT_COLOR,
|
||||
BLD_WIPE_COLOR,
|
||||
BLD_WIPE_TEXT_COLOR,
|
||||
BLD_WIPE_TEXT_COLOR,
|
||||
);
|
||||
pub const TEXT_SUBMSG: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
BLD_COLOR_SUBMSG,
|
||||
BLD_BG,
|
||||
BLD_COLOR_SUBMSG,
|
||||
BLD_COLOR_SUBMSG,
|
||||
);
|
@ -21,6 +21,7 @@ pub enum ButtonMsg {
|
||||
|
||||
pub struct Button<T> {
|
||||
area: Rect,
|
||||
touch_expand: Option<Insets>,
|
||||
content: ButtonContent<T>,
|
||||
styles: ButtonStyleSheet,
|
||||
state: State,
|
||||
@ -37,6 +38,7 @@ impl<T> Button<T> {
|
||||
Self {
|
||||
content,
|
||||
area: Rect::zero(),
|
||||
touch_expand: None,
|
||||
styles: theme::button_default(),
|
||||
state: State::Initial,
|
||||
long_press: None,
|
||||
@ -69,6 +71,11 @@ impl<T> Button<T> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_expanded_touch_area(mut self, expand: Insets) -> Self {
|
||||
self.touch_expand = Some(expand);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_long_press(mut self, duration: Duration) -> Self {
|
||||
self.long_press = Some(duration);
|
||||
self
|
||||
@ -234,6 +241,12 @@ where
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
let touch_area = if let Some(expand) = self.touch_expand {
|
||||
self.area.outset(expand)
|
||||
} else {
|
||||
self.area
|
||||
};
|
||||
|
||||
match event {
|
||||
Event::Touch(TouchEvent::TouchStart(pos)) => {
|
||||
match self.state {
|
||||
@ -242,7 +255,7 @@ where
|
||||
}
|
||||
_ => {
|
||||
// Touch started in our area, transform to `Pressed` state.
|
||||
if self.area.contains(pos) {
|
||||
if touch_area.contains(pos) {
|
||||
self.set(ctx, State::Pressed);
|
||||
if let Some(duration) = self.long_press {
|
||||
self.long_timer = Some(ctx.request_timer(duration));
|
||||
@ -254,7 +267,7 @@ where
|
||||
}
|
||||
Event::Touch(TouchEvent::TouchMove(pos)) => {
|
||||
match self.state {
|
||||
State::Pressed if !self.area.contains(pos) => {
|
||||
State::Pressed if !touch_area.contains(pos) => {
|
||||
// Touch is leaving our area, transform to `Released` state.
|
||||
self.set(ctx, State::Released);
|
||||
return Some(ButtonMsg::Released);
|
||||
@ -269,7 +282,7 @@ where
|
||||
State::Initial | State::Disabled => {
|
||||
// Do nothing.
|
||||
}
|
||||
State::Pressed if self.area.contains(pos) => {
|
||||
State::Pressed if touch_area.contains(pos) => {
|
||||
// Touch finished in our area, we got clicked.
|
||||
self.set(ctx, State::Initial);
|
||||
return Some(ButtonMsg::Clicked);
|
||||
@ -554,7 +567,7 @@ impl IconText {
|
||||
Self { text, icon }
|
||||
}
|
||||
|
||||
pub fn paint(&self, area: Rect, style: &ButtonStyle, baseline_offset: i32) {
|
||||
pub fn paint(&self, area: Rect, style: &ButtonStyle, baseline_offset: i16) {
|
||||
let width = style.font.text_width(self.text);
|
||||
let height = style.font.text_height();
|
||||
|
||||
@ -570,8 +583,7 @@ impl IconText {
|
||||
|
||||
if area.width() > (Self::ICON_SPACE + Self::TEXT_MARGIN + width) {
|
||||
//display both icon and text
|
||||
let start_of_baseline = area.center() + Offset::new(-width / 2, height / 2);
|
||||
text_pos = Point::new(area.top_left().x + Self::ICON_SPACE, start_of_baseline.y);
|
||||
text_pos = Point::new(area.top_left().x + Self::ICON_SPACE, text_pos.y);
|
||||
use_text = true;
|
||||
use_icon = true;
|
||||
} else if area.width() > (width + Self::TEXT_MARGIN) {
|
||||
|
@ -5,24 +5,27 @@ mod fido;
|
||||
mod fido_icons;
|
||||
mod frame;
|
||||
mod hold_to_confirm;
|
||||
#[cfg(feature = "dma2d")]
|
||||
mod homescreen;
|
||||
mod keyboard;
|
||||
mod loader;
|
||||
mod number_input;
|
||||
mod page;
|
||||
mod progress;
|
||||
mod result;
|
||||
mod scroll;
|
||||
mod swipe;
|
||||
mod welcome_screen;
|
||||
|
||||
pub use button::{
|
||||
Button, ButtonContent, ButtonMsg, ButtonStyle, ButtonStyleSheet, CancelConfirmMsg,
|
||||
CancelInfoConfirmMsg, SelectWordMsg,
|
||||
CancelInfoConfirmMsg, IconText, SelectWordMsg,
|
||||
};
|
||||
pub use dialog::{Dialog, DialogMsg, IconDialog};
|
||||
pub use fido::{FidoConfirm, FidoMsg};
|
||||
pub use frame::{Frame, NotificationFrame};
|
||||
pub use hold_to_confirm::{HoldToConfirm, HoldToConfirmMsg};
|
||||
#[cfg(feature = "dma2d")]
|
||||
pub use homescreen::{Homescreen, HomescreenMsg, Lockscreen};
|
||||
pub use keyboard::{
|
||||
bip39::Bip39Input,
|
||||
@ -36,6 +39,7 @@ pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
|
||||
pub use number_input::{NumberInputDialog, NumberInputDialogMsg};
|
||||
pub use page::{SwipeHoldPage, SwipePage};
|
||||
pub use progress::Progress;
|
||||
pub use result::ResultScreen;
|
||||
pub use scroll::ScrollBar;
|
||||
pub use swipe::{Swipe, SwipeDirection};
|
||||
pub use welcome_screen::WelcomeScreen;
|
||||
|
93
core/embed/rust/src/ui/model_tt/component/result.rs
Normal file
93
core/embed/rust/src/ui/model_tt/component/result.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use crate::{
|
||||
alpha,
|
||||
ui::{
|
||||
component::{
|
||||
text::paragraphs::{ParagraphStrType, ParagraphVecShort, Paragraphs},
|
||||
Child, Component, Event, EventCtx, Never, Pad,
|
||||
},
|
||||
constant::screen,
|
||||
display::{self, Color, Icon},
|
||||
geometry::{Offset, Point, Rect, CENTER},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::ui::model_tt::constant::{HEIGHT, WIDTH};
|
||||
|
||||
pub struct ResultScreen<T> {
|
||||
bg: Pad,
|
||||
small_pad: Pad,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Icon,
|
||||
message_top: Child<Paragraphs<ParagraphVecShort<T>>>,
|
||||
message_bottom: Child<Paragraphs<ParagraphVecShort<T>>>,
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType> ResultScreen<T> {
|
||||
pub fn new(
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Icon,
|
||||
message_top: Paragraphs<ParagraphVecShort<T>>,
|
||||
message_bottom: Paragraphs<ParagraphVecShort<T>>,
|
||||
complete_draw: bool,
|
||||
) -> Self {
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(bg_color),
|
||||
small_pad: Pad::with_background(bg_color),
|
||||
fg_color,
|
||||
bg_color,
|
||||
icon,
|
||||
message_top: Child::new(message_top),
|
||||
message_bottom: Child::new(message_bottom),
|
||||
};
|
||||
|
||||
if complete_draw {
|
||||
instance.bg.clear();
|
||||
} else {
|
||||
instance.small_pad.clear();
|
||||
}
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType> Component for ResultScreen<T> {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg
|
||||
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
|
||||
|
||||
self.message_top
|
||||
.place(Rect::new(Point::new(15, 59), Point::new(WIDTH - 15, 149)));
|
||||
|
||||
let bottom_area = Rect::new(Point::new(15, 151), Point::new(WIDTH - 15, HEIGHT));
|
||||
|
||||
self.small_pad.place(bottom_area);
|
||||
self.message_bottom.place(bottom_area);
|
||||
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.small_pad.paint();
|
||||
|
||||
self.icon.draw(
|
||||
Point::new(screen().center().x, 45),
|
||||
CENTER,
|
||||
self.fg_color,
|
||||
self.bg_color,
|
||||
);
|
||||
display::rect_fill(
|
||||
Rect::from_top_left_and_size(Point::new(12, 149), Offset::new(216, 1)),
|
||||
Color::alpha(self.bg_color, alpha!(0.2)),
|
||||
);
|
||||
self.message_top.paint();
|
||||
self.message_bottom.paint();
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@ pub const LOADER_OUTER: f32 = 60_f32;
|
||||
pub const LOADER_INNER: f32 = 42_f32;
|
||||
pub const LOADER_ICON_MAX_SIZE: i16 = 64;
|
||||
|
||||
pub const BACKLIGHT_NORMAL: i32 = 150;
|
||||
|
||||
pub const fn size() -> Offset {
|
||||
Offset::new(WIDTH, HEIGHT)
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
#[cfg(feature = "bootloader")]
|
||||
pub mod bootloader;
|
||||
pub mod component;
|
||||
pub mod constant;
|
||||
pub mod event;
|
||||
@ -5,3 +7,4 @@ pub mod theme;
|
||||
|
||||
#[cfg(feature = "micropython")]
|
||||
pub mod layout;
|
||||
pub mod screens;
|
||||
|
BIN
core/embed/rust/src/ui/model_tt/res/close.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/close.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tt/res/erase.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/erase.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tt/res/erase_big.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/erase_big.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tt/res/info_small.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/info_small.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tt/res/menu.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/menu.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tt/res/reboot.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/reboot.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tt/res/receive.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/receive.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tt/res/success_bld.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/success_bld.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tt/res/trezor_empty.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/trezor_empty.toif
Normal file
Binary file not shown.
BIN
core/embed/rust/src/ui/model_tt/res/warn_bld.toif
Normal file
BIN
core/embed/rust/src/ui/model_tt/res/warn_bld.toif
Normal file
Binary file not shown.
104
core/embed/rust/src/ui/model_tt/screens.rs
Normal file
104
core/embed/rust/src/ui/model_tt/screens.rs
Normal file
@ -0,0 +1,104 @@
|
||||
#[cfg(feature = "micropython")]
|
||||
use crate::micropython::buffer::StrBuffer;
|
||||
use crate::ui::{
|
||||
component::{
|
||||
text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt},
|
||||
Component,
|
||||
},
|
||||
display::Icon,
|
||||
geometry::LinearPlacement,
|
||||
model_tt::{
|
||||
component::ResultScreen,
|
||||
constant,
|
||||
theme::{FATAL_ERROR_COLOR, ICON_WARN_SMALL, TEXT_ERROR_BOLD, TEXT_ERROR_NORMAL, WHITE},
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "micropython"))]
|
||||
// SAFETY: Actually safe but see below
|
||||
unsafe fn get_str(text: &str) -> &str {
|
||||
text
|
||||
}
|
||||
#[cfg(feature = "micropython")]
|
||||
// SAFETY: The caller is responsible for ensuring that the StrBuffer does not
|
||||
// escape the lifetime of the original &str.
|
||||
unsafe fn get_str(text: &str) -> StrBuffer {
|
||||
unsafe { StrBuffer::from_ptr_and_len(text.as_ptr(), text.len()) }
|
||||
}
|
||||
|
||||
pub fn screen_fatal_error(msg: Option<&str>, file: &str) {
|
||||
// SAFETY: these will get placed into `frame` which does not outlive this
|
||||
// function
|
||||
let msg = msg.map(|s| unsafe { get_str(s) });
|
||||
let file = unsafe { get_str(file) };
|
||||
|
||||
let m_top = if let Some(msg) = msg {
|
||||
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());
|
||||
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
|
||||
} 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_BOLD, "PLEASE CONTACT\nTREZOR SUPPORT".into()).centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
FATAL_ERROR_COLOR,
|
||||
Icon::new(ICON_WARN_SMALL),
|
||||
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();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, label).centered());
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
|
||||
};
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "PLEASE UNPLUG\nTHE DEVICE".into()).centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
FATAL_ERROR_COLOR,
|
||||
Icon::new(ICON_WARN_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
true,
|
||||
);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
}
|
@ -42,6 +42,8 @@ pub const GREY_MEDIUM: Color = Color::rgb(0x45, 0x45, 0x45); // button pressed
|
||||
pub const GREY_DARK: Color = Color::rgb(0x1A, 0x1A, 0x1A); // button
|
||||
pub const VIOLET: Color = Color::rgb(0x95, 0x00, 0xCA);
|
||||
|
||||
pub const FATAL_ERROR_COLOR: Color = Color::rgb(0xAD, 0x2B, 0x2B);
|
||||
|
||||
// Commonly used corner radius (i.e. for buttons).
|
||||
pub const RADIUS: u8 = 2;
|
||||
|
||||
@ -64,6 +66,8 @@ pub const ICON_LIST_CURRENT: &[u8] = include_res!("model_tt/res/current.toif");
|
||||
pub const ICON_LIST_CHECK: &[u8] = include_res!("model_tt/res/check.toif");
|
||||
pub const ICON_LOCK: &[u8] = include_res!("model_tt/res/lock.toif");
|
||||
pub const ICON_LOGO: &[u8] = include_res!("model_tt/res/logo.toif");
|
||||
pub const ICON_SUCCESS_SMALL: &[u8] = include_res!("model_tt/res/success_bld.toif");
|
||||
pub const ICON_WARN_SMALL: &[u8] = include_res!("model_tt/res/warn_bld.toif");
|
||||
|
||||
// Large, three-color icons.
|
||||
pub const WARN_COLOR: Color = YELLOW;
|
||||
@ -397,6 +401,10 @@ pub fn textstyle_number(num: i32) -> &'static TextStyle {
|
||||
_ => &TEXT_NORMAL,
|
||||
}
|
||||
}
|
||||
pub const TEXT_ERROR_NORMAL: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, FG, FATAL_ERROR_COLOR, GREY_LIGHT, GREY_LIGHT);
|
||||
pub const TEXT_ERROR_BOLD: TextStyle =
|
||||
TextStyle::new(Font::BOLD, FG, FATAL_ERROR_COLOR, GREY_LIGHT, GREY_LIGHT);
|
||||
|
||||
pub const TEXT_NORMAL_OFF_WHITE: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, OFF_WHITE, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
|
40
core/embed/rust/src/ui/screens.rs
Normal file
40
core/embed/rust/src/ui/screens.rs
Normal file
@ -0,0 +1,40 @@
|
||||
//! 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_c(msg: *const cty::c_char, file: *const cty::c_char) {
|
||||
let msg = if msg.is_null() {
|
||||
None
|
||||
} else {
|
||||
unsafe { from_c_str(msg) }
|
||||
};
|
||||
let file = if file.is_null() {
|
||||
""
|
||||
} else {
|
||||
unwrap!(unsafe { from_c_str(file) })
|
||||
};
|
||||
|
||||
screen_fatal_error(msg, file);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_error_shutdown_c(msg: *const cty::c_char, file: *const cty::c_char) {
|
||||
let msg = if msg.is_null() {
|
||||
None
|
||||
} else {
|
||||
unsafe { from_c_str(msg) }
|
||||
};
|
||||
let file = if file.is_null() {
|
||||
""
|
||||
} else {
|
||||
unwrap!(unsafe { from_c_str(file) })
|
||||
};
|
||||
|
||||
screen_fatal_error(msg, file);
|
||||
}
|
@ -5,6 +5,8 @@ use crate::ui::{
|
||||
geometry::{Offset, Point, CENTER},
|
||||
};
|
||||
|
||||
use cstr_core::CStr;
|
||||
|
||||
pub trait ResultExt {
|
||||
fn assert_if_debugging_ui(self, message: &str);
|
||||
}
|
||||
@ -38,6 +40,46 @@ pub fn u32_to_str(num: u32, buffer: &mut [u8]) -> Option<&str> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a string from a C string.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller is responsible that the pointer is valid, which means that:
|
||||
/// (a) it is not null,
|
||||
/// (b) it points to a memory containing a valid C string (zero-terminated
|
||||
/// sequence of characters), and
|
||||
/// (c) that the pointer has appropriate lifetime.
|
||||
pub unsafe fn from_c_str<'a>(c_str: *const cty::c_char) -> Option<&'a str> {
|
||||
unsafe {
|
||||
let bytes = CStr::from_ptr(c_str).to_bytes();
|
||||
if bytes.is_ascii() {
|
||||
Some(core::str::from_utf8_unchecked(bytes))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct str from a C array.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller is responsible that the pointer is valid, which means that:
|
||||
/// (a) it is not null,
|
||||
/// (b) it points to a memory containing array of characters, with length `len`,
|
||||
/// and
|
||||
/// (c) that the pointer has appropriate lifetime.
|
||||
pub unsafe fn from_c_array<'a>(c_str: *const cty::c_char, len: usize) -> Option<&'a str> {
|
||||
unsafe {
|
||||
let slice = core::slice::from_raw_parts(c_str as *const u8, len);
|
||||
if slice.is_ascii() {
|
||||
Some(core::str::from_utf8_unchecked(slice))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
static mut DISABLE_ANIMATION: bool = false;
|
||||
|
||||
|
@ -23,11 +23,15 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "display.h"
|
||||
#ifdef FANCY_FATAL_ERROR
|
||||
#include "rust_ui.h"
|
||||
#endif
|
||||
#include "flash.h"
|
||||
#include "rand.h"
|
||||
#include "stm32.h"
|
||||
#include "supervise.h"
|
||||
|
||||
#include "mini_printf.h"
|
||||
#include "stm32f4xx_ll_utils.h"
|
||||
|
||||
#ifdef RGB16
|
||||
@ -39,13 +43,16 @@
|
||||
// from util.s
|
||||
extern void shutdown_privileged(void);
|
||||
|
||||
void shutdown(void) {
|
||||
void __attribute__((noreturn)) shutdown(void) {
|
||||
#ifdef USE_SVC_SHUTDOWN
|
||||
svc_shutdown();
|
||||
#else
|
||||
// It won't work properly unless called from the privileged mode
|
||||
shutdown_privileged();
|
||||
#endif
|
||||
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn))
|
||||
@ -53,6 +60,13 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line,
|
||||
const char *func) {
|
||||
display_orientation(0);
|
||||
display_backlight(255);
|
||||
|
||||
#ifdef FANCY_FATAL_ERROR
|
||||
char buf[256] = {0};
|
||||
mini_snprintf(buf, sizeof(buf), "%s: %d", file, line);
|
||||
screen_fatal_error_c(msg, buf);
|
||||
display_refresh();
|
||||
#else
|
||||
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
display_printf("\nFATAL ERROR:\n");
|
||||
if (expr) {
|
||||
@ -73,58 +87,28 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line,
|
||||
rev[4]);
|
||||
#endif
|
||||
display_printf("\nPlease contact Trezor support.\n");
|
||||
#endif
|
||||
shutdown();
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn))
|
||||
error_shutdown(const char *line1, const char *line2, const char *line3,
|
||||
const char *line4) {
|
||||
error_shutdown(const char *label, const char *msg) {
|
||||
display_orientation(0);
|
||||
#ifdef TREZOR_FONT_NORMAL_ENABLE
|
||||
display_clear();
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR);
|
||||
int y = 32;
|
||||
if (line1) {
|
||||
display_text(8, y, line1, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
y += 32;
|
||||
}
|
||||
if (line2) {
|
||||
display_text(8, y, line2, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
y += 32;
|
||||
}
|
||||
if (line3) {
|
||||
display_text(8, y, line3, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
y += 32;
|
||||
}
|
||||
if (line4) {
|
||||
display_text(8, y, line4, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
y += 32;
|
||||
}
|
||||
y += 32;
|
||||
display_text(8, y, "Please unplug the device.", -1, FONT_NORMAL, COLOR_WHITE,
|
||||
COLOR_FATAL_ERROR);
|
||||
#ifdef FANCY_FATAL_ERROR
|
||||
screen_error_shutdown_c(label, msg);
|
||||
display_refresh();
|
||||
#else
|
||||
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
if (line1) {
|
||||
display_printf("%s\n", line1);
|
||||
if (label) {
|
||||
display_printf("%s\n", label);
|
||||
}
|
||||
if (line2) {
|
||||
display_printf("%s\n", line2);
|
||||
}
|
||||
if (line3) {
|
||||
display_printf("%s\n", line3);
|
||||
}
|
||||
if (line4) {
|
||||
display_printf("%s\n", line4);
|
||||
if (msg) {
|
||||
display_printf("%s\n", msg);
|
||||
}
|
||||
display_printf("\nPlease unplug the device.\n");
|
||||
#endif
|
||||
display_backlight(255);
|
||||
shutdown();
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
@ -157,7 +141,7 @@ void clear_otg_hs_memory(void) {
|
||||
uint32_t __stack_chk_guard = 0;
|
||||
|
||||
void __attribute__((noreturn)) __stack_chk_fail(void) {
|
||||
error_shutdown("Internal error", "(SS)", NULL, NULL);
|
||||
error_shutdown("Internal error", "(SS)");
|
||||
}
|
||||
|
||||
uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
|
||||
@ -197,3 +181,13 @@ void ensure_compatible_settings(void) {
|
||||
display_set_slow_pwm();
|
||||
#endif
|
||||
}
|
||||
|
||||
void show_wipe_code_screen(void) {
|
||||
error_shutdown(
|
||||
"DEVICE WIPED!",
|
||||
"You have entered the wipe code. All private data has been erased.");
|
||||
}
|
||||
void show_pin_too_many_screen(void) {
|
||||
error_shutdown("DEVICE WIPED!",
|
||||
"Too many wrong PIN attempts. Storage has been wiped.");
|
||||
}
|
||||
|
@ -51,14 +51,16 @@
|
||||
|
||||
#define STAY_IN_BOOTLOADER_FLAG 0x0FC35A96
|
||||
|
||||
void shutdown(void);
|
||||
void __attribute__((noreturn)) shutdown(void);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
__fatal_error(const char *expr, const char *msg, const char *file, int line,
|
||||
const char *func);
|
||||
void __attribute__((noreturn))
|
||||
error_shutdown(const char *line1, const char *line2, const char *line3,
|
||||
const char *line4);
|
||||
error_shutdown(const char *label, const char *msg);
|
||||
|
||||
void show_wipe_code_screen(void);
|
||||
void show_pin_too_many_screen(void);
|
||||
|
||||
#define ensure(expr, msg) \
|
||||
(((expr) == sectrue) \
|
||||
|
@ -103,19 +103,22 @@ secbool check_image_model(const image_header *const hdr) {
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool check_image_header_sig(const image_header *const hdr, uint8_t key_m,
|
||||
uint8_t key_n, const uint8_t *const *keys) {
|
||||
// check header signature
|
||||
void get_image_fingerprint(const image_header *const hdr, uint8_t *const out) {
|
||||
BLAKE2S_CTX ctx;
|
||||
uint8_t fingerprint[32];
|
||||
|
||||
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
|
||||
blake2s_Update(&ctx, hdr, IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE);
|
||||
for (int i = 0; i < IMAGE_SIG_SIZE; i++) {
|
||||
blake2s_Update(&ctx, (const uint8_t *)"\x00", 1);
|
||||
}
|
||||
blake2s_Final(&ctx, out, BLAKE2S_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
blake2s_Final(&ctx, fingerprint, BLAKE2S_DIGEST_LENGTH);
|
||||
secbool check_image_header_sig(const image_header *const hdr, uint8_t key_m,
|
||||
uint8_t key_n, const uint8_t *const *keys) {
|
||||
// check header signature
|
||||
|
||||
uint8_t fingerprint[32];
|
||||
get_image_fingerprint(hdr, fingerprint);
|
||||
|
||||
ed25519_public_key pub;
|
||||
if (sectrue != compute_pubkey(key_m, key_n, keys, hdr->sigmask, pub))
|
||||
|
@ -107,4 +107,6 @@ secbool __wur check_image_contents(const image_header *const hdr,
|
||||
uint32_t firstskip, const uint8_t *sectors,
|
||||
int blocks);
|
||||
|
||||
void get_image_fingerprint(const image_header *const hdr, uint8_t *const out);
|
||||
|
||||
#endif
|
||||
|
@ -133,7 +133,7 @@ static void _i2c_init(void) {
|
||||
i2c_handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
|
||||
|
||||
if (HAL_OK != HAL_I2C_Init(&i2c_handle)) {
|
||||
ensure(secfalse, NULL);
|
||||
ensure(secfalse, "Touch screen panel was not loaded properly.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -211,7 +211,7 @@ void touch_set_mode(void) {
|
||||
sectrue * (HAL_OK == HAL_I2C_Master_Transmit(
|
||||
&i2c_handle, TOUCH_ADDRESS, touch_panel_config,
|
||||
sizeof(touch_panel_config), 10)),
|
||||
NULL);
|
||||
"Touch screen panel was not loaded properly.");
|
||||
}
|
||||
|
||||
void touch_power_on(void) {
|
||||
|
@ -25,15 +25,22 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "display.h"
|
||||
#ifdef FANCY_FATAL_ERROR
|
||||
#include "rust_ui.h"
|
||||
#endif
|
||||
#include "memzero.h"
|
||||
|
||||
extern void main_clean_exit();
|
||||
|
||||
void __shutdown(void) {
|
||||
void __attribute__((noreturn)) __shutdown(void) {
|
||||
printf("SHUTDOWN\n");
|
||||
main_clean_exit(3);
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) shutdown(void) { __shutdown(); }
|
||||
|
||||
#ifdef RGB16
|
||||
#define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00)
|
||||
#else
|
||||
@ -46,6 +53,13 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line,
|
||||
const char *func) {
|
||||
display_orientation(0);
|
||||
display_backlight(255);
|
||||
|
||||
#ifdef FANCY_FATAL_ERROR
|
||||
char buf[256] = {0};
|
||||
snprintf(buf, sizeof(buf), "%s: %d", file, line);
|
||||
screen_fatal_error_c(msg, buf);
|
||||
display_refresh();
|
||||
#else
|
||||
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
display_printf("\nFATAL ERROR:\n");
|
||||
printf("\nFATAL ERROR:\n");
|
||||
@ -74,42 +88,35 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line,
|
||||
#endif
|
||||
display_printf("\n\n\nHint:\nIsn't the emulator already running?\n");
|
||||
printf("Hint:\nIsn't the emulator already running?\n");
|
||||
#endif
|
||||
hal_delay(3000);
|
||||
__shutdown();
|
||||
for (;;)
|
||||
;
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void __attribute__((noreturn))
|
||||
error_shutdown(const char *line1, const char *line2, const char *line3,
|
||||
const char *line4) {
|
||||
error_shutdown(const char *label, const char *msg) {
|
||||
#ifdef FANCY_FATAL_ERROR
|
||||
screen_error_shutdown_c(label, msg);
|
||||
display_refresh();
|
||||
#else
|
||||
display_clear();
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR);
|
||||
int y = 32;
|
||||
if (line1) {
|
||||
display_text(8, y, line1, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
printf("%s\n", line1);
|
||||
if (label) {
|
||||
display_text(8, y, label, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
printf("%s\n", label);
|
||||
y += 32;
|
||||
}
|
||||
if (line2) {
|
||||
display_text(8, y, line2, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
printf("%s\n", line2);
|
||||
y += 32;
|
||||
}
|
||||
if (line3) {
|
||||
display_text(8, y, line3, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
printf("%s\n", line3);
|
||||
y += 32;
|
||||
}
|
||||
if (line4) {
|
||||
display_text(8, y, line4, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
printf("%s\n", line4);
|
||||
if (msg) {
|
||||
display_text(8, y, msg, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
printf("%s\n", msg);
|
||||
y += 32;
|
||||
}
|
||||
y += 32;
|
||||
display_text(8, y, "Please unplug the device.", -1, FONT_NORMAL, COLOR_WHITE,
|
||||
COLOR_FATAL_ERROR);
|
||||
printf("\nPlease unplug the device.\n");
|
||||
#endif
|
||||
display_backlight(255);
|
||||
hal_delay(5000);
|
||||
exit(4);
|
||||
@ -153,3 +160,13 @@ void emulator_poll_events(void) {
|
||||
uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
|
||||
|
||||
void collect_hw_entropy(void) { memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); }
|
||||
|
||||
void show_wipe_code_screen(void) {
|
||||
error_shutdown(
|
||||
"DEVICE WIPED!",
|
||||
"You have entered the wipe code. All private data has been erased.");
|
||||
}
|
||||
void show_pin_too_many_screen(void) {
|
||||
error_shutdown("DEVICE WIPED!",
|
||||
"Too many wrong PIN attempts. Storage has been wiped.");
|
||||
}
|
||||
|
@ -40,12 +40,15 @@
|
||||
})
|
||||
#endif
|
||||
|
||||
void __attribute__((noreturn)) shutdown(void);
|
||||
|
||||
void __attribute__((noreturn))
|
||||
__fatal_error(const char *expr, const char *msg, const char *file, int line,
|
||||
const char *func);
|
||||
void __attribute__((noreturn))
|
||||
error_shutdown(const char *line1, const char *line2, const char *line3,
|
||||
const char *line4);
|
||||
error_shutdown(const char *label, const char *msg);
|
||||
void show_wipe_code_screen(void);
|
||||
void show_pin_too_many_screen(void);
|
||||
|
||||
#define ensure(expr, msg) \
|
||||
(((expr) == sectrue) \
|
||||
|
@ -115,3 +115,12 @@ uint32_t drbg_random32(void) {
|
||||
drbg_generate((uint8_t *)&value, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
void show_wipe_code_screen(void) {
|
||||
error_shutdown("You have entered the", "wipe code. All private",
|
||||
"data has been erased.", NULL);
|
||||
}
|
||||
void show_pin_too_many_screen(void) {
|
||||
error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.",
|
||||
NULL);
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ __fatal_error(const char *expr, const char *msg, const char *file, int line,
|
||||
void __attribute__((noreturn))
|
||||
error_shutdown(const char *line1, const char *line2, const char *line3,
|
||||
const char *line4);
|
||||
void show_wipe_code_screen(void);
|
||||
void show_pin_too_many_screen(void);
|
||||
|
||||
#define ensure(expr, msg) \
|
||||
(((expr) == sectrue) \
|
||||
|
@ -992,8 +992,7 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv) {
|
||||
static void ensure_not_wipe_code(const uint8_t *pin, size_t pin_len) {
|
||||
if (sectrue != is_not_wipe_code(pin, pin_len)) {
|
||||
storage_wipe();
|
||||
error_shutdown("You have entered the", "wipe code. All private",
|
||||
"data has been erased.", NULL);
|
||||
show_wipe_code_screen();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1028,8 +1027,7 @@ static secbool unlock(const uint8_t *pin, size_t pin_len,
|
||||
wait_random();
|
||||
if (ctr >= PIN_MAX_TRIES) {
|
||||
storage_wipe();
|
||||
error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.",
|
||||
NULL);
|
||||
show_pin_too_many_screen();
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
@ -1091,8 +1089,7 @@ static secbool unlock(const uint8_t *pin, size_t pin_len,
|
||||
wait_random();
|
||||
if (ctr + 1 >= PIN_MAX_TRIES) {
|
||||
storage_wipe();
|
||||
error_shutdown("Too many wrong PIN", "attempts. Storage has",
|
||||
"been wiped.", NULL);
|
||||
show_pin_too_many_screen();
|
||||
}
|
||||
return secfalse;
|
||||
}
|
||||
|
@ -46,12 +46,5 @@ void __fatal_error(const char *expr, const char *msg, const char *file,
|
||||
__shutdown();
|
||||
}
|
||||
|
||||
void error_shutdown(const char *line1, const char *line2, const char *line3,
|
||||
const char *line4) {
|
||||
// For testing do not treat pin_fails_check_max as a fatal error.
|
||||
(void)line1;
|
||||
(void)line2;
|
||||
(void)line3;
|
||||
(void)line4;
|
||||
return;
|
||||
}
|
||||
void show_wipe_code_screen(void) {}
|
||||
void show_pin_too_many_screen(void) {}
|
||||
|
@ -24,8 +24,9 @@
|
||||
|
||||
void __fatal_error(const char *expr, const char *msg, const char *file,
|
||||
int line, const char *func);
|
||||
void error_shutdown(const char *line1, const char *line2, const char *line3,
|
||||
const char *line4);
|
||||
|
||||
void show_wipe_code_screen(void);
|
||||
void show_pin_too_many_screen(void);
|
||||
|
||||
#define ensure(expr, msg) \
|
||||
(((expr) == sectrue) \
|
||||
|
Loading…
Reference in New Issue
Block a user