mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-02-20 11:32:04 +00:00
feat(core/rust): bootloader implementation in rust
This commit is contained in:
parent
a5dd838883
commit
c8871aac1a
1
core/.changelog.d/1049.added
Normal file
1
core/.changelog.d/1049.added
Normal file
@ -0,0 +1 @@
|
||||
Error screens redesign
|
@ -29,10 +29,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 '
|
||||
@ -44,6 +44,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',
|
||||
|
@ -194,8 +194,12 @@ SOURCE_MOD += [
|
||||
if UI2:
|
||||
CPPDEFINES_MOD += [
|
||||
'TREZOR_UI2',
|
||||
'USE_RUST_LOADER'
|
||||
'USE_RUST_LOADER',
|
||||
]
|
||||
if TREZOR_MODEL not in ('1', ):
|
||||
CPPDEFINES_MOD += [
|
||||
'FANCY_FATAL_ERROR',
|
||||
]
|
||||
|
||||
# modtrezorutils
|
||||
SOURCE_MOD += [
|
||||
|
@ -190,8 +190,12 @@ SOURCE_MOD += [
|
||||
if UI2:
|
||||
CPPDEFINES_MOD += [
|
||||
'TREZOR_UI2',
|
||||
'USE_RUST_LOADER'
|
||||
'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/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/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
|
@ -34,6 +34,8 @@
|
||||
#include "mini_printf.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "rust_ui.h"
|
||||
|
||||
#if defined TREZOR_MODEL_T
|
||||
#include "touch.h"
|
||||
#elif defined TREZOR_MODEL_R
|
||||
@ -64,29 +66,26 @@
|
||||
|
||||
// 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 void format_ver_bfr(const char *format, uint32_t version, char *bfr,
|
||||
size_t bfr_len) {
|
||||
mini_snprintf(bfr, bfr_len, format, (int)(version & 0xFF),
|
||||
(int)((version >> 8) & 0xFF), (int)((version >> 16) & 0xFF)
|
||||
// ignore build field (int)((version >> 24) & 0xFF)
|
||||
);
|
||||
}
|
||||
|
||||
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),
|
||||
(int)((version >> 8) & 0xFF), (int)((version >> 16) & 0xFF)
|
||||
// ignore build field (int)((version >> 24) & 0xFF)
|
||||
);
|
||||
format_ver_bfr(format, version, ver_str, sizeof(ver_str));
|
||||
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) {
|
||||
@ -159,160 +158,77 @@ void ui_screen_welcome_third(void) {
|
||||
COLOR_WELCOME_FG, COLOR_WELCOME_BG);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
uint32_t ui_screen_intro(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
char bld_ver[32];
|
||||
format_ver_bfr("%d.%d.%d", VERSION_UINT32, bld_ver, sizeof(bld_ver));
|
||||
const char *ver_str = format_ver("Firmware %d.%d.%d by", hdr->version);
|
||||
return screen_intro(bld_ver, vhdr->vstr, vhdr->vstr_len, ver_str);
|
||||
}
|
||||
|
||||
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);
|
||||
uint32_t ui_screen_menu(void) {
|
||||
char bld_ver[32];
|
||||
format_ver_bfr("%d.%d.%d", VERSION_UINT32, bld_ver, sizeof(bld_ver));
|
||||
return screen_menu(bld_ver);
|
||||
}
|
||||
|
||||
void ui_screen_firmware_fingerprint(const image_header *const hdr) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
display_text(16, 32, "Firmware fingerprint", -1, FONT_NORMAL, COLOR_BL_FG,
|
||||
COLOR_BL_BG);
|
||||
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG);
|
||||
|
||||
uint32_t ui_screen_firmware_fingerprint(const image_header *const hdr) {
|
||||
static const char *hexdigits = "0123456789abcdef";
|
||||
char fingerprint_str[64];
|
||||
char fingerprint_str[65];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
fingerprint_str[i * 2] = hexdigits[(hdr->fingerprint[i] >> 4) & 0xF];
|
||||
fingerprint_str[i * 2 + 1] = hexdigits[hdr->fingerprint[i] & 0xF];
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
display_text_center(120, 70 + i * 25, fingerprint_str + i * 16, 16,
|
||||
FONT_MONO, COLOR_BL_FG, COLOR_BL_BG);
|
||||
}
|
||||
|
||||
display_bar_radius(9, 184, 222, 50, COLOR_BL_DONE, COLOR_BL_BG, 4);
|
||||
display_icon(9 + (222 - 19) / 2, 184 + (50 - 16) / 2, 20, 16,
|
||||
toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12,
|
||||
COLOR_BL_BG, COLOR_BL_DONE);
|
||||
fingerprint_str[64] = 0;
|
||||
return screen_fwinfo(fingerprint_str);
|
||||
}
|
||||
|
||||
// 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);
|
||||
uint32_t ui_screen_install_confirm_upgrade(const vendor_header *const vhdr,
|
||||
const image_header *const hdr) {
|
||||
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();
|
||||
return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str, 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();
|
||||
if (downgrade_wipe) {
|
||||
const char *ver_str = format_ver("to version %d.%d.%d?", hdr->version);
|
||||
return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str, true,
|
||||
false);
|
||||
} else {
|
||||
const char *ver_str = format_ver("version %d.%d.%d?", hdr->version);
|
||||
return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str, 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);
|
||||
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);
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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];
|
||||
@ -323,28 +239,18 @@ 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);
|
||||
|
||||
screen_install_success(str, initial_setup, full_redraw);
|
||||
}
|
||||
|
||||
void ui_screen_boot_empty() {
|
||||
screen_boot_empty();
|
||||
display_refresh();
|
||||
display_backlight(BACKLIGHT_NORMAL);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
void ui_screen_fail(void) { screen_install_fail(); }
|
||||
|
||||
// general functions
|
||||
|
||||
@ -354,43 +260,3 @@ void ui_fadeout(void) {
|
||||
display_fade(BACKLIGHT_NORMAL, 0, 500);
|
||||
display_clear();
|
||||
}
|
||||
|
||||
int ui_user_input(int zones) {
|
||||
for (;;) {
|
||||
#if defined TREZOR_MODEL_T
|
||||
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 TREZOR_MODEL_R
|
||||
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 Unknown Trezor model
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,15 @@
|
||||
|
||||
#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);
|
||||
@ -32,20 +41,23 @@ void ui_screen_welcome_first(void);
|
||||
void ui_screen_welcome_second(void);
|
||||
void ui_screen_welcome_third(void);
|
||||
|
||||
void ui_screen_firmware_info(const vendor_header* const vhdr,
|
||||
const image_header* const hdr);
|
||||
void ui_screen_firmware_fingerprint(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_firmware_fingerprint(const image_header* const hdr);
|
||||
|
||||
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);
|
||||
|
||||
@ -55,6 +67,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();
|
||||
|
||||
// clang-format off
|
||||
#define INPUT_CANCEL 0x01 // Cancel button
|
||||
|
@ -42,7 +42,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;
|
||||
@ -94,8 +94,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) {
|
||||
secbool 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);
|
||||
@ -123,13 +123,10 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
break;
|
||||
case 5: // WipeDevice
|
||||
ui_fadeout();
|
||||
ui_screen_wipe_confirm();
|
||||
ui_fadein();
|
||||
int response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL);
|
||||
uint32_t response = ui_screen_wipe_confirm();
|
||||
if (INPUT_CANCEL == response) {
|
||||
ui_fadeout();
|
||||
ui_screen_firmware_info(vhdr, hdr);
|
||||
ui_fadein();
|
||||
screen_connect();
|
||||
send_user_abort(USB_IFACE_NUM, "Wipe cancelled");
|
||||
break;
|
||||
}
|
||||
@ -139,14 +136,14 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf);
|
||||
if (r < 0) { // error
|
||||
ui_fadeout();
|
||||
ui_screen_fail();
|
||||
screen_wipe_fail();
|
||||
ui_fadein();
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
return secfalse; // shutdown
|
||||
} else { // success
|
||||
ui_fadeout();
|
||||
ui_screen_done(0, sectrue);
|
||||
screen_wipe_success();
|
||||
ui_fadein();
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
@ -179,6 +176,7 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
ui_fadeout();
|
||||
ui_screen_boot_empty();
|
||||
return sectrue; // jump to firmware
|
||||
}
|
||||
break;
|
||||
@ -198,7 +196,7 @@ secbool load_vendor_header_keys(const uint8_t *const data,
|
||||
BOOTLOADER_KEYS, vhdr);
|
||||
}
|
||||
|
||||
static secbool check_vendor_header_lock(const vendor_header *const vhdr) {
|
||||
secbool check_vendor_header_lock(const vendor_header *const vhdr) {
|
||||
uint8_t lock[FLASH_OTP_BLOCK_SIZE];
|
||||
ensure(flash_otp_read(FLASH_OTP_BLOCK_VENDOR_HEADER_LOCK, 0, lock,
|
||||
FLASH_OTP_BLOCK_SIZE),
|
||||
@ -256,6 +254,11 @@ int main(void) {
|
||||
|
||||
#if defined TREZOR_MODEL_T
|
||||
display_set_little_endian();
|
||||
#endif
|
||||
|
||||
ui_screen_boot_empty();
|
||||
|
||||
#if defined TREZOR_MODEL_T
|
||||
touch_power_on();
|
||||
touch_init();
|
||||
#endif
|
||||
@ -271,8 +274,6 @@ int main(void) {
|
||||
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) {
|
||||
@ -301,7 +302,7 @@ int main(void) {
|
||||
|
||||
vendor_header vhdr;
|
||||
image_header hdr;
|
||||
// detect whether the devices contains a valid firmware
|
||||
// detect whether the device contains a valid firmware
|
||||
|
||||
secbool firmware_present =
|
||||
load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr);
|
||||
@ -321,9 +322,14 @@ int main(void) {
|
||||
|
||||
// start the bootloader if no or broken firmware found ...
|
||||
if (firmware_present != sectrue) {
|
||||
// ignore stay in bootloader
|
||||
stay_in_bootloader = secfalse;
|
||||
|
||||
// show intro animation
|
||||
|
||||
// no ui_fadeout(); - we already start from black screen
|
||||
ui_set_initial_setup(true);
|
||||
|
||||
ui_fadeout();
|
||||
ui_screen_welcome_first();
|
||||
ui_fadein();
|
||||
|
||||
@ -349,16 +355,88 @@ int main(void) {
|
||||
}
|
||||
}
|
||||
|
||||
ensure(load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr),
|
||||
"invalid vendor header");
|
||||
ensure(load_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen),
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE,
|
||||
vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub, &hdr),
|
||||
"invalid firmware header");
|
||||
|
||||
// ... 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_fadeout();
|
||||
ui_screen_boot_empty();
|
||||
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_fadeout();
|
||||
ui_screen_wipe();
|
||||
ui_fadein();
|
||||
secbool r = bootloader_WipeDevice();
|
||||
if (r != sectrue) { // error
|
||||
ui_fadeout();
|
||||
screen_wipe_fail();
|
||||
ui_fadein();
|
||||
return 1;
|
||||
} else { // success
|
||||
ui_fadeout();
|
||||
screen_wipe_success();
|
||||
ui_fadein();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SCREEN_WAIT_FOR_HOST:
|
||||
screen_connect();
|
||||
if (sectrue == bootloader_usb_loop(&vhdr, &hdr)) {
|
||||
continue_to_firmware = true;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (continue_to_firmware) {
|
||||
break;
|
||||
} else {
|
||||
ui_fadeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,7 +457,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();
|
||||
|
||||
@ -429,3 +507,5 @@ int main(void) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(HF)"); }
|
||||
|
@ -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
|
||||
@ -507,33 +508,32 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
detect_installation(¤t_vhdr, ¤t_hdr, &vhdr, &hdr, &is_new,
|
||||
&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, ¤t_hdr);
|
||||
ui_fadein();
|
||||
screen_connect();
|
||||
send_user_abort(iface_num, "Firmware install cancelled");
|
||||
return -4;
|
||||
}
|
||||
|
||||
ui_fadeout();
|
||||
ui_screen_install_start();
|
||||
ui_fadein();
|
||||
|
||||
headers_offset = IMAGE_HEADER_SIZE + vhdr.hdrlen;
|
||||
read_offset = IMAGE_INIT_CHUNK_SIZE;
|
||||
|
||||
@ -549,11 +549,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(
|
||||
@ -625,7 +620,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,
|
||||
@ -648,8 +643,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) {
|
||||
int 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");
|
||||
|
@ -48,4 +48,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
|
||||
|
@ -176,7 +176,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
|
||||
@ -184,29 +184,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,24 @@ 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, bool downgrade,
|
||||
bool vendor);
|
||||
uint32_t screen_wipe_confirm(void);
|
||||
uint32_t screen_install_progress(int16_t progress, bool initialize,
|
||||
bool initial_setup);
|
||||
uint32_t 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);
|
||||
uint32_t screen_connect(void);
|
||||
uint32_t screen_fwinfo(const char* fingerprint);
|
||||
uint32_t screen_fatal_error(const char* msg, const char* file);
|
||||
uint32_t screen_error_shutdown(const char* label, const char* msg);
|
||||
uint32_t screen_wipe_success(void);
|
||||
uint32_t 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_boot_empty(void);
|
||||
|
@ -1,12 +1,11 @@
|
||||
use core::{
|
||||
convert::{Infallible, TryInto},
|
||||
num::TryFromIntError,
|
||||
};
|
||||
|
||||
use cstr_core::CStr;
|
||||
use core::{convert::Infallible, num::TryFromIntError};
|
||||
|
||||
#[cfg(feature = "micropython")]
|
||||
use crate::micropython::{ffi, obj::Obj, qstr::Qstr};
|
||||
use {
|
||||
crate::micropython::{ffi, obj::Obj, qstr::Qstr},
|
||||
core::convert::TryInto,
|
||||
cstr_core::CStr,
|
||||
};
|
||||
|
||||
#[allow(clippy::enum_variant_names)] // We mimic the Python exception classnames here.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
@ -200,7 +200,7 @@ pub fn toif_info(data: &[u8]) -> Option<(Offset, ToifFormat)> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Aborts if the TOIF file does not have the correct grayscale flag, do not use
|
||||
/// Aborts if the TOIF file does not have the correct format, do not use
|
||||
/// with user-supplied inputs.
|
||||
fn toif_info_ensure(data: &[u8], format: ToifFormat) -> (Offset, &[u8]) {
|
||||
let info = unwrap!(display::toif_info(data), "Invalid TOIF data");
|
||||
@ -951,6 +951,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());
|
||||
|
@ -352,6 +352,15 @@ impl Rect {
|
||||
self.inset(Insets::uniform(size))
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
/// Leave just the left side of a certain `width`.
|
||||
pub const fn cut_from_left(&self, width: i16) -> Self {
|
||||
Self {
|
||||
|
123
core/embed/rust/src/ui/model_tt/bootloader/confirm.rs
Normal file
123
core/embed/rust/src/ui/model_tt/bootloader/confirm.rs
Normal file
@ -0,0 +1,123 @@
|
||||
use crate::ui::{
|
||||
component::{text::paragraphs::Paragraphs, Child, Component, Event, EventCtx, Pad},
|
||||
constant::screen,
|
||||
display,
|
||||
display::Color,
|
||||
geometry::{Offset, Point, Rect},
|
||||
model_tt::{
|
||||
component::{Button, ButtonMsg::Clicked},
|
||||
constant::{HEIGHT, WIDTH},
|
||||
theme::WHITE,
|
||||
},
|
||||
};
|
||||
|
||||
use super::ReturnToC;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ConfirmMsg {
|
||||
Cancel = 1,
|
||||
Confirm = 2,
|
||||
}
|
||||
|
||||
impl ReturnToC for ConfirmMsg {
|
||||
fn return_to_c(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Confirm {
|
||||
bg: Pad,
|
||||
bg_color: Color,
|
||||
icon: Option<&'static [u8]>,
|
||||
message: Child<Paragraphs<&'static str>>,
|
||||
left: Child<Button<&'static str>>,
|
||||
right: Child<Button<&'static str>>,
|
||||
confirm_left: bool,
|
||||
}
|
||||
|
||||
impl Confirm {
|
||||
pub fn new(
|
||||
bg_color: Color,
|
||||
icon: Option<&'static [u8]>,
|
||||
message: Paragraphs<&'static str>,
|
||||
left: Button<&'static str>,
|
||||
right: Button<&'static str>,
|
||||
confirm_left: bool,
|
||||
) -> Self {
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(bg_color),
|
||||
bg_color,
|
||||
icon,
|
||||
message: Child::new(message),
|
||||
left: Child::new(left),
|
||||
right: Child::new(right),
|
||||
confirm_left,
|
||||
};
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Confirm {
|
||||
type Msg = ConfirmMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg
|
||||
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
|
||||
self.message.place(Rect::new(
|
||||
Point::new(15, 59),
|
||||
Point::new(WIDTH - 15, HEIGHT - 64),
|
||||
));
|
||||
|
||||
let button_size = Offset::new(102, 48);
|
||||
self.left.place(Rect::from_top_left_and_size(
|
||||
Point::new(15, 176),
|
||||
button_size,
|
||||
));
|
||||
self.right.place(Rect::from_top_left_and_size(
|
||||
Point::new(123, 176),
|
||||
button_size,
|
||||
));
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
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();
|
||||
|
||||
if let Some(icon) = self.icon {
|
||||
display::icon(
|
||||
Point::new(screen().center().x, 45),
|
||||
icon,
|
||||
WHITE,
|
||||
self.bg_color,
|
||||
);
|
||||
}
|
||||
|
||||
self.message.paint();
|
||||
self.left.paint();
|
||||
self.right.paint();
|
||||
}
|
||||
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
self.left.bounds(sink);
|
||||
self.right.bounds(sink);
|
||||
}
|
||||
}
|
55
core/embed/rust/src/ui/model_tt/bootloader/connect.rs
Normal file
55
core/embed/rust/src/ui/model_tt/bootloader/connect.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
constant::screen,
|
||||
display::{self, Font},
|
||||
geometry::{Offset, Point, Rect},
|
||||
model_tt::bootloader::theme::{BLD_BG, BLD_TITLE_COLOR},
|
||||
};
|
||||
|
||||
use crate::ui::model_tt::constant::{HEIGHT, WIDTH};
|
||||
|
||||
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(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
|
||||
}
|
78
core/embed/rust/src/ui/model_tt/bootloader/fwinfo.rs
Normal file
78
core/embed/rust/src/ui/model_tt/bootloader/fwinfo.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use crate::ui::{
|
||||
component::{Child, Component, Event, EventCtx, Pad},
|
||||
display::{self, Font},
|
||||
geometry::{Point, Rect},
|
||||
model_tt::{
|
||||
bootloader::theme::{button_bld_menu_item, BLD_BG, BLD_FG, BLD_TITLE_COLOR},
|
||||
component::{Button, ButtonMsg::Clicked},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::ui::model_tt::constant::{HEIGHT, WIDTH};
|
||||
|
||||
pub struct FwInfo {
|
||||
bg: Pad,
|
||||
message: &'static str,
|
||||
fingerprint: &'static str,
|
||||
exit: Child<Button<&'static str>>,
|
||||
}
|
||||
|
||||
impl FwInfo {
|
||||
pub fn new(fingerprint: &'static str) -> Self {
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
message: "FIRMWARE FINGERPRINT",
|
||||
fingerprint,
|
||||
exit: Child::new(Button::with_text("Return to menu").styled(button_bld_menu_item())),
|
||||
};
|
||||
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for FwInfo {
|
||||
type Msg = ();
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg
|
||||
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
|
||||
self.exit.place(Rect::new(
|
||||
Point::new(16, 178),
|
||||
Point::new(16 + 209, 178 + 48),
|
||||
));
|
||||
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
if let Some(Clicked) = self.exit.event(ctx, event) {
|
||||
return Some(());
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.exit.paint();
|
||||
display::rect_fill(
|
||||
Rect::new(Point::new(16, 44), Point::new(WIDTH - 12, 45)),
|
||||
BLD_FG,
|
||||
);
|
||||
display::text_top_left(
|
||||
Point::new(15, 24),
|
||||
self.message,
|
||||
Font::BOLD,
|
||||
BLD_TITLE_COLOR,
|
||||
BLD_BG,
|
||||
);
|
||||
for i in 0..4usize {
|
||||
let ypos = (60 + i * 20) as i16;
|
||||
let idx = i * 16;
|
||||
let part = self.fingerprint.get(idx..idx + 16).unwrap_or("");
|
||||
display::text_top_left(Point::new(15, ypos), part, Font::MEDIUM, BLD_FG, BLD_BG);
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
|
||||
}
|
105
core/embed/rust/src/ui/model_tt/bootloader/intro.rs
Normal file
105
core/embed/rust/src/ui/model_tt/bootloader/intro.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use crate::ui::{
|
||||
component::{text::paragraphs::Paragraphs, Child, Component, Event, EventCtx, Pad},
|
||||
geometry::{Insets, LinearPlacement, Point, Rect},
|
||||
model_tt::{
|
||||
bootloader::{
|
||||
theme::{button_bld_menu, button_bld_menu_item, BLD_BG, MENU, TEXT_NORMAL},
|
||||
title::Title,
|
||||
ReturnToC,
|
||||
},
|
||||
component::ButtonMsg::Clicked,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::ui::model_tt::{
|
||||
component::Button,
|
||||
constant::{HEIGHT, WIDTH},
|
||||
};
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum IntroMsg {
|
||||
Menu = 1,
|
||||
Host = 2,
|
||||
}
|
||||
impl ReturnToC for IntroMsg {
|
||||
fn return_to_c(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Intro {
|
||||
bg: Pad,
|
||||
title: Child<Title>,
|
||||
menu: Child<Button<&'static str>>,
|
||||
host: Child<Button<&'static str>>,
|
||||
text: Child<Paragraphs<&'static str>>,
|
||||
}
|
||||
|
||||
impl Intro {
|
||||
pub fn new(bld_version: &'static str, vendor: &'static str, version: &'static str) -> Self {
|
||||
let p1 = Paragraphs::new()
|
||||
.add(TEXT_NORMAL, version)
|
||||
.add(TEXT_NORMAL, vendor)
|
||||
.with_placement(LinearPlacement::vertical().align_at_start());
|
||||
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
title: Child::new(Title::new(bld_version)),
|
||||
menu: Child::new(
|
||||
Button::with_icon(MENU)
|
||||
.styled(button_bld_menu())
|
||||
.with_expanded_touch_area(Insets::uniform(13)),
|
||||
),
|
||||
host: Child::new(Button::with_text("CONNECT TO HOST").styled(button_bld_menu_item())),
|
||||
text: Child::new(p1),
|
||||
};
|
||||
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Intro {
|
||||
type Msg = IntroMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg
|
||||
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
|
||||
self.title
|
||||
.place(Rect::new(Point::new(15, 24), Point::new(180, 40)));
|
||||
self.menu.place(Rect::new(
|
||||
Point::new(187, 15),
|
||||
Point::new(187 + 38, 15 + 38),
|
||||
));
|
||||
self.host.place(Rect::new(
|
||||
Point::new(16, 178),
|
||||
Point::new(16 + 209, 178 + 48),
|
||||
));
|
||||
self.text
|
||||
.place(Rect::new(Point::new(15, 75), Point::new(225, 200)));
|
||||
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);
|
||||
}
|
||||
}
|
109
core/embed/rust/src/ui/model_tt/bootloader/menu.rs
Normal file
109
core/embed/rust/src/ui/model_tt/bootloader/menu.rs
Normal file
@ -0,0 +1,109 @@
|
||||
use crate::ui::{
|
||||
component::{Child, Component, Event, EventCtx, Pad},
|
||||
geometry::{Insets, Point, Rect},
|
||||
model_tt::{
|
||||
bootloader::{
|
||||
theme::{button_bld_menu, button_bld_menu_item, BLD_BG, CLOSE, ERASE, REBOOT},
|
||||
title::Title,
|
||||
ReturnToC,
|
||||
},
|
||||
component::{Button, ButtonMsg::Clicked, IconText},
|
||||
constant::{HEIGHT, WIDTH},
|
||||
},
|
||||
};
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum MenuMsg {
|
||||
Close = 1,
|
||||
Reboot = 2,
|
||||
FactoryReset = 3,
|
||||
}
|
||||
impl ReturnToC for MenuMsg {
|
||||
fn return_to_c(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Menu {
|
||||
bg: Pad,
|
||||
title: Child<Title>,
|
||||
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", REBOOT);
|
||||
let content_reset = IconText::new("FACTORY RESET", ERASE);
|
||||
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
title: Child::new(Title::new(bld_version)),
|
||||
close: Child::new(
|
||||
Button::with_icon(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(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
|
||||
self.title
|
||||
.place(Rect::new(Point::new(15, 24), Point::new(180, 40)));
|
||||
self.close.place(Rect::new(
|
||||
Point::new(187, 15),
|
||||
Point::new(187 + 38, 15 + 38),
|
||||
));
|
||||
self.reboot
|
||||
.place(Rect::new(Point::new(16, 66), Point::new(16 + 209, 66 + 48)));
|
||||
self.reset.place(Rect::new(
|
||||
Point::new(16, 122),
|
||||
Point::new(16 + 209, 122 + 48),
|
||||
));
|
||||
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);
|
||||
}
|
||||
}
|
421
core/embed/rust/src/ui/model_tt/bootloader/mod.rs
Normal file
421
core/embed/rust/src/ui/model_tt/bootloader/mod.rs
Normal file
@ -0,0 +1,421 @@
|
||||
use crate::{
|
||||
trezorhal::io::{io_touch_read, io_touch_unpack_x, io_touch_unpack_y},
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display::{self, Font},
|
||||
event::TouchEvent,
|
||||
geometry::Point,
|
||||
model_tt::constant,
|
||||
},
|
||||
};
|
||||
|
||||
pub mod confirm;
|
||||
mod connect;
|
||||
mod fwinfo;
|
||||
pub mod intro;
|
||||
pub mod menu;
|
||||
mod theme;
|
||||
mod title;
|
||||
|
||||
use crate::ui::{
|
||||
component::text::paragraphs::Paragraphs,
|
||||
display::Color,
|
||||
geometry::LinearPlacement,
|
||||
model_tt::{
|
||||
bootloader::{
|
||||
connect::Connect,
|
||||
theme::{
|
||||
button_install_cancel, button_install_confirm, button_wipe_cancel,
|
||||
button_wipe_confirm, BLD_BG, BLD_COLOR_INITIAL_INSTALL_BG,
|
||||
BLD_COLOR_INITIAL_INSTALL_SUCCESS, BLD_FG, BLD_WIPE_COLOR, ERASE_BIG, LOGO_EMPTY,
|
||||
RECEIVE,
|
||||
},
|
||||
},
|
||||
component::{Button, ResultScreen},
|
||||
theme::{
|
||||
BACKLIGHT_DIM, BACKLIGHT_NORMAL, BLACK, ICON_SUCCESS_SMALL, ICON_WARN_SMALL,
|
||||
TEXT_ERROR_BOLD, TEXT_ERROR_NORMAL, WHITE,
|
||||
},
|
||||
},
|
||||
util::{from_c_array, from_c_str},
|
||||
};
|
||||
use confirm::Confirm;
|
||||
use fwinfo::FwInfo;
|
||||
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 ReturnToC for () {
|
||||
fn return_to_c(self) -> u32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
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));
|
||||
|
||||
frame.paint();
|
||||
if let Some(message) = msg {
|
||||
return message.return_to_c();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn touch_eval() -> Option<TouchEvent> {
|
||||
let event = io_touch_read();
|
||||
if event == 0 {
|
||||
return None;
|
||||
}
|
||||
let event_type = event >> 24;
|
||||
let x = io_touch_unpack_x(event) as u32;
|
||||
let y = io_touch_unpack_y(event) as u32;
|
||||
TouchEvent::new(event_type, x, y).ok()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_confirm(
|
||||
vendor_str: *const cty::c_char,
|
||||
vendor_str_len: u8,
|
||||
version: *const cty::c_char,
|
||||
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) });
|
||||
|
||||
const ICON: Option<&'static [u8]> = Some(RECEIVE);
|
||||
|
||||
let msg = if downgrade {
|
||||
"Downgrade firmware by"
|
||||
} else if vendor {
|
||||
"Change vendor to"
|
||||
} else {
|
||||
"Update firmware by"
|
||||
};
|
||||
|
||||
let mut message = Paragraphs::new()
|
||||
.add(theme::TEXT_NORMAL, msg)
|
||||
.centered()
|
||||
.add(theme::TEXT_NORMAL, text)
|
||||
.centered()
|
||||
.add(theme::TEXT_NORMAL, version)
|
||||
.centered();
|
||||
|
||||
if vendor || downgrade {
|
||||
message = message
|
||||
.add(theme::TEXT_BOLD, "Seed will be erased!")
|
||||
.centered();
|
||||
}
|
||||
|
||||
message = message.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, ICON, message, left, right, false);
|
||||
|
||||
run(&mut frame)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_confirm() -> u32 {
|
||||
const ICON: Option<&'static [u8]> = Some(ERASE_BIG);
|
||||
|
||||
let message = Paragraphs::new()
|
||||
.add(TEXT_ERROR_NORMAL, "Do you really want to wipe the device?")
|
||||
.centered()
|
||||
.add(TEXT_ERROR_BOLD, "Seed will be erased!")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let left = Button::with_text("WIPE").styled(button_wipe_confirm());
|
||||
let right = Button::with_text("CANCEL").styled(button_wipe_cancel());
|
||||
|
||||
let mut frame = Confirm::new(BLD_WIPE_COLOR, ICON, message, left, right, true);
|
||||
|
||||
run(&mut frame)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_menu(bld_version: *const cty::c_char) -> u32 {
|
||||
let bld_version = unwrap!(unsafe { from_c_str(bld_version) });
|
||||
|
||||
run(&mut Menu::new(bld_version))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_intro(
|
||||
bld_version: *const cty::c_char,
|
||||
vendor_str: *const cty::c_char,
|
||||
vendor_str_len: u8,
|
||||
version: *const cty::c_char,
|
||||
) -> u32 {
|
||||
display::set_backlight(0);
|
||||
let vendor = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) });
|
||||
let version = unwrap!(unsafe { from_c_str(version) });
|
||||
let bld_version = unwrap!(unsafe { from_c_str(bld_version) });
|
||||
|
||||
run(&mut Intro::new(bld_version, vendor, version))
|
||||
}
|
||||
|
||||
fn screen_progress(
|
||||
text: &str,
|
||||
progress: u16,
|
||||
initialize: bool,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(&[u8], Color)>,
|
||||
) -> u32 {
|
||||
if initialize {
|
||||
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);
|
||||
0
|
||||
}
|
||||
|
||||
const INITIAL_INSTALL_LOADER_COLOR: Color = Color::rgb(0x4A, 0x90, 0xE2);
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_progress(progress: u16, initialize: bool, initial_setup: bool) -> u32 {
|
||||
let bg_color = if initial_setup { WHITE } else { BLD_BG };
|
||||
let icon_color = if initial_setup { BLACK } else { BLD_FG };
|
||||
let fg_color = if initial_setup {
|
||||
INITIAL_INSTALL_LOADER_COLOR
|
||||
} else {
|
||||
BLD_FG
|
||||
};
|
||||
|
||||
screen_progress(
|
||||
"Installing firmware...",
|
||||
progress,
|
||||
initialize,
|
||||
fg_color,
|
||||
bg_color,
|
||||
Some((theme::RECEIVE, icon_color)),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) -> u32 {
|
||||
screen_progress(
|
||||
"Wiping device...",
|
||||
progress,
|
||||
initialize,
|
||||
theme::BLD_FG,
|
||||
BLD_WIPE_COLOR,
|
||||
Some((theme::ERASE_BIG, theme::BLD_FG)),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_connect() -> u32 {
|
||||
let mut frame = Connect::new("Waiting for host...");
|
||||
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
fadein();
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_fwinfo(fingerprint: *const cty::c_char) -> u32 {
|
||||
let fingerprint = unwrap!(unsafe { from_c_str(fingerprint) });
|
||||
|
||||
run(&mut FwInfo::new(fingerprint))
|
||||
}
|
||||
//
|
||||
// fn screen_result(message_top: &'static str, message_bottom: &'static str,
|
||||
// icon: &'static [u8], bg: Color) -> u32 {
|
||||
//
|
||||
// let m_top = Paragraphs::new()
|
||||
// .add(
|
||||
// theme::TEXT_BOLD,message_top,
|
||||
// ).centered()
|
||||
// .with_placement(LinearPlacement::vertical().align_at_center());
|
||||
//
|
||||
// let m_bottom = Paragraphs::new()
|
||||
// .add(
|
||||
// theme::TEXT_SUBMSG,message_bottom,
|
||||
// ).centered()
|
||||
// .with_placement(LinearPlacement::vertical().align_at_center());
|
||||
//
|
||||
// let mut frame = Result::new(bg, icon, m_top, m_bottom);
|
||||
// frame.place(constant::screen());
|
||||
// frame.paint();
|
||||
// 0
|
||||
// }
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_success() -> u32 {
|
||||
let m_top = Paragraphs::new()
|
||||
.add(theme::TEXT_BOLD, "Device wiped")
|
||||
.centered()
|
||||
.add(theme::TEXT_BOLD, "successfully.")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let m_bottom = Paragraphs::new()
|
||||
.add(theme::TEXT_SUBMSG, "PLEASE RECONNECT")
|
||||
.centered()
|
||||
.add(theme::TEXT_SUBMSG, "THE DEVICE")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(WHITE, BLD_BG, ICON_SUCCESS_SMALL, m_top, m_bottom, true);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_fail() -> u32 {
|
||||
let m_top = Paragraphs::new()
|
||||
.add(theme::TEXT_BOLD, "Device wipe was")
|
||||
.centered()
|
||||
.add(theme::TEXT_BOLD, "not successful.")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let m_bottom = Paragraphs::new()
|
||||
.add(theme::TEXT_SUBMSG, "PLEASE RECONNECT")
|
||||
.centered()
|
||||
.add(theme::TEXT_SUBMSG, "THE DEVICE")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(WHITE, BLD_BG, ICON_WARN_SMALL, m_top, m_bottom, true);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_boot_empty() {
|
||||
display::icon(constant::screen().center(), LOGO_EMPTY, WHITE, BLACK);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_fail() -> u32 {
|
||||
let m_top = Paragraphs::new()
|
||||
.add(theme::TEXT_BOLD, "Firmware installation was")
|
||||
.centered()
|
||||
.add(theme::TEXT_BOLD, "not successful.")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let m_bottom = Paragraphs::new()
|
||||
.add(theme::TEXT_SUBMSG, "PLEASE RECONNECT")
|
||||
.centered()
|
||||
.add(theme::TEXT_SUBMSG, "THE DEVICE")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(WHITE, BLD_BG, ICON_WARN_SMALL, m_top, m_bottom, true);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
0
|
||||
}
|
||||
|
||||
fn screen_install_success_bld(msg: &'static str, complete_draw: bool) -> u32 {
|
||||
let m_top = Paragraphs::new()
|
||||
.add(theme::TEXT_BOLD, "Firmware installed")
|
||||
.centered()
|
||||
.add(theme::TEXT_BOLD, "successfully.")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let m_bottom = Paragraphs::new()
|
||||
.add(theme::TEXT_SUBMSG, msg)
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
BLD_BG,
|
||||
ICON_SUCCESS_SMALL,
|
||||
m_top,
|
||||
m_bottom,
|
||||
complete_draw,
|
||||
);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
0
|
||||
}
|
||||
|
||||
fn screen_install_success_initial(msg: &'static str, complete_draw: bool) -> u32 {
|
||||
let m_top = Paragraphs::new()
|
||||
.add(theme::TEXT_INITIAL_INSTALL_SUCCESS, "Firmware installed")
|
||||
.centered()
|
||||
.add(theme::TEXT_INITIAL_INSTALL_SUCCESS, "successfully.")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let m_bottom = Paragraphs::new()
|
||||
.add(theme::TEXT_INITIAL_INSTALL_SUCCESS, msg)
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
BLD_COLOR_INITIAL_INSTALL_SUCCESS,
|
||||
BLD_COLOR_INITIAL_INSTALL_BG,
|
||||
ICON_SUCCESS_SMALL,
|
||||
m_top,
|
||||
m_bottom,
|
||||
complete_draw,
|
||||
);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_success(
|
||||
reboot_msg: *const cty::c_char,
|
||||
initial_setup: bool,
|
||||
complete_draw: bool,
|
||||
) -> u32 {
|
||||
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)
|
||||
}
|
||||
}
|
255
core/embed/rust/src/ui/model_tt/bootloader/theme.rs
Normal file
255
core/embed/rust/src/ui/model_tt/bootloader/theme.rs
Normal file
@ -0,0 +1,255 @@
|
||||
use crate::{
|
||||
alpha,
|
||||
ui::{
|
||||
component::text::TextStyle,
|
||||
display::{Color, Font},
|
||||
model_tt::{
|
||||
component::{ButtonStyle, ButtonStyleSheet},
|
||||
theme::{FG, GREY_DARK, GREY_LIGHT, 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_BTN_COLOR: Color = Color::alpha(BLD_WIPE_COLOR, alpha!(0.3));
|
||||
pub const BLD_WIPE_BTN_COLOR_ACTIVE: Color = Color::alpha(BLD_WIPE_COLOR, alpha!(0.15));
|
||||
pub const BLD_COLOR_SUBMSG: Color = Color::rgb(0x80, 0x8B, 0xD1);
|
||||
pub const BLD_COLOR_INITIAL_INSTALL_SUCCESS: Color = Color::rgb(0x39, 0xA8, 0x14);
|
||||
pub const BLD_COLOR_INITIAL_INSTALL_BG: Color = Color::rgb(0xDE, 0xDE, 0xDE);
|
||||
|
||||
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));
|
||||
|
||||
// Commonly used corner radius (i.e. for buttons).
|
||||
pub const RADIUS: u8 = 2;
|
||||
|
||||
// Size of icons in the UI (i.e. inside buttons).
|
||||
pub const ICON_SIZE: i32 = 16;
|
||||
|
||||
// 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 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_BTN_MENU_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: WHITE,
|
||||
button_color: BLD_BTN_MENU_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: WHITE,
|
||||
button_color: BLD_WIPE_BTN_COLOR,
|
||||
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_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
|
||||
pub const TEXT_BOLD: TextStyle = TextStyle::new(Font::BOLD, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
|
||||
pub const TEXT_SUBMSG: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
BLD_COLOR_SUBMSG,
|
||||
BLD_BG,
|
||||
BLD_COLOR_SUBMSG,
|
||||
BLD_COLOR_SUBMSG,
|
||||
);
|
||||
pub const TEXT_INITIAL_INSTALL_SUCCESS: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
BLD_COLOR_INITIAL_INSTALL_SUCCESS,
|
||||
BLD_COLOR_INITIAL_INSTALL_BG,
|
||||
BLD_COLOR_INITIAL_INSTALL_SUCCESS,
|
||||
BLD_COLOR_INITIAL_INSTALL_SUCCESS,
|
||||
);
|
52
core/embed/rust/src/ui/model_tt/bootloader/title.rs
Normal file
52
core/embed/rust/src/ui/model_tt/bootloader/title.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display::{self, Font},
|
||||
geometry::{Point, Rect},
|
||||
model_tt::bootloader::theme::{BLD_BG, BLD_TITLE_COLOR},
|
||||
};
|
||||
|
||||
pub struct Title {
|
||||
version: &'static str,
|
||||
area: Rect,
|
||||
}
|
||||
|
||||
impl Title {
|
||||
pub fn new(version: &'static str) -> Self {
|
||||
Self {
|
||||
version,
|
||||
area: Rect::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Title {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
display::text_top_left(
|
||||
self.area.top_left(),
|
||||
"BOOTLOADER",
|
||||
Font::BOLD,
|
||||
BLD_TITLE_COLOR,
|
||||
BLD_BG,
|
||||
);
|
||||
display::text_top_left(
|
||||
Point::new(self.area.top_left().x + 115, self.area.top_left().y),
|
||||
self.version,
|
||||
Font::BOLD,
|
||||
BLD_TITLE_COLOR,
|
||||
BLD_BG,
|
||||
);
|
||||
}
|
||||
|
||||
fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
|
||||
}
|
@ -6,7 +6,7 @@ use crate::{
|
||||
},
|
||||
display::{self, Color, Font},
|
||||
event::TouchEvent,
|
||||
geometry::{Insets, Offset, Rect},
|
||||
geometry::{Insets, Offset, Point, Rect},
|
||||
},
|
||||
};
|
||||
|
||||
@ -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,
|
||||
@ -52,6 +54,10 @@ impl<T> Button<T> {
|
||||
Self::new(ButtonContent::Icon(image))
|
||||
}
|
||||
|
||||
pub fn with_icon_and_text(content: IconText) -> Self {
|
||||
Self::new(ButtonContent::IconAndText(content))
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
Self::new(ButtonContent::Empty)
|
||||
}
|
||||
@ -61,6 +67,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
|
||||
@ -196,6 +207,9 @@ impl<T> Button<T> {
|
||||
style.button_color,
|
||||
);
|
||||
}
|
||||
ButtonContent::IconAndText(child) => {
|
||||
child.paint(self.area, self.style(), Self::BASELINE_OFFSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -212,6 +226,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 {
|
||||
@ -220,7 +240,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));
|
||||
@ -232,12 +252,12 @@ where
|
||||
}
|
||||
Event::Touch(TouchEvent::TouchMove(pos)) => {
|
||||
match self.state {
|
||||
State::Released if self.area.contains(pos) => {
|
||||
State::Released if touch_area.contains(pos) => {
|
||||
// Touch entered our area, transform to `Pressed` state.
|
||||
self.set(ctx, State::Pressed);
|
||||
return Some(ButtonMsg::Pressed);
|
||||
}
|
||||
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);
|
||||
@ -252,7 +272,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);
|
||||
@ -300,6 +320,7 @@ where
|
||||
ButtonContent::Empty => {}
|
||||
ButtonContent::Text(text) => t.field("text", text),
|
||||
ButtonContent::Icon(_) => t.symbol("icon"),
|
||||
ButtonContent::IconAndText(_) => {}
|
||||
}
|
||||
t.close();
|
||||
}
|
||||
@ -318,6 +339,7 @@ pub enum ButtonContent<T> {
|
||||
Empty,
|
||||
Text(T),
|
||||
Icon(&'static [u8]),
|
||||
IconAndText(IconText),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
@ -517,3 +539,55 @@ pub enum CancelInfoConfirmMsg {
|
||||
pub enum SelectWordMsg {
|
||||
Selected(usize),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct IconText {
|
||||
text: &'static str,
|
||||
icon: &'static [u8],
|
||||
}
|
||||
|
||||
impl IconText {
|
||||
pub fn new(text: &'static str, icon: &'static [u8]) -> Self {
|
||||
Self { text, icon }
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
let mut use_icon = false;
|
||||
let mut use_text = false;
|
||||
|
||||
let mut icon_pos = Point::new(area.top_left().x + 25, area.center().y);
|
||||
let mut text_pos =
|
||||
area.center() + Offset::new(-width / 2, height / 2) + Offset::y(baseline_offset);
|
||||
|
||||
if area.width() > (46 + 10 + 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 + 46, start_of_baseline.y);
|
||||
use_text = true;
|
||||
use_icon = true;
|
||||
} else if area.width() > (width + 10) {
|
||||
use_text = true;
|
||||
} else {
|
||||
//if we can't fit the text, retreat to centering the icon
|
||||
icon_pos = area.center();
|
||||
use_icon = true;
|
||||
}
|
||||
|
||||
if use_text {
|
||||
display::text(
|
||||
text_pos,
|
||||
self.text,
|
||||
style.font,
|
||||
style.text_color,
|
||||
style.button_color,
|
||||
);
|
||||
}
|
||||
|
||||
if use_icon {
|
||||
display::icon(icon_pos, self.icon, style.text_color, style.button_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,13 @@ mod keyboard;
|
||||
mod loader;
|
||||
mod number_input;
|
||||
mod page;
|
||||
mod result;
|
||||
mod scroll;
|
||||
mod swipe;
|
||||
|
||||
pub use button::{
|
||||
Button, ButtonContent, ButtonMsg, ButtonStyle, ButtonStyleSheet, CancelConfirmMsg,
|
||||
CancelInfoConfirmMsg, SelectWordMsg,
|
||||
CancelInfoConfirmMsg, IconText, SelectWordMsg,
|
||||
};
|
||||
pub use dialog::{Dialog, DialogMsg, IconDialog};
|
||||
pub use frame::{Frame, NotificationFrame};
|
||||
@ -27,6 +28,7 @@ pub use keyboard::{
|
||||
pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
|
||||
pub use number_input::{NumberInputDialog, NumberInputDialogMsg};
|
||||
pub use page::{SwipeHoldPage, SwipePage};
|
||||
pub use result::ResultScreen;
|
||||
pub use scroll::ScrollBar;
|
||||
pub use swipe::{Swipe, SwipeDirection};
|
||||
|
||||
|
92
core/embed/rust/src/ui/model_tt/component/result.rs
Normal file
92
core/embed/rust/src/ui/model_tt/component/result.rs
Normal file
@ -0,0 +1,92 @@
|
||||
use crate::{
|
||||
alpha,
|
||||
ui::{
|
||||
component::{text::paragraphs::Paragraphs, Child, Component, Event, EventCtx, Never, Pad},
|
||||
constant::screen,
|
||||
display::{self, Color},
|
||||
geometry::{Offset, Point, Rect},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::ui::model_tt::constant::{HEIGHT, WIDTH};
|
||||
|
||||
pub struct ResultScreen {
|
||||
bg: Pad,
|
||||
small_pad: Pad,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: &'static [u8],
|
||||
message_top: Child<Paragraphs<&'static str>>,
|
||||
message_bottom: Child<Paragraphs<&'static str>>,
|
||||
}
|
||||
|
||||
impl ResultScreen {
|
||||
pub fn new(
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: &'static [u8],
|
||||
message_top: Paragraphs<&'static str>,
|
||||
message_bottom: Paragraphs<&'static str>,
|
||||
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 Component for ResultScreen {
|
||||
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();
|
||||
|
||||
display::icon(
|
||||
Point::new(screen().center().x, 45),
|
||||
self.icon,
|
||||
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();
|
||||
}
|
||||
|
||||
fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
|
||||
}
|
@ -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/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.
76
core/embed/rust/src/ui/model_tt/screens.rs
Normal file
76
core/embed/rust/src/ui/model_tt/screens.rs
Normal file
@ -0,0 +1,76 @@
|
||||
use crate::ui::{
|
||||
component::{text::paragraphs::Paragraphs, Component},
|
||||
geometry::LinearPlacement,
|
||||
model_tt::{
|
||||
component::ResultScreen,
|
||||
constant,
|
||||
theme::{ERROR_COLOR, ICON_WARN_SMALL, TEXT_ERROR_BOLD, TEXT_ERROR_NORMAL, WHITE},
|
||||
},
|
||||
util::from_c_str,
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_fatal_error(msg: *const cty::c_char, file: *const cty::c_char) -> u32 {
|
||||
let m_top = if msg.is_null() {
|
||||
Paragraphs::new()
|
||||
.add(TEXT_ERROR_BOLD, "FATAL ERROR!")
|
||||
.centered()
|
||||
// .add(theme::TEXT_WIPE_NORMAL, unwrap!(unsafe { from_c_str(expr) }))
|
||||
// .centered()
|
||||
.add(TEXT_ERROR_NORMAL, unwrap!(unsafe { from_c_str(file) }))
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center())
|
||||
} else {
|
||||
let msg = unwrap!(unsafe { from_c_str(msg) });
|
||||
Paragraphs::new()
|
||||
.add(TEXT_ERROR_BOLD, "FATAL ERROR!")
|
||||
.centered()
|
||||
.add(TEXT_ERROR_NORMAL, msg)
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center())
|
||||
};
|
||||
|
||||
let m_bottom = Paragraphs::new()
|
||||
.add(TEXT_ERROR_BOLD, "PLEASE CONTACT")
|
||||
.centered()
|
||||
.add(TEXT_ERROR_BOLD, "TREZOR SUPPORT")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(WHITE, ERROR_COLOR, ICON_WARN_SMALL, m_top, m_bottom, true);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_error_shutdown(label: *const cty::c_char, msg: *const cty::c_char) -> u32 {
|
||||
let label = unwrap!(unsafe { from_c_str(label) });
|
||||
|
||||
let m_top = if msg.is_null() {
|
||||
Paragraphs::new()
|
||||
.add(TEXT_ERROR_BOLD, label)
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center())
|
||||
} else {
|
||||
let msg = unwrap!(unsafe { from_c_str(msg) });
|
||||
Paragraphs::new()
|
||||
.add(TEXT_ERROR_BOLD, label)
|
||||
.centered()
|
||||
.add(TEXT_ERROR_NORMAL, msg)
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center())
|
||||
};
|
||||
|
||||
let m_bottom = Paragraphs::new()
|
||||
.add(TEXT_ERROR_BOLD, "PLEASE UNPLUG")
|
||||
.centered()
|
||||
.add(TEXT_ERROR_BOLD, "THE DEVICE")
|
||||
.centered()
|
||||
.with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(WHITE, ERROR_COLOR, ICON_WARN_SMALL, m_top, m_bottom, true);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
0
|
||||
}
|
@ -35,6 +35,8 @@ pub const GREY_LIGHT: Color = Color::rgb(0xA8, 0xA8, 0xA8); // greyish
|
||||
pub const GREY_MEDIUM: Color = Color::rgb(0x64, 0x64, 0x64);
|
||||
pub const GREY_DARK: Color = Color::rgb(0x33, 0x33, 0x33); // greyer
|
||||
|
||||
pub const ERROR_COLOR: Color = Color::rgb(0xAD, 0x2B, 0x2B);
|
||||
|
||||
// Commonly used corner radius (i.e. for buttons).
|
||||
pub const RADIUS: u8 = 2;
|
||||
|
||||
@ -54,6 +56,8 @@ pub const ICON_NEXT: &[u8] = include_res!("model_tt/res/next.toif");
|
||||
pub const ICON_WARN: &[u8] = include_res!("model_tt/res/warn-icon.toif");
|
||||
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_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;
|
||||
@ -391,6 +395,10 @@ pub const TEXT_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, FG, BG, GREY_LIG
|
||||
pub const TEXT_DEMIBOLD: TextStyle = TextStyle::new(Font::DEMIBOLD, FG, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
pub const TEXT_BOLD: TextStyle = TextStyle::new(Font::BOLD, FG, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
pub const TEXT_MONO: TextStyle = TextStyle::new(Font::MONO, FG, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
pub const TEXT_ERROR_NORMAL: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, FG, ERROR_COLOR, GREY_LIGHT, GREY_LIGHT);
|
||||
pub const TEXT_ERROR_BOLD: TextStyle =
|
||||
TextStyle::new(Font::BOLD, FG, ERROR_COLOR, GREY_LIGHT, GREY_LIGHT);
|
||||
|
||||
pub const TEXT_NORMAL_OFF_WHITE: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, OFF_WHITE, BG, GREY_LIGHT, GREY_LIGHT);
|
||||
|
@ -1,5 +1,7 @@
|
||||
use heapless::String;
|
||||
|
||||
use cstr_core::CStr;
|
||||
|
||||
pub trait ResultExt {
|
||||
fn assert_if_debugging_ui(self, message: &str);
|
||||
}
|
||||
@ -33,6 +35,28 @@ pub fn u32_to_str(num: u32, buffer: &mut [u8]) -> Option<&str> {
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn from_c_str(c_str: *const cty::c_char) -> Option<&'static str> {
|
||||
unsafe {
|
||||
let bytes = CStr::from_ptr(c_str).to_bytes();
|
||||
if bytes.is_ascii() {
|
||||
Some(core::str::from_utf8_unchecked(bytes))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn from_c_array(c_str: *const cty::c_char, len: usize) -> Option<&'static 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(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -23,10 +23,14 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "display.h"
|
||||
#ifdef FANCY_FATAL_ERROR
|
||||
#include "rust_ui.h"
|
||||
#endif
|
||||
#include "flash.h"
|
||||
#include "rand.h"
|
||||
#include "supervise.h"
|
||||
|
||||
#include "mini_printf.h"
|
||||
#include "stm32f4xx_ll_utils.h"
|
||||
|
||||
#ifdef RGB16
|
||||
@ -52,6 +56,12 @@ __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, line %d", file, line);
|
||||
screen_fatal_error(msg, buf);
|
||||
#else
|
||||
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
display_printf("\nFATAL ERROR:\n");
|
||||
if (expr) {
|
||||
@ -72,51 +82,24 @@ __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(label, msg);
|
||||
#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
|
||||
@ -156,7 +139,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];
|
||||
@ -193,3 +176,13 @@ void ensure_compatible_settings(void) {
|
||||
display_set_big_endian();
|
||||
#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.");
|
||||
}
|
||||
|
@ -57,8 +57,10 @@ 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) \
|
||||
|
@ -132,7 +132,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;
|
||||
}
|
||||
}
|
||||
@ -210,7 +210,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,6 +25,9 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "display.h"
|
||||
#ifdef FANCY_FATAL_ERROR
|
||||
#include "rust_ui.h"
|
||||
#endif
|
||||
#include "memzero.h"
|
||||
|
||||
extern void main_clean_exit();
|
||||
@ -46,6 +49,12 @@ __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, line %d", file, line);
|
||||
screen_fatal_error(msg, buf);
|
||||
#else
|
||||
display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR);
|
||||
display_printf("\nFATAL ERROR:\n");
|
||||
printf("\nFATAL ERROR:\n");
|
||||
@ -74,42 +83,36 @@ __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();
|
||||
//__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) {
|
||||
#ifdef FANCY_FATAL_ERROR
|
||||
screen_error_shutdown(label, msg);
|
||||
#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 +156,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.");
|
||||
}
|
||||
|
@ -44,8 +44,9 @@ 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