mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-02-13 16:12:18 +00:00
refactor(core): render prodtest UI in rust
[no changelog]
This commit is contained in:
parent
1700841856
commit
c3981cdebe
@ -58,7 +58,7 @@ SOURCE_MOD_CRYPTO += [
|
||||
|
||||
# modtrezorui
|
||||
CPPPATH_MOD += [
|
||||
'vendor/micropython/lib/uzlib',
|
||||
'vendor/micropython/lib/uzlib'
|
||||
]
|
||||
|
||||
SOURCE_MOD += [
|
||||
@ -138,6 +138,23 @@ env.Replace(
|
||||
env.Replace(
|
||||
TREZOR_MODEL=TREZOR_MODEL, )
|
||||
|
||||
ALLPATHS = [
|
||||
'embed/rust',
|
||||
'embed/projects/prodtest',
|
||||
'embed/rtl/inc',
|
||||
'embed/models',
|
||||
'embed/gfx/inc',
|
||||
'embed/sys/bsp/inc',
|
||||
'embed/util/image/inc',
|
||||
'embed/util/rsod/inc',
|
||||
'embed/util/scm_revision/inc',
|
||||
'embed/util/translations/inc',
|
||||
'embed/upymod/modtrezorui',
|
||||
]
|
||||
|
||||
ALLPATHS += CPPPATH_MOD + PATH_HAL
|
||||
|
||||
|
||||
env.Replace(
|
||||
COPT=env.get('ENV').get('OPTIMIZE', '-Os'),
|
||||
CCFLAGS='$COPT '
|
||||
@ -149,18 +166,8 @@ env.Replace(
|
||||
'-fstack-protector-all '
|
||||
+ env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD,
|
||||
CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB',
|
||||
LINKFLAGS=f'-T build/prodtest/memory.ld -Wl,--gc-sections -Wl,--print-memory-usage -Wl,-Map=build/prodtest/prodtest.map -Wl,--warn-common',
|
||||
CPPPATH=[
|
||||
'embed/projects/prodtest',
|
||||
'embed/rtl/inc',
|
||||
'embed/models',
|
||||
'embed/gfx/inc',
|
||||
'embed/sys/bsp/inc',
|
||||
'embed/util/image/inc',
|
||||
'embed/util/rsod/inc',
|
||||
'embed/util/scm_revision/inc',
|
||||
'embed/upymod/modtrezorui',
|
||||
] + CPPPATH_MOD + PATH_HAL,
|
||||
LINKFLAGS=['-Tbuild/prodtest/memory.ld', '-Wl,--gc-sections', '-Wl,--print-memory-usage', '-Wl,-Map=build/prodtest/prodtest.map', '-Wl,--warn-common'],
|
||||
CPPPATH=ALLPATHS,
|
||||
CPPDEFINES=[
|
||||
'TREZOR_PRODTEST',
|
||||
'TREZOR_MODEL_'+TREZOR_MODEL,
|
||||
@ -197,6 +204,20 @@ obj_program.extend(env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftriv
|
||||
obj_program.extend(env.Object(source=SOURCE_PRODTEST))
|
||||
obj_program.extend(env.Object(source=SOURCE_HAL))
|
||||
|
||||
#
|
||||
# Rust library
|
||||
#
|
||||
features = ['prodtest',] + FEATURES_AVAILABLE + RUST_UI_FEATURES
|
||||
|
||||
|
||||
rust = tools.add_rust_lib(
|
||||
env,
|
||||
'prodtest',
|
||||
'release',
|
||||
features,
|
||||
ALLPATHS,
|
||||
str(Dir('.').abspath))
|
||||
|
||||
|
||||
if (vh := ARGUMENTS.get("VENDOR_HEADER", None)):
|
||||
VENDORHEADER = vh
|
||||
@ -232,10 +253,11 @@ program_elf = env.Command(
|
||||
target='prodtest.elf',
|
||||
source=obj_program,
|
||||
action=
|
||||
'$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc -lm',
|
||||
'$LINK -o $TARGET $CCFLAGS $CFLAGS $SOURCES $LINKFLAGS -lc_nano -lgcc -lm',
|
||||
)
|
||||
|
||||
env.Depends(program_elf, linkerscript_gen)
|
||||
env.Depends(program_elf, rust)
|
||||
|
||||
BINARY_NAME = f"build/prodtest/prodtest-{TREZOR_MODEL}"
|
||||
BINARY_NAME += "-" + tools.get_version('embed/projects/prodtest/version.h')
|
||||
|
@ -17,9 +17,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <rust_ui_prodtest.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <gfx/gfx_draw.h>
|
||||
#include <io/display.h>
|
||||
#include <rtl/cli.h>
|
||||
|
||||
@ -29,24 +29,14 @@ static void prodtest_display_border(cli_t* cli) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfx_clear();
|
||||
|
||||
cli_trace(cli, "Drawing display border...");
|
||||
|
||||
gfx_rect_t r_out = gfx_rect_wh(0, 0, DISPLAY_RESX, DISPLAY_RESY);
|
||||
gfx_rect_t r_in = gfx_rect_wh(1, 1, DISPLAY_RESX - 2, DISPLAY_RESY - 2);
|
||||
|
||||
gfx_draw_bar(r_out, COLOR_WHITE);
|
||||
gfx_draw_bar(r_in, COLOR_BLACK);
|
||||
|
||||
display_refresh();
|
||||
screen_prodtest_border();
|
||||
|
||||
cli_ok(cli, "");
|
||||
}
|
||||
|
||||
static void prodtest_display_bars(cli_t* cli) {
|
||||
gfx_clear();
|
||||
|
||||
const char* colors = cli_arg(cli, "colors");
|
||||
size_t color_count = strlen(colors);
|
||||
|
||||
@ -59,34 +49,13 @@ static void prodtest_display_bars(cli_t* cli) {
|
||||
|
||||
cli_trace(cli, "Drawing %d vertical bars...", color_count);
|
||||
|
||||
screen_prodtest_bars(colors, color_count);
|
||||
|
||||
for (size_t i = 0; i < color_count; i++) {
|
||||
gfx_color_t c = COLOR_BLACK; // black
|
||||
switch (colors[i]) {
|
||||
case 'R':
|
||||
case 'r':
|
||||
c = gfx_color_rgb(255, 0, 0);
|
||||
break;
|
||||
case 'G':
|
||||
case 'g':
|
||||
c = gfx_color_rgb(0, 255, 0);
|
||||
break;
|
||||
case 'B':
|
||||
case 'b':
|
||||
c = gfx_color_rgb(0, 0, 255);
|
||||
break;
|
||||
case 'W':
|
||||
case 'w':
|
||||
c = COLOR_WHITE;
|
||||
break;
|
||||
default:
|
||||
if (strchr("RGBWrgbw", colors[i]) == NULL) {
|
||||
invalid_color = true;
|
||||
break;
|
||||
}
|
||||
|
||||
int x1 = (DISPLAY_RESX * i) / color_count;
|
||||
int x2 = (DISPLAY_RESX * (i + 1)) / color_count;
|
||||
|
||||
gfx_draw_bar(gfx_rect(x1, 0, x2, DISPLAY_RESY), c);
|
||||
}
|
||||
|
||||
if (strlen(colors) == 0 || invalid_color) {
|
||||
@ -102,7 +71,7 @@ static void prodtest_display_set_backlight(cli_t* cli) {
|
||||
uint32_t level = 0;
|
||||
|
||||
if (!cli_arg_uint32(cli, "level", &level) || level > 255) {
|
||||
cli_error_arg(cli, "Expecting backlig level in range 0-255 (100%%).");
|
||||
cli_error_arg(cli, "Expecting backlight level in range 0-255 (100%%).");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -17,26 +17,15 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <rust_ui_prodtest.h>
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <gfx/fonts.h>
|
||||
#include <gfx/gfx_draw.h>
|
||||
#include <io/display.h>
|
||||
#include <rtl/cli.h>
|
||||
#include <sys/bootutils.h>
|
||||
#include <sys/mpu.h>
|
||||
#include <sys/systick.h>
|
||||
#include <util/fwutils.h>
|
||||
|
||||
#include <version.h>
|
||||
|
||||
static gfx_text_attr_t bold = {
|
||||
.font = FONT_BOLD,
|
||||
.fg_color = COLOR_WHITE,
|
||||
.bg_color = COLOR_BLACK,
|
||||
};
|
||||
|
||||
static void prodtest_prodtest_intro(cli_t* cli) {
|
||||
cli_trace(cli, "Welcome to Trezor %s Production Test Firmware v%d.%d.%d.",
|
||||
MODEL_NAME, VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
||||
@ -63,10 +52,8 @@ static void prodtest_prodtest_wipe(cli_t* cli) {
|
||||
cli_trace(cli, "Invalidating the production test firmware header...");
|
||||
firmware_invalidate_header();
|
||||
|
||||
gfx_clear();
|
||||
gfx_offset_t pos = gfx_offset(DISPLAY_RESX / 2, DISPLAY_RESY / 2 + 10);
|
||||
gfx_draw_text(pos, "WIPED", -1, &bold, GFX_ALIGN_CENTER);
|
||||
display_refresh();
|
||||
const char msg[] = "WIPED";
|
||||
screen_prodtest_show_text(msg, strlen(msg));
|
||||
|
||||
cli_ok(cli, "");
|
||||
}
|
||||
|
@ -17,23 +17,16 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <rust_ui_prodtest.h>
|
||||
#ifdef USE_TOUCH
|
||||
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <gfx/fonts.h>
|
||||
#include <gfx/gfx_draw.h>
|
||||
#include <io/display.h>
|
||||
#include <io/touch.h>
|
||||
#include <rtl/cli.h>
|
||||
#include <sys/systick.h>
|
||||
|
||||
const static gfx_text_attr_t bold = {
|
||||
.font = FONT_BOLD,
|
||||
.fg_color = COLOR_WHITE,
|
||||
.bg_color = COLOR_BLACK,
|
||||
};
|
||||
|
||||
static bool ensure_touch_init(cli_t* cli) {
|
||||
cli_trace(cli, "Initializing the touch controller...");
|
||||
if (sectrue != touch_init()) {
|
||||
@ -108,27 +101,24 @@ static void prodtest_touch_test(cli_t* cli) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int width = DISPLAY_RESX / 2;
|
||||
const int height = DISPLAY_RESY / 2;
|
||||
const int16_t width = DISPLAY_RESX / 2;
|
||||
const int16_t height = DISPLAY_RESY / 2;
|
||||
|
||||
gfx_clear();
|
||||
switch (position) {
|
||||
case 1:
|
||||
gfx_draw_bar(gfx_rect_wh(0, 0, width, height), COLOR_WHITE);
|
||||
screen_prodtest_touch(0, 0, width, height);
|
||||
break;
|
||||
case 2:
|
||||
gfx_draw_bar(gfx_rect_wh(width, 0, width, height), COLOR_WHITE);
|
||||
screen_prodtest_touch(width, 0, width, height);
|
||||
break;
|
||||
case 3:
|
||||
gfx_draw_bar(gfx_rect_wh(width, height, width, height), COLOR_WHITE);
|
||||
screen_prodtest_touch(width, height, width, height);
|
||||
break;
|
||||
default:
|
||||
gfx_draw_bar(gfx_rect_wh(0, height, width, height), COLOR_WHITE);
|
||||
screen_prodtest_touch(0, height, width, height);
|
||||
break;
|
||||
}
|
||||
|
||||
display_refresh();
|
||||
|
||||
uint32_t event = 0;
|
||||
if (touch_click_timeout(cli, &event, timeout)) {
|
||||
uint16_t x = touch_unpack_x(event);
|
||||
@ -140,8 +130,7 @@ static void prodtest_touch_test(cli_t* cli) {
|
||||
}
|
||||
}
|
||||
|
||||
gfx_clear();
|
||||
display_refresh();
|
||||
screen_prodtest_welcome();
|
||||
}
|
||||
|
||||
static void prodtest_touch_test_custom(cli_t* cli) {
|
||||
@ -188,9 +177,7 @@ static void prodtest_touch_test_custom(cli_t* cli) {
|
||||
cli_trace(cli, "Drawing a rectangle at [%d, %d] with size [%d x %d]...", x, y,
|
||||
width, height);
|
||||
|
||||
gfx_clear();
|
||||
gfx_draw_bar(gfx_rect_wh(x, y, width, height), COLOR_WHITE);
|
||||
display_refresh();
|
||||
screen_prodtest_touch(x, y, width, height);
|
||||
|
||||
uint32_t expire_time = ticks_timeout(timeout);
|
||||
|
||||
@ -226,8 +213,7 @@ static void prodtest_touch_test_custom(cli_t* cli) {
|
||||
}
|
||||
}
|
||||
|
||||
gfx_clear();
|
||||
display_refresh();
|
||||
screen_prodtest_welcome();
|
||||
}
|
||||
|
||||
static void prodtest_touch_test_idle(cli_t* cli) {
|
||||
@ -243,10 +229,8 @@ static void prodtest_touch_test_idle(cli_t* cli) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfx_clear();
|
||||
gfx_offset_t pos = gfx_offset(DISPLAY_RESX / 2, DISPLAY_RESY / 2);
|
||||
gfx_draw_text(pos, "DON'T TOUCH", -1, &bold, GFX_ALIGN_CENTER);
|
||||
display_refresh();
|
||||
const char msg[] = "DON'T TOUCH";
|
||||
screen_prodtest_show_text(msg, strlen(msg));
|
||||
|
||||
if (!ensure_touch_init(cli)) {
|
||||
return;
|
||||
@ -273,8 +257,7 @@ static void prodtest_touch_test_idle(cli_t* cli) {
|
||||
cli_ok(cli, "");
|
||||
|
||||
cleanup:
|
||||
gfx_clear();
|
||||
display_refresh();
|
||||
screen_prodtest_welcome();
|
||||
}
|
||||
|
||||
static void prodtest_touch_test_power(cli_t* cli) {
|
||||
@ -290,10 +273,8 @@ static void prodtest_touch_test_power(cli_t* cli) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfx_clear();
|
||||
gfx_offset_t pos = gfx_offset(DISPLAY_RESX / 2, DISPLAY_RESY / 2);
|
||||
gfx_draw_text(pos, "MEASURING", -1, &bold, GFX_ALIGN_CENTER);
|
||||
display_refresh();
|
||||
const char text[] = "MEASURING";
|
||||
screen_prodtest_show_text(text, strlen(text));
|
||||
|
||||
cli_trace(cli, "Setting touch controller power for %d ms...", timeout);
|
||||
|
||||
@ -311,8 +292,7 @@ static void prodtest_touch_test_power(cli_t* cli) {
|
||||
|
||||
cleanup:
|
||||
touch_power_set(false);
|
||||
gfx_clear();
|
||||
display_refresh();
|
||||
screen_prodtest_welcome();
|
||||
}
|
||||
|
||||
static void prodtest_touch_test_sensitivity(cli_t* cli) {
|
||||
@ -338,28 +318,22 @@ static void prodtest_touch_test_sensitivity(cli_t* cli) {
|
||||
cli_trace(cli, "Running touch controller test...");
|
||||
cli_trace(cli, "Press CTRL+C for exit.");
|
||||
|
||||
gfx_clear();
|
||||
display_refresh();
|
||||
|
||||
for (;;) {
|
||||
uint32_t evt = touch_get_event();
|
||||
if (evt & TOUCH_START || evt & TOUCH_MOVE) {
|
||||
int x = touch_unpack_x(evt);
|
||||
int y = touch_unpack_y(evt);
|
||||
gfx_clear();
|
||||
gfx_draw_bar(gfx_rect_wh(x - 48, y - 48, 96, 96), COLOR_WHITE);
|
||||
display_refresh();
|
||||
|
||||
screen_prodtest_touch(x - 48, y - 48, 96, 96);
|
||||
} else if (evt & TOUCH_END) {
|
||||
gfx_clear();
|
||||
display_refresh();
|
||||
screen_prodtest_touch(0, 0, 0, 0);
|
||||
}
|
||||
if (cli_aborted(cli)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gfx_clear();
|
||||
display_refresh();
|
||||
screen_prodtest_welcome();
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
@ -20,18 +20,15 @@
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <gfx/fonts.h>
|
||||
#include <gfx/gfx_draw.h>
|
||||
#include <io/display.h>
|
||||
#include <io/display_utils.h>
|
||||
#include <io/usb.h>
|
||||
#include <rtl/cli.h>
|
||||
#include <sys/system.h>
|
||||
#include <sys/systick.h>
|
||||
#include <util/flash.h>
|
||||
#include <util/flash_otp.h>
|
||||
#include <util/rsod.h>
|
||||
|
||||
#include "rust_ui_prodtest.h"
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
#include <io/button.h>
|
||||
#endif
|
||||
@ -144,53 +141,17 @@ static void usb_init_all(void) {
|
||||
ensure(usb_start(), NULL);
|
||||
}
|
||||
|
||||
static inline gfx_rect_t gfx_rect_shrink(gfx_rect_t r, int padding) {
|
||||
gfx_rect_t result = {
|
||||
.x0 = r.x0 + padding,
|
||||
.y0 = r.y0 + padding,
|
||||
.x1 = r.x1 - padding,
|
||||
.y1 = r.y1 - padding,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
static void draw_welcome_screen(void) {
|
||||
gfx_clear();
|
||||
gfx_rect_t r = gfx_rect_wh(0, 0, DISPLAY_RESX, DISPLAY_RESY);
|
||||
uint8_t qr_scale = 4;
|
||||
int16_t text_offset = 30;
|
||||
gfx_text_attr_t bold = {
|
||||
.font = FONT_BOLD,
|
||||
.fg_color = COLOR_WHITE,
|
||||
.bg_color = COLOR_BLACK,
|
||||
};
|
||||
|
||||
#if defined TREZOR_MODEL_T2B1 || defined TREZOR_MODEL_T3B1
|
||||
gfx_draw_bar(r, COLOR_WHITE);
|
||||
qr_scale = 2;
|
||||
text_offset = 9;
|
||||
bold.fg_color = COLOR_BLACK;
|
||||
bold.bg_color = COLOR_WHITE;
|
||||
#else
|
||||
gfx_draw_bar(gfx_rect_shrink(r, 3), COLOR_WHITE);
|
||||
gfx_draw_bar(gfx_rect_shrink(r, 4), COLOR_BLACK);
|
||||
#endif
|
||||
|
||||
char dom[32];
|
||||
static void show_welcome_screen(void) {
|
||||
char dom[32] = {0};
|
||||
// format: {MODEL_IDENTIFIER}YYMMDD
|
||||
if (sectrue == flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, (uint8_t *)dom, 32) &&
|
||||
dom[31] == 0 && cstr_starts_with(dom, MODEL_IDENTIFIER)) {
|
||||
gfx_offset_t pos;
|
||||
|
||||
pos = gfx_offset(DISPLAY_RESX / 2, DISPLAY_RESY / 2);
|
||||
gfx_draw_qrcode(pos, qr_scale, dom);
|
||||
|
||||
pos = gfx_offset(DISPLAY_RESX / 2, DISPLAY_RESY - text_offset);
|
||||
gfx_draw_text(pos, dom + sizeof(MODEL_IDENTIFIER) - 1, -1, &bold,
|
||||
GFX_ALIGN_CENTER);
|
||||
if ((sectrue ==
|
||||
flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, (uint8_t *)dom, 32) &&
|
||||
dom[31] == 0 && cstr_starts_with(dom, MODEL_IDENTIFIER))) {
|
||||
screen_prodtest_info(dom, strlen(dom), dom + sizeof(MODEL_IDENTIFIER) - 1,
|
||||
strlen(dom) - sizeof(MODEL_IDENTIFIER) + 1);
|
||||
} else {
|
||||
screen_prodtest_welcome();
|
||||
}
|
||||
|
||||
display_refresh();
|
||||
}
|
||||
|
||||
static void drivers_init(void) {
|
||||
@ -230,9 +191,7 @@ int main(void) {
|
||||
drivers_init();
|
||||
usb_init_all();
|
||||
|
||||
// Draw welcome screen
|
||||
draw_welcome_screen();
|
||||
display_fade(0, BACKLIGHT_NORMAL, 1000);
|
||||
show_welcome_screen();
|
||||
|
||||
// Initialize command line interface
|
||||
cli_init(&g_cli, console_read, console_write, NULL);
|
||||
|
@ -29,6 +29,7 @@ ui_empty_lock = []
|
||||
ui_jpeg = []
|
||||
hw_jpeg_decoder = []
|
||||
bootloader = []
|
||||
prodtest = []
|
||||
button = []
|
||||
touch = []
|
||||
clippy = []
|
||||
|
14
core/embed/rust/rust_ui_prodtest.h
Normal file
14
core/embed/rust/rust_ui_prodtest.h
Normal file
@ -0,0 +1,14 @@
|
||||
#include <trezor_types.h>
|
||||
|
||||
void screen_prodtest_info(char* id, uint8_t id_len, char* date,
|
||||
uint8_t date_len);
|
||||
|
||||
void screen_prodtest_welcome(void);
|
||||
|
||||
void screen_prodtest_bars(const char* colors, size_t color_count);
|
||||
|
||||
void screen_prodtest_show_text(const char* text, uint8_t text_len);
|
||||
|
||||
void screen_prodtest_touch(int16_t x0, int16_t y0, int16_t w, int16_t h);
|
||||
|
||||
void screen_prodtest_border(void);
|
@ -5,3 +5,6 @@ pub mod bootloader_c;
|
||||
|
||||
#[cfg(feature = "micropython")]
|
||||
pub mod firmware_micropython;
|
||||
|
||||
#[cfg(feature = "prodtest")]
|
||||
pub mod prodtest_c;
|
||||
|
49
core/embed/rust/src/ui/api/prodtest_c.rs
Normal file
49
core/embed/rust/src/ui/api/prodtest_c.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use crate::ui::{ui_prodtest::ProdtestUI, util::from_c_array, ModelUI};
|
||||
|
||||
#[cfg(feature = "touch")]
|
||||
use crate::ui::geometry::{Offset, Point, Rect};
|
||||
#[cfg(feature = "touch")]
|
||||
use cty::int16_t;
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_prodtest_welcome() {
|
||||
ModelUI::screen_prodtest_welcome();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_prodtest_info(
|
||||
id: *const cty::c_char,
|
||||
id_len: u8,
|
||||
date: *const cty::c_char,
|
||||
date_len: u8,
|
||||
) {
|
||||
let id = unwrap!(unsafe { from_c_array(id, id_len as usize) });
|
||||
let date = unwrap!(unsafe { from_c_array(date, date_len as usize) });
|
||||
|
||||
ModelUI::screen_prodtest_info(id, date);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_prodtest_show_text(text: *const cty::c_char, text_len: u8) {
|
||||
let text = unwrap!(unsafe { from_c_array(text, text_len as usize) });
|
||||
|
||||
ModelUI::screen_prodtest_show_text(text);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_prodtest_border() {
|
||||
ModelUI::screen_prodtest_border();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_prodtest_bars(colors: *const cty::c_char, colors_len: u8) {
|
||||
let colors: &str = unwrap!(unsafe { from_c_array(colors, colors_len as usize) });
|
||||
ModelUI::screen_prodtest_bars(colors);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "touch")]
|
||||
extern "C" fn screen_prodtest_touch(x0: int16_t, y0: int16_t, w: int16_t, h: int16_t) {
|
||||
let area = Rect::from_top_left_and_size(Point::new(x0, y0), Offset::new(w, h));
|
||||
ModelUI::screen_prodtest_touch(area);
|
||||
}
|
@ -23,6 +23,9 @@ pub struct UIBolt;
|
||||
#[cfg(feature = "micropython")]
|
||||
pub mod ui_firmware;
|
||||
|
||||
#[cfg(feature = "prodtest")]
|
||||
pub mod prodtest;
|
||||
|
||||
impl CommonUI for UIBolt {
|
||||
#[cfg(feature = "backlight")]
|
||||
fn fadein() {
|
||||
|
136
core/embed/rust/src/ui/layout_bolt/prodtest/mod.rs
Normal file
136
core/embed/rust/src/ui/layout_bolt/prodtest/mod.rs
Normal file
@ -0,0 +1,136 @@
|
||||
use crate::ui::{
|
||||
component::{base::Component, Qr},
|
||||
constant::screen,
|
||||
display,
|
||||
display::Color,
|
||||
geometry::{Alignment, Offset, Rect},
|
||||
layout_bolt::{fonts, theme, UIBolt},
|
||||
shape,
|
||||
shape::render_on_display,
|
||||
ui_prodtest::ProdtestUI,
|
||||
};
|
||||
|
||||
impl ProdtestUI for UIBolt {
|
||||
fn screen_prodtest_welcome() {
|
||||
display::sync();
|
||||
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
let area = screen();
|
||||
shape::Bar::new(area)
|
||||
.with_fg(Color::white())
|
||||
.with_thickness(1)
|
||||
.render(target);
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
display::fade_backlight_duration(theme::backlight::get_backlight_normal(), 150);
|
||||
}
|
||||
|
||||
fn screen_prodtest_info(id: &str, date: &str) {
|
||||
display::sync();
|
||||
let qr = Qr::new(id, true);
|
||||
let mut qr = unwrap!(qr).with_border(4);
|
||||
|
||||
// place the qr in the middle of the screen and size it to half the screen
|
||||
let qr_width = screen().width() / 2;
|
||||
|
||||
let qr_area = Rect::from_center_and_size(screen().center(), Offset::uniform(qr_width));
|
||||
qr.place(qr_area);
|
||||
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
let area = screen();
|
||||
shape::Bar::new(area).with_fg(Color::white()).render(target);
|
||||
|
||||
qr.render(target);
|
||||
|
||||
shape::Text::new(
|
||||
screen().bottom_center() - Offset::y(10),
|
||||
date,
|
||||
fonts::FONT_BOLD_UPPER,
|
||||
)
|
||||
.with_fg(Color::white())
|
||||
.with_align(Alignment::Center)
|
||||
.render(target);
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
display::fade_backlight_duration(theme::backlight::get_backlight_normal(), 150);
|
||||
}
|
||||
|
||||
fn screen_prodtest_show_text(text: &str) {
|
||||
display::sync();
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
shape::Text::new(screen().center(), text, fonts::FONT_BOLD_UPPER)
|
||||
.with_fg(Color::white())
|
||||
.with_align(Alignment::Center)
|
||||
.render(target);
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
display::fade_backlight_duration(theme::backlight::get_backlight_normal(), 150);
|
||||
}
|
||||
|
||||
fn screen_prodtest_border() {
|
||||
display::sync();
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
let area = screen();
|
||||
shape::Bar::new(area)
|
||||
.with_fg(Color::white())
|
||||
.with_thickness(1)
|
||||
.render(target);
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
display::fade_backlight_duration(theme::backlight::get_backlight_normal(), 150);
|
||||
}
|
||||
|
||||
fn screen_prodtest_bars(colors: &str) {
|
||||
display::sync();
|
||||
|
||||
let num_colors = colors.chars().count();
|
||||
|
||||
let width = if num_colors > 0 {
|
||||
screen().width() / num_colors as i16
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
for (i, c) in colors.chars().enumerate() {
|
||||
let color = match c {
|
||||
'r' | 'R' => Color::rgb(255, 0, 0),
|
||||
'g' | 'G' => Color::rgb(0, 255, 0),
|
||||
'b' | 'B' => Color::rgb(0, 0, 255),
|
||||
'w' | 'W' => Color::white(),
|
||||
_ => Color::black(),
|
||||
};
|
||||
|
||||
let area = Rect::from_top_left_and_size(
|
||||
screen().top_left() + Offset::x(i as i16 * width),
|
||||
Offset::new(width, screen().height()),
|
||||
);
|
||||
|
||||
shape::Bar::new(area)
|
||||
.with_fg(color)
|
||||
.with_bg(color)
|
||||
.render(target);
|
||||
}
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
display::fade_backlight_duration(theme::backlight::get_backlight_normal(), 150);
|
||||
}
|
||||
|
||||
fn screen_prodtest_touch(area: Rect) {
|
||||
display::sync();
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
shape::Bar::new(area)
|
||||
.with_fg(Color::white())
|
||||
.with_bg(Color::white())
|
||||
.render(target);
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
display::set_backlight(theme::backlight::get_backlight_normal());
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#[cfg(not(feature = "bootloader"))]
|
||||
#[cfg(not(any(feature = "bootloader", feature = "prodtest")))]
|
||||
use crate::storage;
|
||||
|
||||
// Typical backlight values.
|
||||
@ -9,24 +9,24 @@ const BACKLIGHT_NONE: u8 = 0;
|
||||
const BACKLIGHT_MIN: u8 = 10;
|
||||
const BACKLIGHT_MAX: u8 = 255;
|
||||
|
||||
#[cfg(feature = "bootloader")]
|
||||
#[cfg(any(feature = "bootloader", feature = "prodtest"))]
|
||||
pub fn get_backlight_normal() -> u8 {
|
||||
BACKLIGHT_NORMAL
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "bootloader"))]
|
||||
#[cfg(not(any(feature = "bootloader", feature = "prodtest")))]
|
||||
pub fn get_backlight_normal() -> u8 {
|
||||
storage::get_brightness()
|
||||
.unwrap_or(BACKLIGHT_NORMAL)
|
||||
.clamp(BACKLIGHT_MIN, BACKLIGHT_MAX)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bootloader")]
|
||||
#[cfg(any(feature = "bootloader", feature = "prodtest"))]
|
||||
pub fn get_backlight_low() -> u8 {
|
||||
BACKLIGHT_LOW
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "bootloader"))]
|
||||
#[cfg(not(any(feature = "bootloader", feature = "prodtest")))]
|
||||
pub fn get_backlight_low() -> u8 {
|
||||
storage::get_brightness()
|
||||
.unwrap_or(BACKLIGHT_LOW)
|
||||
|
@ -2,6 +2,10 @@ use super::{geometry::Rect, CommonUI};
|
||||
|
||||
#[cfg(feature = "bootloader")]
|
||||
pub mod bootloader;
|
||||
|
||||
#[cfg(feature = "prodtest")]
|
||||
pub mod prodtest;
|
||||
|
||||
pub mod common_messages;
|
||||
pub mod component;
|
||||
#[cfg(feature = "micropython")]
|
||||
|
115
core/embed/rust/src/ui/layout_caesar/prodtest/mod.rs
Normal file
115
core/embed/rust/src/ui/layout_caesar/prodtest/mod.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use crate::ui::{
|
||||
component::{base::Component, Qr},
|
||||
constant::screen,
|
||||
display,
|
||||
display::Color,
|
||||
geometry::{Alignment, Offset, Rect},
|
||||
layout_caesar::{fonts, UICaesar},
|
||||
shape,
|
||||
shape::render_on_display,
|
||||
ui_prodtest::ProdtestUI,
|
||||
};
|
||||
|
||||
impl ProdtestUI for UICaesar {
|
||||
fn screen_prodtest_welcome() {
|
||||
display::sync();
|
||||
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
let area = screen();
|
||||
shape::Bar::new(area)
|
||||
.with_fg(Color::white())
|
||||
.with_bg(Color::white())
|
||||
.render(target);
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
fn screen_prodtest_info(id: &str, date: &str) {
|
||||
display::sync();
|
||||
let qr = Qr::new(id, true);
|
||||
let mut qr = unwrap!(qr).with_border(1);
|
||||
|
||||
let qr_width = 50;
|
||||
|
||||
let qr_area = Rect::from_center_and_size(screen().center(), Offset::uniform(qr_width))
|
||||
.translate(Offset::y(-5));
|
||||
qr.place(qr_area);
|
||||
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
qr.render(target);
|
||||
|
||||
shape::Text::new(screen().bottom_center(), date, fonts::FONT_BOLD_UPPER)
|
||||
.with_fg(Color::white())
|
||||
.with_align(Alignment::Center)
|
||||
.render(target);
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
fn screen_prodtest_show_text(text: &str) {
|
||||
display::sync();
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
shape::Text::new(screen().center(), text, fonts::FONT_BOLD_UPPER)
|
||||
.with_fg(Color::white())
|
||||
.with_align(Alignment::Center)
|
||||
.render(target);
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
fn screen_prodtest_border() {
|
||||
display::sync();
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
let area = screen();
|
||||
shape::Bar::new(area)
|
||||
.with_fg(Color::white())
|
||||
.with_thickness(1)
|
||||
.render(target);
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
fn screen_prodtest_bars(colors: &str) {
|
||||
display::sync();
|
||||
|
||||
let num_colors = colors.chars().count();
|
||||
|
||||
let width = if num_colors > 0 {
|
||||
screen().width() / num_colors as i16
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
render_on_display(None, Some(Color::black()), |target| {
|
||||
for (i, c) in colors.chars().enumerate() {
|
||||
let color = match c {
|
||||
'r' | 'R' => Color::rgb(255, 0, 0),
|
||||
'g' | 'G' => Color::rgb(0, 255, 0),
|
||||
'b' | 'B' => Color::rgb(0, 0, 255),
|
||||
'w' | 'W' => Color::white(),
|
||||
_ => Color::black(),
|
||||
};
|
||||
|
||||
let area = Rect::from_top_left_and_size(
|
||||
screen().top_left() + Offset::x(i as i16 * width),
|
||||
Offset::new(width, screen().height()),
|
||||
);
|
||||
|
||||
shape::Bar::new(area)
|
||||
.with_fg(color)
|
||||
.with_bg(color)
|
||||
.render(target);
|
||||
}
|
||||
});
|
||||
|
||||
display::refresh();
|
||||
}
|
||||
|
||||
fn screen_prodtest_touch(_area: Rect) {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
@ -26,6 +26,10 @@ pub mod layout_delizia;
|
||||
|
||||
#[cfg(feature = "bootloader")]
|
||||
pub mod ui_bootloader;
|
||||
|
||||
#[cfg(feature = "prodtest")]
|
||||
pub mod ui_prodtest;
|
||||
|
||||
pub mod ui_common;
|
||||
#[cfg(feature = "micropython")]
|
||||
pub mod ui_firmware;
|
||||
|
15
core/embed/rust/src/ui/ui_prodtest.rs
Normal file
15
core/embed/rust/src/ui/ui_prodtest.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use crate::ui::geometry::Rect;
|
||||
|
||||
pub trait ProdtestUI {
|
||||
fn screen_prodtest_welcome();
|
||||
|
||||
fn screen_prodtest_info(id: &str, date: &str);
|
||||
|
||||
fn screen_prodtest_show_text(text: &str);
|
||||
|
||||
fn screen_prodtest_border();
|
||||
|
||||
fn screen_prodtest_bars(colors: &str);
|
||||
|
||||
fn screen_prodtest_touch(area: Rect);
|
||||
}
|
Loading…
Reference in New Issue
Block a user