WIP - integration - bootloader

cepetr/drawlib-integration
cepetr 2 months ago
parent b8a0e67e8a
commit ef54be2ef4

@ -248,6 +248,11 @@ build_bootloader_emu: ## build the unix bootloader emulator
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(BOOTLOADER_EMU_BUILD_DIR)/bootloader.elf
build_bootloader_emu_debug: ## build the unix bootloader emulator
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" TREZOR_EMULATOR_DEBUGGABLE=1 \
$(BOOTLOADER_EMU_BUILD_DIR)/bootloader.elf
build_prodtest: ## build production test firmware
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
CMAKELISTS="$(CMAKELISTS)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" $(PRODTEST_BUILD_DIR)/prodtest.bin

@ -22,8 +22,11 @@
#include TREZOR_BOARD
#include "bootui.h"
#include "colors.h"
#include "display.h"
#include "display_draw.h"
#include "display_utils.h"
#include "fonts/fonts.h"
#ifdef TREZOR_EMULATOR
#include "emulator.h"
#else
@ -69,13 +72,17 @@ static void format_ver(const char *format, uint32_t version, char *buffer,
// boot UI
#ifndef NEW_RENDERING
static uint16_t boot_background;
#endif
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) {
#ifndef NEW_RENDERING
static void ui_screen_boot_old(const vendor_header *const vhdr,
const image_header *const hdr) {
const int show_string = ((vhdr->vtrust & VTRUST_STRING) == 0);
if ((vhdr->vtrust & VTRUST_RED) == 0) {
boot_background = COLOR_BL_FAIL;
@ -127,9 +134,11 @@ void ui_screen_boot(const vendor_header *const vhdr,
display_pixeldata_dirty();
display_refresh();
}
#endif
void ui_screen_boot_wait(int wait_seconds) {
char wait_str[16];
#ifndef NEW_RENDERING
static void ui_screen_boot_wait(int wait_seconds) {
char wait_str[32];
mini_snprintf(wait_str, sizeof(wait_str), "starting in %d s", wait_seconds);
display_bar(0, BOOT_WAIT_Y_TOP, DISPLAY_RESX, BOOT_WAIT_HEIGHT,
boot_background);
@ -138,6 +147,7 @@ void ui_screen_boot_wait(int wait_seconds) {
display_pixeldata_dirty();
display_refresh();
}
#endif
#if defined USE_TOUCH
#include "touch.h"
@ -179,7 +189,8 @@ void ui_click(void) {
#error "No input method defined"
#endif
void ui_screen_boot_click(void) {
#ifndef NEW_RENDERING
static void ui_screen_boot_click(void) {
display_bar(0, BOOT_WAIT_Y_TOP, DISPLAY_RESX, BOOT_WAIT_HEIGHT,
boot_background);
bld_continue_label(boot_background);
@ -187,6 +198,33 @@ void ui_screen_boot_click(void) {
display_refresh();
ui_click();
}
#endif
#ifdef NEW_RENDERING
void ui_screen_boot(const vendor_header *const vhdr,
const image_header *const hdr, int wait) {
bool show_string = ((vhdr->vtrust & VTRUST_STRING) == 0);
const char *vendor_str = show_string ? vhdr->vstr : NULL;
const size_t vendor_str_len = show_string ? vhdr->vstr_len : 0;
bool red_screen = ((vhdr->vtrust & VTRUST_RED) == 0);
uint32_t vimg_len = *(uint32_t *)(vhdr->vimg + 8);
screen_boot(red_screen, vendor_str, vendor_str_len, hdr->version, vhdr->vimg,
vimg_len, wait);
}
#else // NEW_RENDERING
void ui_screen_boot(const vendor_header *const vhdr,
const image_header *const hdr, int wait) {
if (wait == 0) {
ui_screen_boot_old(vhdr, hdr);
} else if (wait > 0) {
ui_screen_boot_wait(wait);
} else {
ui_screen_boot_click();
}
}
#endif
// welcome UI

@ -34,10 +34,22 @@ typedef enum {
SCREEN_WELCOME = 5,
} screen_t;
// Displays a warning screeen before jumping to the untrusted firmware
//
// Shows vendor image, vendor string and firmware version
// and optional message to the user (see `wait` argument)
//
// `wait` argument specifies a message to the user
// 0 do not show any message
// > 0 show a message like "starting in %d s"
// < 0 show a message like "press button to continue"
void ui_screen_boot(const vendor_header* const vhdr,
const image_header* const hdr);
void ui_screen_boot_wait(int wait_seconds);
void ui_screen_boot_click(void);
const image_header* const hdr, int wait);
// Waits until the user confirms the untrusted firmware
//
// Implementation is device specific - it wait's until
// the user presses a button, touches the display
void ui_click(void);
void ui_screen_welcome(void);

@ -111,6 +111,7 @@ __attribute__((noreturn)) void display_error_and_die(const char *message,
}
__attribute__((noreturn)) int main(int argc, char **argv) {
display_init();
flash_init();
flash_otp_init();
@ -188,10 +189,6 @@ __attribute__((noreturn)) int main(int argc, char **argv) {
jump_to(NULL);
}
void display_set_little_endian(void) {}
void display_reinit(void) {}
void mpu_config_bootloader(void) {}
void mpu_config_off(void) {}

@ -72,7 +72,6 @@
#include "emulator.h"
#else
#include "compiler_traits.h"
#include "mini_printf.h"
#include "mpu.h"
#include "platform.h"
#endif
@ -356,13 +355,13 @@ void real_jump_to_firmware(void) {
// if all VTRUST flags are unset = ultimate trust => skip the procedure
if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) {
ui_fadeout();
ui_screen_boot(&vhdr, hdr);
ui_screen_boot(&vhdr, hdr, 0);
ui_fadein();
int delay = (vhdr.vtrust & VTRUST_WAIT) ^ VTRUST_WAIT;
if (delay > 1) {
while (delay > 0) {
ui_screen_boot_wait(delay);
ui_screen_boot(&vhdr, hdr, delay);
hal_delay(1000);
delay--;
}
@ -371,7 +370,8 @@ void real_jump_to_firmware(void) {
}
if ((vhdr.vtrust & VTRUST_CLICK) == 0) {
ui_screen_boot_click();
ui_screen_boot(&vhdr, hdr, -1);
ui_click();
}
ui_screen_boot_empty(false);

@ -67,6 +67,8 @@ SECTIONS {
.buf : ALIGN(4) {
*(.buf*);
. = ALIGN(4);
*(.no_dma_buffers*);
. = ALIGN(4);
} >SRAM
.boot_args : ALIGN(8) {

@ -24,7 +24,8 @@
#include "display.h"
#include TREZOR_BOARD
#ifndef TREZOR_PRINT_DISABLE
#include "fonts/fonts.h"
#include "gl_draw.h"
#define TERMINAL_COLS (DISPLAY_RESX / 6)
#define TERMINAL_ROWS (DISPLAY_RESY / 8)
@ -39,6 +40,62 @@ void term_set_color(uint16_t fgcolor, uint16_t bgcolor) {
terminal_bgcolor = bgcolor;
}
#ifdef NEW_RENDERING
// Font_Bitmap contains 96 (0x20 - 0x7F) 5x7 glyphs
// Each glyph consists of 5 bytes (each byte represents one column)
//
// This function converts the glyph into the format compatible
// with `display_copy_mono1p()` functions.
static uint64_t term_glyph_bits(char ch) {
union {
uint64_t u64;
uint8_t bytes[8];
} result = {0};
if (ch > ' ' && ch < 128) {
const uint8_t *b = &Font_Bitmap[(ch - ' ') * 5];
for (int y = 0; y < 7; y++) {
uint8_t mask = 1 << y;
result.bytes[y] |= ((b[0] & mask) ? 128 : 0) + ((b[1] & mask) ? 64 : 0) +
((b[2] & mask) ? 32 : 0) + ((b[3] & mask) ? 16 : 0) +
((b[4] & mask) ? 8 : 0);
}
}
return result.u64;
}
// Redraws specified rows to the display
static void term_redraw_rows(int start_row, int row_count) {
uint64_t glyph_bits = 0;
dma2d_params_t dp = {
.height = 8,
.width = 6,
.dst_row = NULL,
.dst_x = 0,
.dst_y = 0,
.dst_stride = 0,
.src_row = &glyph_bits,
.src_x = 0,
.src_y = 0,
.src_stride = 8,
.src_fg = terminal_fgcolor,
.src_bg = terminal_bgcolor,
};
for (int y = start_row; y < start_row + row_count; y++) {
dp.dst_y = y * 8;
for (int x = 0; x < TERMINAL_COLS; x++) {
glyph_bits = term_glyph_bits(terminal_fb[y][x]);
dp.dst_x = x * 6;
display_copy_mono1p(&dp);
}
}
}
#endif // NEW_RENDERING
// display text using bitmap font
void term_print(const char *text, int textlen) {
static uint8_t row = 0, col = 0;
@ -78,8 +135,9 @@ void term_print(const char *text, int textlen) {
}
#ifdef NEW_RENDERING
// TODO !@#
#else
term_redraw_rows(0, TERMINAL_ROWS);
display_refresh();
#else // NEW RENDERING
// render buffer to display
display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
@ -131,5 +189,3 @@ void term_printf(const char *fmt, ...) {
va_end(va);
}
}
#endif // TREZOR_PRINT_DISABLE

@ -22,11 +22,9 @@
#include "colors.h"
#ifndef TREZOR_PRINT_DISABLE
void term_set_color(uint16_t fgcolor, uint16_t bgcolor);
void term_print(const char *text, int textlen);
void term_printf(const char *fmt, ...)
__attribute__((__format__(__printf__, 1, 2)));
#endif
#endif // LIB_TERMINAL_H

@ -1,5 +1,6 @@
#include <stdbool.h>
#include "common.h"
#include "rust_ui_bootloader.h"
#include "rust_ui_common.h"

@ -24,3 +24,6 @@ void screen_boot_empty(bool fading);
uint32_t screen_unlock_bootloader_confirm(void);
void screen_unlock_bootloader_success(void);
void bld_continue_label(uint16_t bg_color);
void screen_boot(bool warning, const char* vendor_str, size_t vendor_str_len,
uint32_t version, const void* vendor_img,
size_t vendor_img_len, int wait);

@ -101,6 +101,24 @@ extern "C" fn screen_boot_empty(fading: bool) {
ModelUI::screen_boot_empty(fading)
}
#[no_mangle]
#[cfg(feature = "new_rendering")]
extern "C" fn screen_boot(
warning: bool,
vendor_str: *const cty::c_char,
vendor_str_len: usize,
version: u32,
vendor_img: *const cty::c_void,
vendor_img_len: usize,
wait: i32,
) {
let vendor_str = unsafe { from_c_array(vendor_str, vendor_str_len) };
let vendor_img =
unsafe { core::slice::from_raw_parts(vendor_img as *const u8, vendor_img_len) };
ModelUI::screen_boot(warning, vendor_str, version, vendor_img, wait);
}
#[no_mangle]
extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) {
ModelUI::screen_wipe_progress(progress, initialize)

@ -8,12 +8,18 @@ use crate::ui::event::ButtonEvent;
use crate::ui::event::TouchEvent;
use crate::ui::{
component::{Component, Event, EventCtx, Never},
display,
ui_features::ModelUI,
UIFeaturesCommon,
};
use num_traits::ToPrimitive;
#[cfg(not(feature = "new_rendering"))]
use crate::ui::display;
#[cfg(feature = "new_rendering")]
use crate::ui::{display::color::Color, shape::render_on_display};
pub trait ReturnToC {
fn return_to_c(self) -> u32;
}
@ -63,6 +69,25 @@ fn touch_eval() -> Option<TouchEvent> {
TouchEvent::new(event_type, ex as _, ey as _).ok()
}
fn render<F>(frame: &mut F)
where
F: Component,
{
#[cfg(not(feature = "new_rendering"))]
{
display::sync();
frame.paint();
display::refresh();
}
#[cfg(feature = "new_rendering")]
{
render_on_display(None, Some(Color::black()), |target| {
frame.render(target);
});
}
}
pub fn run<F>(frame: &mut F) -> u32
where
F: Component,
@ -70,9 +95,7 @@ where
{
frame.place(ModelUI::SCREEN);
ModelUI::fadeout();
display::sync();
frame.paint();
display::refresh();
render(frame);
ModelUI::fadein();
#[cfg(feature = "button")]
@ -93,9 +116,7 @@ where
if let Some(message) = msg {
return message.return_to_c();
}
display::sync();
frame.paint();
display::refresh();
render(frame);
}
}
}
@ -105,12 +126,13 @@ where
F: Component,
{
frame.place(ModelUI::SCREEN);
if fading {
ModelUI::fadeout()
};
display::sync();
frame.paint();
display::refresh();
render(frame);
if fading {
ModelUI::fadein()
};

@ -7,7 +7,7 @@ use crate::{
constant,
constant::{HEIGHT, SCREEN},
display::{self, Color, Font, Icon},
geometry::{Alignment2D, Offset, Point, Rect},
geometry::{Alignment2D, Offset, Point},
layout::simplified::{run, show, ReturnToC},
},
};
@ -24,6 +24,18 @@ use super::{
ModelTRFeatures,
};
#[cfg(not(feature = "new_rendering"))]
use crate::ui::geometry::Rect;
#[cfg(feature = "new_rendering")]
use crate::ui::{
display::toif::Toif, geometry::Alignment, model_tr::cshape, shape, shape::render_on_display,
util::version_split,
};
#[cfg(feature = "new_rendering")]
use ufmt::uwrite;
mod intro;
mod menu;
mod welcome;
@ -42,6 +54,7 @@ impl ReturnToC for ConfirmMsg {
}
impl ModelTRFeatures {
#[cfg(not(feature = "new_rendering"))]
fn screen_progress(
text: &str,
text2: &str,
@ -84,6 +97,46 @@ impl ModelTRFeatures {
display::refresh();
}
#[cfg(feature = "new_rendering")]
fn screen_progress(
text: &str,
text2: &str,
progress: u16,
_initialize: bool,
fg_color: Color,
bg_color: Color,
icon: Option<(Icon, Color)>,
) {
let progress = if progress < 20 { 20 } else { progress };
render_on_display(None, Some(bg_color), |target| {
let center = SCREEN.top_center() + Offset::y(12);
cshape::LoaderCircular::new(center, progress)
.with_color(fg_color)
.render(target);
if let Some((icon, color)) = icon {
shape::ToifImage::new(center, icon.toif)
.with_align(Alignment2D::CENTER)
.with_fg(color)
.render(target);
}
shape::Text::new(SCREEN.center() + Offset::y(8), text)
.with_align(Alignment::Center)
.with_font(Font::BOLD)
.with_fg(fg_color)
.render(target);
shape::Text::new(SCREEN.center() + Offset::y(20), text2)
.with_align(Alignment::Center)
.with_font(Font::BOLD)
.with_fg(fg_color)
.render(target);
});
}
}
impl UIFeaturesBootloader for ModelTRFeatures {
@ -315,4 +368,90 @@ impl UIFeaturesBootloader for ModelTRFeatures {
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_ALERT, title, content, true);
show(&mut frame, false);
}
#[cfg(feature = "new_rendering")]
fn screen_boot(
_warning: bool,
vendor_str: Option<&str>,
version: u32,
vendor_img: &[u8],
wait: i32,
) {
render_on_display(None, Some(BLD_BG), |target| {
// Draw vendor image if it's valid and has size of 24x24
if let Ok(toif) = Toif::new(vendor_img) {
if (toif.width() == 24) && (toif.height() == 24) {
let pos = Point::new((constant::WIDTH - 22) / 2, 0);
shape::ToifImage::new(pos, toif)
.with_align(Alignment2D::TOP_CENTER)
.with_fg(BLD_FG)
.render(target);
}
}
// Draw vendor string if present
if let Some(text) = vendor_str {
let pos = Point::new(constant::WIDTH / 2, 36);
shape::Text::new(pos, text)
.with_align(Alignment::Center)
.with_font(Font::NORMAL)
.with_fg(BLD_FG) //COLOR_BL_BG
.render(target);
let pos = Point::new(constant::WIDTH / 2, 46);
let mut version_text: BootloaderString = String::new();
let ver_nums = version_split(version);
unwrap!(uwrite!(
version_text,
"{}.{}.{}",
ver_nums[0],
ver_nums[1],
ver_nums[2]
));
shape::Text::new(pos, version_text.as_str())
.with_align(Alignment::Center)
.with_font(Font::NORMAL)
.with_fg(BLD_FG)
.render(target);
}
// Draw a message
match wait.cmp(&0) {
core::cmp::Ordering::Equal => {}
core::cmp::Ordering::Greater => {
let mut text: BootloaderString = String::new();
unwrap!(uwrite!(text, "starting in {} s", wait));
let pos = Point::new(constant::WIDTH / 2, HEIGHT - 5);
shape::Text::new(pos, text.as_str())
.with_align(Alignment::Center)
.with_font(Font::NORMAL)
.with_fg(BLD_FG)
.render(target);
}
core::cmp::Ordering::Less => {
let pos = Point::new(constant::WIDTH / 2, HEIGHT - 2);
shape::Text::new(pos, "CONTINUE")
.with_align(Alignment::Center)
.with_fg(BLD_FG)
.render(target);
let pos = Point::new(constant::WIDTH / 2 - 36, HEIGHT - 6);
shape::ToifImage::new(pos, ICON_ARM_LEFT.toif)
.with_align(Alignment2D::TOP_LEFT)
.with_fg(BLD_FG)
.render(target);
let pos = Point::new(constant::WIDTH / 2 + 25, HEIGHT - 6);
shape::ToifImage::new(pos, ICON_ARM_RIGHT.toif)
.with_align(Alignment2D::TOP_LEFT)
.with_fg(BLD_FG)
.render(target);
}
}
});
}
}

@ -23,12 +23,29 @@ use super::{
FIRE40, RESULT_FW_INSTALL, RESULT_INITIAL, RESULT_WIPE, TEXT_BOLD, TEXT_NORMAL,
TEXT_WIPE_BOLD, TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, X24,
},
BACKLIGHT_NORMAL, BLACK, FG, WHITE,
BACKLIGHT_NORMAL, BLACK, FG,
},
ModelTTFeatures,
};
use crate::ui::{ui_features::UIFeaturesBootloader, UIFeaturesCommon};
#[cfg(feature = "new_rendering")]
use crate::ui::{
constant,
display::toif::Toif,
geometry::{Alignment, Alignment2D, Offset},
shape,
shape::render_on_display,
util::version_split,
};
#[cfg(feature = "new_rendering")]
use ufmt::uwrite;
#[cfg(feature = "new_rendering")]
use super::theme::bootloader::BLD_WARN_COLOR;
use intro::Intro;
use menu::Menu;
@ -43,6 +60,7 @@ const RECONNECT_MESSAGE: &str = "PLEASE RECONNECT\nTHE DEVICE";
const SCREEN: Rect = ModelTTFeatures::SCREEN;
impl ModelTTFeatures {
#[cfg(not(feature = "new_rendering"))]
fn screen_progress(
text: &str,
progress: u16,
@ -70,6 +88,60 @@ impl ModelTTFeatures {
}
}
#[cfg(feature = "new_rendering")]
fn screen_progress(
text: &str,
progress: u16,
initialize: bool,
fg_color: Color,
bg_color: Color,
icon: Option<(Icon, Color)>,
) {
if initialize {
ModelTTFeatures::fadeout();
}
render_on_display(None, Some(bg_color), |target| {
shape::Text::new(Point::new(SCREEN.width() / 2, SCREEN.height() - 45), text)
.with_align(Alignment::Center)
.with_font(Font::NORMAL)
.with_fg(fg_color)
.render(target);
let center = SCREEN.center() + Offset::y(-20);
let inactive_color = bg_color.blend(fg_color, 85);
shape::Circle::new(center, constant::LOADER_OUTER)
.with_bg(inactive_color)
.render(target);
shape::Circle::new(center, constant::LOADER_OUTER)
.with_bg(fg_color)
.with_end_angle(((progress as i32 * shape::PI4 as i32 * 8) / 1000) as i16)
.render(target);
shape::Circle::new(center, constant::LOADER_INNER + 2)
.with_bg(fg_color)
.render(target);
shape::Circle::new(center, constant::LOADER_INNER)
.with_bg(bg_color)
.render(target);
if let Some((icon, color)) = icon {
shape::ToifImage::new(center, icon.toif)
.with_align(Alignment2D::CENTER)
.with_fg(color)
.render(target);
}
});
if initialize {
ModelTTFeatures::fadein();
}
}
fn screen_install_success_bld(msg: &str, complete_draw: bool) {
let mut frame = ResultScreen::new(
&RESULT_FW_INSTALL,
@ -104,7 +176,7 @@ impl UIFeaturesBootloader for ModelTTFeatures {
Point::new(SCREEN.width() / 2, SCREEN.height() - 5),
"click to continue ...",
Font::NORMAL,
WHITE,
BLD_FG,
bg_color,
);
}
@ -250,6 +322,7 @@ impl UIFeaturesBootloader for ModelTTFeatures {
ModelTTFeatures::fadeout();
}
#[cfg(not(feature = "new_rendering"))]
display::rect_fill(SCREEN, BLACK);
let mut frame = WelcomeScreen::new(true);
@ -317,4 +390,87 @@ impl UIFeaturesBootloader for ModelTTFeatures {
);
show(&mut frame, true);
}
#[cfg(feature = "new_rendering")]
fn screen_boot(
warning: bool,
vendor_str: Option<&str>,
version: u32,
vendor_img: &[u8],
wait: i32,
) {
let bg_color = if warning { BLD_WARN_COLOR } else { BLD_BG };
render_on_display(None, Some(bg_color), |target| {
// Draw vendor image if it's valid and has size of 120x120
if let Ok(toif) = Toif::new(vendor_img) {
if (toif.width() == 120) && (toif.height() == 120) {
// Image position depends on the vendor string presence
let pos = if vendor_str.is_some() {
Point::new(SCREEN.width() / 2, 30)
} else {
Point::new(SCREEN.width() / 2, 60)
};
shape::ToifImage::new(pos, toif)
.with_align(Alignment2D::TOP_CENTER)
.with_fg(BLD_FG)
.render(target);
}
}
// Draw vendor string if present
if let Some(text) = vendor_str {
let pos = Point::new(SCREEN.width() / 2, SCREEN.height() - 5 - 50);
shape::Text::new(pos, text)
.with_align(Alignment::Center)
.with_font(Font::NORMAL)
.with_fg(BLD_FG) //COLOR_BL_BG
.render(target);
let pos = Point::new(SCREEN.width() / 2, SCREEN.height() - 5 - 25);
let mut version_text: BootloaderString = String::new();
let ver_nums = version_split(version);
unwrap!(uwrite!(
version_text,
"{}.{}.{}",
ver_nums[0],
ver_nums[1],
ver_nums[2]
));
shape::Text::new(pos, version_text.as_str())
.with_align(Alignment::Center)
.with_font(Font::NORMAL)
.with_fg(BLD_FG)
.render(target);
}
// Draw a message
match wait.cmp(&0) {
core::cmp::Ordering::Equal => {}
core::cmp::Ordering::Greater => {
let mut text: BootloaderString = String::new();
unwrap!(uwrite!(text, "starting in {} s", wait));
let pos = Point::new(SCREEN.width() / 2, SCREEN.height() - 5);
shape::Text::new(pos, text.as_str())
.with_align(Alignment::Center)
.with_font(Font::NORMAL)
.with_fg(BLD_FG)
.render(target);
}
core::cmp::Ordering::Less => {
let pos = Point::new(SCREEN.width() / 2, SCREEN.height() - 5);
shape::Text::new(pos, "click to continue ...")
.with_align(Alignment::Center)
.with_font(Font::NORMAL)
.with_fg(BLD_FG)
.render(target);
}
}
});
}
}

@ -53,6 +53,15 @@ pub trait UIFeaturesBootloader {
fn screen_wipe_success();
fn screen_wipe_fail();
#[cfg(feature = "new_rendering")]
fn screen_boot(
warning: bool,
vendor_str: Option<&str>,
version: u32,
vendor_img: &[u8],
wait: i32,
);
}
#[cfg(all(feature = "model_tr", not(feature = "model_tt")))]

@ -179,6 +179,10 @@ macro_rules! include_icon {
};
}
pub fn version_split(version: u32) -> [u8; 4] {
version.to_le_bytes()
}
#[cfg(test)]
mod tests {
use crate::strutil;

@ -37,9 +37,9 @@
#include <sys/types.h>
#include <unistd.h>
#include "display.h"
#include "extmod/misc.h"
#include "extmod/vfs_posix.h"
#include "display.h"
#include "flash.h"
#include "flash_otp.h"
#include "genhdr/mpversion.h"

Loading…
Cancel
Save