Can be built by `TREZOR_MODEL=R make build_unix`, `make build_unix_frozen` does not work yet. All the dialogs are not very pretty, they are just meant to work.pull/2243/head
parent
396d81f272
commit
6b5f578d02
@ -0,0 +1 @@
|
|||||||
|
Add model R emulator
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 19 KiB |
@ -0,0 +1,34 @@
|
|||||||
|
"""
|
||||||
|
Creates a header file containing image data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
background_image = "background_R.jpg"
|
||||||
|
|
||||||
|
h_file_name = "background_R.h"
|
||||||
|
|
||||||
|
h_file_template = """\
|
||||||
|
// clang-format off
|
||||||
|
unsigned char background_R_jpg[] = {content};
|
||||||
|
unsigned int background_R_jpg_len = {length};
|
||||||
|
"""
|
||||||
|
|
||||||
|
with open(background_image, "rb") as f:
|
||||||
|
image_data = f.read()
|
||||||
|
|
||||||
|
column_count = 12
|
||||||
|
|
||||||
|
content = "{{\n{image_bytes}\n}}"
|
||||||
|
image_bytes = " " # begin with indent
|
||||||
|
for index, byte in enumerate(image_data, start=1):
|
||||||
|
image_bytes += f"0x{byte:02x},"
|
||||||
|
# If at the end of line, include a newline with indent, otherwise just space
|
||||||
|
if index % column_count == 0:
|
||||||
|
image_bytes += "\n "
|
||||||
|
else:
|
||||||
|
image_bytes += " "
|
||||||
|
|
||||||
|
# Get rid of trailing coma
|
||||||
|
image_bytes = image_bytes.rstrip(", \n")
|
||||||
|
|
||||||
|
with open(h_file_name, "w") as f:
|
||||||
|
f.write(h_file_template.format(content=content.format(image_bytes=image_bytes), length=len(image_data)))
|
@ -1,8 +1,10 @@
|
|||||||
from trezor import utils
|
from trezor import utils
|
||||||
|
|
||||||
if utils.MODEL == "1":
|
if utils.MODEL in ("1",):
|
||||||
from .t1 import * # noqa: F401,F403
|
from .t1 import * # noqa: F401,F403
|
||||||
elif utils.MODEL == "T":
|
elif utils.MODEL in ("R",):
|
||||||
|
from .tr import * # noqa: F401,F403
|
||||||
|
elif utils.MODEL in ("T",):
|
||||||
from .tt import * # noqa: F401,F403
|
from .tt import * # noqa: F401,F403
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown Trezor model")
|
raise ValueError("Unknown Trezor model")
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
from micropython import const
|
||||||
|
|
||||||
|
TEXT_HEADER_HEIGHT = const(13)
|
||||||
|
TEXT_LINE_HEIGHT = const(9)
|
||||||
|
TEXT_LINE_HEIGHT_HALF = const(4)
|
||||||
|
TEXT_MARGIN_LEFT = const(0)
|
||||||
|
TEXT_MAX_LINES = const(4)
|
||||||
|
TEXT_MAX_LINES_NO_HEADER = const(5)
|
||||||
|
PAGINATION_MARGIN_RIGHT = const(4)
|
@ -0,0 +1,295 @@
|
|||||||
|
from typing import TYPE_CHECKING, Sequence
|
||||||
|
|
||||||
|
from trezor import io, log, loop, ui, wire, workflow
|
||||||
|
from trezor.enums import ButtonRequestType
|
||||||
|
|
||||||
|
import trezorui2
|
||||||
|
|
||||||
|
from ..common import button_request, interact
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Any, NoReturn, Type
|
||||||
|
|
||||||
|
ExceptionType = BaseException | Type[BaseException]
|
||||||
|
|
||||||
|
|
||||||
|
class _RustLayout(ui.Layout):
|
||||||
|
# pylint: disable=super-init-not-called
|
||||||
|
def __init__(self, layout: Any):
|
||||||
|
self.layout = layout
|
||||||
|
self.timer = loop.Timer()
|
||||||
|
self.layout.set_timer_fn(self.set_timer)
|
||||||
|
|
||||||
|
def set_timer(self, token: int, deadline: int) -> None:
|
||||||
|
self.timer.schedule(deadline, token)
|
||||||
|
|
||||||
|
def create_tasks(self) -> tuple[loop.Task, ...]:
|
||||||
|
return self.handle_input_and_rendering(), self.handle_timers()
|
||||||
|
|
||||||
|
def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator]
|
||||||
|
button = loop.wait(io.BUTTON)
|
||||||
|
ui.display.clear()
|
||||||
|
self.layout.paint()
|
||||||
|
while True:
|
||||||
|
# Using `yield` instead of `await` to avoid allocations.
|
||||||
|
event, button_num = yield button
|
||||||
|
workflow.idle_timer.touch()
|
||||||
|
msg = None
|
||||||
|
if event in (io.BUTTON_PRESSED, io.BUTTON_RELEASED):
|
||||||
|
msg = self.layout.button_event(event, button_num)
|
||||||
|
self.layout.paint()
|
||||||
|
if msg is not None:
|
||||||
|
raise ui.Result(msg)
|
||||||
|
|
||||||
|
def handle_timers(self) -> loop.Task: # type: ignore [awaitable-is-generator]
|
||||||
|
while True:
|
||||||
|
# Using `yield` instead of `await` to avoid allocations.
|
||||||
|
token = yield self.timer
|
||||||
|
msg = self.layout.timer(token)
|
||||||
|
self.layout.paint()
|
||||||
|
if msg is not None:
|
||||||
|
raise ui.Result(msg)
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_action(
|
||||||
|
ctx: wire.GenericContext,
|
||||||
|
br_type: str,
|
||||||
|
title: str,
|
||||||
|
action: str | None = None,
|
||||||
|
description: str | None = None,
|
||||||
|
description_param: str | None = None,
|
||||||
|
description_param_font: int = ui.BOLD,
|
||||||
|
verb: str | bytes | None = "OK",
|
||||||
|
verb_cancel: str | bytes | None = "cancel",
|
||||||
|
hold: bool = False,
|
||||||
|
hold_danger: bool = False,
|
||||||
|
icon: str | None = None,
|
||||||
|
icon_color: int | None = None,
|
||||||
|
reverse: bool = False,
|
||||||
|
larger_vspace: bool = False,
|
||||||
|
exc: ExceptionType = wire.ActionCancelled,
|
||||||
|
br_code: ButtonRequestType = ButtonRequestType.Other,
|
||||||
|
) -> None:
|
||||||
|
if isinstance(verb, bytes) or isinstance(verb_cancel, bytes):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
if description is not None and description_param is not None:
|
||||||
|
if description_param_font != ui.BOLD:
|
||||||
|
log.error(__name__, "confirm_action description_param_font not implemented")
|
||||||
|
description = description.format(description_param)
|
||||||
|
|
||||||
|
if hold:
|
||||||
|
log.error(__name__, "confirm_action hold not implemented")
|
||||||
|
|
||||||
|
result = await interact(
|
||||||
|
ctx,
|
||||||
|
_RustLayout(
|
||||||
|
trezorui2.confirm_action(
|
||||||
|
title=title.upper(),
|
||||||
|
action=action,
|
||||||
|
description=description,
|
||||||
|
verb=verb,
|
||||||
|
verb_cancel=verb_cancel,
|
||||||
|
hold=hold,
|
||||||
|
reverse=reverse,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
br_type,
|
||||||
|
br_code,
|
||||||
|
)
|
||||||
|
if result is not trezorui2.CONFIRMED:
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_text(
|
||||||
|
ctx: wire.GenericContext,
|
||||||
|
br_type: str,
|
||||||
|
title: str,
|
||||||
|
data: str,
|
||||||
|
description: str | None = None,
|
||||||
|
br_code: ButtonRequestType = ButtonRequestType.Other,
|
||||||
|
icon: str = ui.ICON_SEND, # TODO cleanup @ redesign
|
||||||
|
icon_color: int = ui.GREEN, # TODO cleanup @ redesign
|
||||||
|
) -> None:
|
||||||
|
result = await interact(
|
||||||
|
ctx,
|
||||||
|
_RustLayout(
|
||||||
|
trezorui2.confirm_text(
|
||||||
|
title=title.upper(),
|
||||||
|
data=data,
|
||||||
|
description=description,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
br_type,
|
||||||
|
br_code,
|
||||||
|
)
|
||||||
|
if result is not trezorui2.CONFIRMED:
|
||||||
|
raise wire.ActionCancelled
|
||||||
|
|
||||||
|
|
||||||
|
async def show_success(
|
||||||
|
ctx: wire.GenericContext,
|
||||||
|
br_type: str,
|
||||||
|
content: str,
|
||||||
|
) -> None:
|
||||||
|
result = await interact(
|
||||||
|
ctx,
|
||||||
|
_RustLayout(
|
||||||
|
trezorui2.confirm_text(
|
||||||
|
title="Success",
|
||||||
|
data=content,
|
||||||
|
description="",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
br_type,
|
||||||
|
br_code=ButtonRequestType.Other,
|
||||||
|
)
|
||||||
|
if result is not trezorui2.CONFIRMED:
|
||||||
|
raise wire.ActionCancelled
|
||||||
|
|
||||||
|
|
||||||
|
async def show_address(
|
||||||
|
ctx: wire.GenericContext,
|
||||||
|
address: str,
|
||||||
|
*,
|
||||||
|
case_sensitive: bool = True,
|
||||||
|
address_qr: str | None = None,
|
||||||
|
title: str = "Confirm address",
|
||||||
|
network: str | None = None,
|
||||||
|
multisig_index: int | None = None,
|
||||||
|
xpubs: Sequence[str] = (),
|
||||||
|
address_extra: str | None = None,
|
||||||
|
title_qr: str | None = None,
|
||||||
|
) -> None:
|
||||||
|
result = await interact(
|
||||||
|
ctx,
|
||||||
|
_RustLayout(
|
||||||
|
trezorui2.confirm_text(
|
||||||
|
title="ADDRESS",
|
||||||
|
data=address,
|
||||||
|
description="Confirm address",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"show_address",
|
||||||
|
ButtonRequestType.Address,
|
||||||
|
)
|
||||||
|
if result is not trezorui2.CONFIRMED:
|
||||||
|
raise wire.ActionCancelled
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_output(
|
||||||
|
ctx: wire.GenericContext,
|
||||||
|
address: str,
|
||||||
|
amount: str,
|
||||||
|
font_amount: int = ui.NORMAL, # TODO cleanup @ redesign
|
||||||
|
title: str = "Confirm sending",
|
||||||
|
icon: str = ui.ICON_SEND,
|
||||||
|
) -> None:
|
||||||
|
result = await interact(
|
||||||
|
ctx,
|
||||||
|
_RustLayout(
|
||||||
|
trezorui2.confirm_text(
|
||||||
|
title=title,
|
||||||
|
data=f"Send {amount} to {address}?",
|
||||||
|
description="Confirm Output",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"confirm_output",
|
||||||
|
ButtonRequestType.Other,
|
||||||
|
)
|
||||||
|
if result is not trezorui2.CONFIRMED:
|
||||||
|
raise wire.ActionCancelled
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_total(
|
||||||
|
ctx: wire.GenericContext,
|
||||||
|
total_amount: str,
|
||||||
|
fee_amount: str,
|
||||||
|
title: str = "Confirm transaction",
|
||||||
|
total_label: str = "Total amount:\n",
|
||||||
|
fee_label: str = "\nincluding fee:\n",
|
||||||
|
icon_color: int = ui.GREEN,
|
||||||
|
br_type: str = "confirm_total",
|
||||||
|
br_code: ButtonRequestType = ButtonRequestType.SignTx,
|
||||||
|
) -> None:
|
||||||
|
result = await interact(
|
||||||
|
ctx,
|
||||||
|
_RustLayout(
|
||||||
|
trezorui2.confirm_text(
|
||||||
|
title=title,
|
||||||
|
data=f"{total_label}{total_amount}\n{fee_label}{fee_amount}",
|
||||||
|
description="Confirm Output",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
br_type,
|
||||||
|
br_code,
|
||||||
|
)
|
||||||
|
if result is not trezorui2.CONFIRMED:
|
||||||
|
raise wire.ActionCancelled
|
||||||
|
|
||||||
|
|
||||||
|
async def confirm_blob(
|
||||||
|
ctx: wire.GenericContext,
|
||||||
|
br_type: str,
|
||||||
|
title: str,
|
||||||
|
data: bytes | str,
|
||||||
|
description: str | None = None,
|
||||||
|
hold: bool = False,
|
||||||
|
br_code: ButtonRequestType = ButtonRequestType.Other,
|
||||||
|
icon: str = ui.ICON_SEND, # TODO cleanup @ redesign
|
||||||
|
icon_color: int = ui.GREEN, # TODO cleanup @ redesign
|
||||||
|
ask_pagination: bool = False,
|
||||||
|
) -> None:
|
||||||
|
result = await interact(
|
||||||
|
ctx,
|
||||||
|
_RustLayout(
|
||||||
|
trezorui2.confirm_text(
|
||||||
|
title=title,
|
||||||
|
data=str(data),
|
||||||
|
description=description,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
br_type,
|
||||||
|
br_code,
|
||||||
|
)
|
||||||
|
if result is not trezorui2.CONFIRMED:
|
||||||
|
raise wire.ActionCancelled
|
||||||
|
|
||||||
|
|
||||||
|
def draw_simple_text(title: str, description: str = "") -> None:
|
||||||
|
log.error(__name__, "draw_simple_text not implemented")
|
||||||
|
|
||||||
|
|
||||||
|
async def request_pin_on_device(
|
||||||
|
ctx: wire.GenericContext,
|
||||||
|
prompt: str,
|
||||||
|
attempts_remaining: int | None,
|
||||||
|
allow_cancel: bool,
|
||||||
|
) -> str:
|
||||||
|
await button_request(ctx, "pin_device", code=ButtonRequestType.PinEntry)
|
||||||
|
|
||||||
|
# TODO: this should not be callable on TR
|
||||||
|
return "1234"
|
||||||
|
|
||||||
|
|
||||||
|
async def show_error_and_raise(
|
||||||
|
ctx: wire.GenericContext,
|
||||||
|
br_type: str,
|
||||||
|
content: str,
|
||||||
|
header: str = "Error",
|
||||||
|
subheader: str | None = None,
|
||||||
|
button: str = "Close",
|
||||||
|
red: bool = False,
|
||||||
|
exc: ExceptionType = wire.ActionCancelled,
|
||||||
|
) -> NoReturn:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
async def show_popup(
|
||||||
|
title: str,
|
||||||
|
description: str,
|
||||||
|
subtitle: str | None = None,
|
||||||
|
description_param: str = "",
|
||||||
|
timeout_ms: int = 3000,
|
||||||
|
) -> None:
|
||||||
|
raise NotImplementedError
|
Loading…
Reference in new issue