feat(core): allow different screens sizes for TT UI

[no changelog]
tychovrahe/bluetooth/unification2
tychovrahe 1 year ago
parent 1481783d27
commit f56a8710a8

@ -32,8 +32,8 @@ enum SafetyCheckLevel {
* Format of the homescreen image * Format of the homescreen image
*/ */
enum HomescreenFormat { enum HomescreenFormat {
Toif144x144 = 1; Toif = 1;
Jpeg240x240 = 2; Jpeg = 2;
} }
/** /**
@ -121,8 +121,11 @@ message Features {
optional uint32 display_rotation = 39; // in degrees from North optional uint32 display_rotation = 39; // in degrees from North
optional bool experimental_features = 40; // are experimental message types enabled? optional bool experimental_features = 40; // are experimental message types enabled?
optional bool busy = 41; // is the device busy, showing "Do not disconnect"? optional bool busy = 41; // is the device busy, showing "Do not disconnect"?
optional HomescreenFormat homescreen_format = 42; // format of the homescreen, 1 = TOIf 144x144, 2 = jpg 240x240 optional HomescreenFormat homescreen_format = 42; // format of the homescreen, 1 = TOIf, 2 = jpg
optional bool hide_passphrase_from_host = 43; // should we hide the passphrase when it comes from host? optional bool hide_passphrase_from_host = 43; // should we hide the passphrase when it comes from host?
optional uint32 homescreen_width = 44; // homescreen width in pixels
optional uint32 homescreen_height = 45; // homescreen height in pixels
} }
/** /**

@ -295,6 +295,8 @@ fn generate_trezorhal_bindings() {
.allowlist_function("display_sync") .allowlist_function("display_sync")
.allowlist_var("DISPLAY_CMD_ADDRESS") .allowlist_var("DISPLAY_CMD_ADDRESS")
.allowlist_var("DISPLAY_DATA_ADDRESS") .allowlist_var("DISPLAY_DATA_ADDRESS")
.allowlist_var("DISPLAY_RESX")
.allowlist_var("DISPLAY_RESY")
.allowlist_type("toif_format_t") .allowlist_type("toif_format_t")
// fonts // fonts
.allowlist_function("font_height") .allowlist_function("font_height")

@ -4,6 +4,8 @@ use cty::c_int;
use crate::trezorhal::buffers::BufferText; use crate::trezorhal::buffers::BufferText;
pub use ffi::{DISPLAY_RESX, DISPLAY_RESY};
#[derive(PartialEq, Debug, Eq, FromPrimitive, Clone, Copy)] #[derive(PartialEq, Debug, Eq, FromPrimitive, Clone, Copy)]
pub enum ToifFormat { pub enum ToifFormat {
FullColorBE = ffi::toif_format_t_TOIF_FULL_COLOR_BE as _, FullColorBE = ffi::toif_format_t_TOIF_FULL_COLOR_BE as _,

@ -1,7 +1,9 @@
use crate::ui::geometry::{Offset, Point, Rect}; use crate::ui::geometry::{Offset, Point, Rect};
pub const WIDTH: i16 = 128; use crate::trezorhal::display::{DISPLAY_RESX, DISPLAY_RESY};
pub const HEIGHT: i16 = 128;
pub const WIDTH: i16 = DISPLAY_RESX as _;
pub const HEIGHT: i16 = DISPLAY_RESY as _;
pub const LINE_SPACE: i16 = 1; pub const LINE_SPACE: i16 = 1;
pub const FONT_BPP: i16 = 1; pub const FONT_BPP: i16 = 1;

@ -1,7 +1,9 @@
use crate::ui::geometry::{Offset, Point, Rect}; use crate::ui::geometry::{Offset, Point, Rect};
pub const WIDTH: i16 = 240; use crate::trezorhal::display::{DISPLAY_RESX, DISPLAY_RESY};
pub const HEIGHT: i16 = 240;
pub const WIDTH: i16 = DISPLAY_RESX as _;
pub const HEIGHT: i16 = DISPLAY_RESY as _;
pub const LINE_SPACE: i16 = 4; pub const LINE_SPACE: i16 = 4;
pub const FONT_BPP: i16 = 4; pub const FONT_BPP: i16 = 4;

@ -1,6 +1,11 @@
#ifndef _STM32F429I_DISC1_H #ifndef _STM32F429I_DISC1_H
#define _STM32F429I_DISC1_H #define _STM32F429I_DISC1_H
#define MAX_DISPLAY_RESX 240
#define MAX_DISPLAY_RESY 320
#define DISPLAY_RESX 240
#define DISPLAY_RESY 320
#define USE_I2C 1 #define USE_I2C 1
#define USE_TOUCH 1 #define USE_TOUCH 1
#define USE_BLE 1 #define USE_BLE 1

@ -1,6 +1,9 @@
#ifndef _TREZOR_T_H #ifndef _TREZOR_T_H
#define _TREZOR_T_H #define _TREZOR_T_H
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#define USE_SD_CARD 1 #define USE_SD_CARD 1
#define USE_I2C 1 #define USE_I2C 1
#define USE_TOUCH 1 #define USE_TOUCH 1

@ -4,10 +4,6 @@
#include STM32_HAL_H #include STM32_HAL_H
#define MAX_DISPLAY_RESX 240
#define MAX_DISPLAY_RESY 320
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#define TREZOR_FONT_BPP 4 #define TREZOR_FONT_BPP 4
extern uint8_t *const DISPLAY_DATA_ADDRESS; extern uint8_t *const DISPLAY_DATA_ADDRESS;

@ -6,8 +6,6 @@
// ILI9341V, GC9307 and ST7789V drivers support 240px x 320px display resolution // ILI9341V, GC9307 and ST7789V drivers support 240px x 320px display resolution
#define MAX_DISPLAY_RESX 240 #define MAX_DISPLAY_RESX 240
#define MAX_DISPLAY_RESY 320 #define MAX_DISPLAY_RESY 320
#define DISPLAY_RESX 240
#define DISPLAY_RESY 320
#define TREZOR_FONT_BPP 4 #define TREZOR_FONT_BPP 4
#ifdef USE_DISP_I8080_16BIT_DW #ifdef USE_DISP_I8080_16BIT_DW

@ -46,6 +46,7 @@ def get_features() -> Features:
from trezor import sdcard from trezor import sdcard
from trezor.enums import Capability from trezor.enums import Capability
from trezor.messages import Features from trezor.messages import Features
from trezor.ui import WIDTH, HEIGHT
from apps.common import mnemonic, safety_checks from apps.common import mnemonic, safety_checks
@ -63,7 +64,9 @@ def get_features() -> Features:
pin_protection=config.has_pin(), pin_protection=config.has_pin(),
unlocked=config.is_unlocked(), unlocked=config.is_unlocked(),
busy=busy_expiry_ms() > 0, busy=busy_expiry_ms() > 0,
homescreen_format=HomescreenFormat.Jpeg240x240, homescreen_format=HomescreenFormat.Jpeg,
homescreen_width=WIDTH,
homescreen_height=HEIGHT,
) )
if utils.BITCOIN_ONLY: if utils.BITCOIN_ONLY:

@ -16,6 +16,7 @@ BRT_PROTECT_CALL = ButtonRequestType.ProtectCall # CACHE
def _validate_homescreen(homescreen: bytes) -> None: def _validate_homescreen(homescreen: bytes) -> None:
import trezorui2 import trezorui2
import storage.device as storage_device import storage.device as storage_device
from trezor.ui import WIDTH, HEIGHT
if homescreen == b"": if homescreen == b"":
return return
@ -29,8 +30,8 @@ def _validate_homescreen(homescreen: bytes) -> None:
w, h, mcu_height = trezorui2.jpeg_info(homescreen) w, h, mcu_height = trezorui2.jpeg_info(homescreen)
except ValueError: except ValueError:
raise DataError("Invalid homescreen") raise DataError("Invalid homescreen")
if w != 240 or h != 240: if w != WIDTH or h != HEIGHT:
raise DataError("Homescreen must be 240x240 pixel large") raise DataError(f"Homescreen must be {WIDTH}x{HEIGHT} pixel large")
if mcu_height > 16: if mcu_height > 16:
raise DataError("Unsupported jpeg type") raise DataError("Unsupported jpeg type")
try: try:

@ -2,5 +2,5 @@
# fmt: off # fmt: off
# isort:skip_file # isort:skip_file
Toif144x144 = 1 Toif = 1
Jpeg240x240 = 2 Jpeg = 2

@ -415,8 +415,8 @@ if TYPE_CHECKING:
PromptTemporarily = 2 PromptTemporarily = 2
class HomescreenFormat(IntEnum): class HomescreenFormat(IntEnum):
Toif144x144 = 1 Toif = 1
Jpeg240x240 = 2 Jpeg = 2
class Capability(IntEnum): class Capability(IntEnum):
Bitcoin = 1 Bitcoin = 1

@ -2178,6 +2178,8 @@ if TYPE_CHECKING:
busy: "bool | None" busy: "bool | None"
homescreen_format: "HomescreenFormat | None" homescreen_format: "HomescreenFormat | None"
hide_passphrase_from_host: "bool | None" hide_passphrase_from_host: "bool | None"
homescreen_width: "int | None"
homescreen_height: "int | None"
def __init__( def __init__(
self, self,
@ -2222,6 +2224,8 @@ if TYPE_CHECKING:
busy: "bool | None" = None, busy: "bool | None" = None,
homescreen_format: "HomescreenFormat | None" = None, homescreen_format: "HomescreenFormat | None" = None,
hide_passphrase_from_host: "bool | None" = None, hide_passphrase_from_host: "bool | None" = None,
homescreen_width: "int | None" = None,
homescreen_height: "int | None" = None,
) -> None: ) -> None:
pass pass

@ -60,7 +60,7 @@ def image_to_t1(filename: str) -> bytes:
return image.tobytes("raw", "1") return image.tobytes("raw", "1")
def image_to_toif_144x144(filename: str) -> bytes: def image_to_toif(filename: str, width: int, height: int) -> bytes:
if filename.endswith(".toif"): if filename.endswith(".toif"):
try: try:
toif_image = toif.load(filename) toif_image = toif.load(filename)
@ -81,8 +81,8 @@ def image_to_toif_144x144(filename: str) -> bytes:
"Failed to convert image to Trezor format" "Failed to convert image to Trezor format"
) from e ) from e
if toif_image.size != (144, 144): if toif_image.size != (width, height):
raise click.ClickException("Wrong size of image - should be 144x144") raise click.ClickException(f"Wrong size of image - should be {width}x{height}")
if toif_image.mode != toif.ToifMode.full_color: if toif_image.mode != toif.ToifMode.full_color:
raise click.ClickException("Wrong image mode - should be full_color") raise click.ClickException("Wrong image mode - should be full_color")
@ -90,7 +90,7 @@ def image_to_toif_144x144(filename: str) -> bytes:
return toif_image.to_bytes() return toif_image.to_bytes()
def image_to_jpeg_240x240(filename: str) -> bytes: def image_to_jpeg(filename: str, width: int, height: int) -> bytes:
if not (filename.endswith(".jpg") or filename.endswith(".jpeg")): if not (filename.endswith(".jpg") or filename.endswith(".jpeg")):
raise click.ClickException("Please use a jpg image") raise click.ClickException("Please use a jpg image")
@ -108,8 +108,8 @@ def image_to_jpeg_240x240(filename: str) -> bytes:
if "progressive" in image.info: if "progressive" in image.info:
raise click.ClickException("Progressive JPEG is not supported") raise click.ClickException("Progressive JPEG is not supported")
if image.size != (240, 240): if image.size != (width, height):
raise click.ClickException("Wrong size of image - should be 240x240") raise click.ClickException(f"Wrong size of image - should be {width}x{height}")
image.close() image.close()
@ -243,17 +243,33 @@ def homescreen(client: "TrezorClient", filename: str) -> str:
if client.features.model == "1": if client.features.model == "1":
img = image_to_t1(filename) img = image_to_t1(filename)
else: else:
if ( if client.features.homescreen_format == messages.HomescreenFormat.Jpeg:
client.features.homescreen_format width = (
== messages.HomescreenFormat.Jpeg240x240 client.features.homescreen_width
): if client.features.homescreen_width is not None
img = image_to_jpeg_240x240(filename) else 240
)
height = (
client.features.homescreen_height
if client.features.homescreen_height is not None
else 240
)
img = image_to_jpeg(filename, width, height)
elif ( elif (
client.features.homescreen_format client.features.homescreen_format == messages.HomescreenFormat.Toif
== messages.HomescreenFormat.Toif144x144
or client.features.homescreen_format is None or client.features.homescreen_format is None
): ):
img = image_to_toif_144x144(filename) width = (
client.features.homescreen_width
if client.features.homescreen_width is not None
else 144
)
height = (
client.features.homescreen_height
if client.features.homescreen_height is not None
else 144
)
img = image_to_toif(filename, width, height)
else: else:
raise click.ClickException( raise click.ClickException(
"Unknown image format requested by the device." "Unknown image format requested by the device."

@ -445,8 +445,8 @@ class SafetyCheckLevel(IntEnum):
class HomescreenFormat(IntEnum): class HomescreenFormat(IntEnum):
Toif144x144 = 1 Toif = 1
Jpeg240x240 = 2 Jpeg = 2
class Capability(IntEnum): class Capability(IntEnum):
@ -3226,6 +3226,8 @@ class Features(protobuf.MessageType):
41: protobuf.Field("busy", "bool", repeated=False, required=False, default=None), 41: protobuf.Field("busy", "bool", repeated=False, required=False, default=None),
42: protobuf.Field("homescreen_format", "HomescreenFormat", repeated=False, required=False, default=None), 42: protobuf.Field("homescreen_format", "HomescreenFormat", repeated=False, required=False, default=None),
43: protobuf.Field("hide_passphrase_from_host", "bool", repeated=False, required=False, default=None), 43: protobuf.Field("hide_passphrase_from_host", "bool", repeated=False, required=False, default=None),
44: protobuf.Field("homescreen_width", "uint32", repeated=False, required=False, default=None),
45: protobuf.Field("homescreen_height", "uint32", repeated=False, required=False, default=None),
} }
def __init__( def __init__(
@ -3272,6 +3274,8 @@ class Features(protobuf.MessageType):
busy: Optional["bool"] = None, busy: Optional["bool"] = None,
homescreen_format: Optional["HomescreenFormat"] = None, homescreen_format: Optional["HomescreenFormat"] = None,
hide_passphrase_from_host: Optional["bool"] = None, hide_passphrase_from_host: Optional["bool"] = None,
homescreen_width: Optional["int"] = None,
homescreen_height: Optional["int"] = None,
) -> None: ) -> None:
self.capabilities: Sequence["Capability"] = capabilities if capabilities is not None else [] self.capabilities: Sequence["Capability"] = capabilities if capabilities is not None else []
self.major_version = major_version self.major_version = major_version
@ -3314,6 +3318,8 @@ class Features(protobuf.MessageType):
self.busy = busy self.busy = busy
self.homescreen_format = homescreen_format self.homescreen_format = homescreen_format
self.hide_passphrase_from_host = hide_passphrase_from_host self.hide_passphrase_from_host = hide_passphrase_from_host
self.homescreen_width = homescreen_width
self.homescreen_height = homescreen_height
class LockDevice(protobuf.MessageType): class LockDevice(protobuf.MessageType):

Loading…
Cancel
Save