1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 23:48:12 +00:00

bunch of api cleanups

This commit is contained in:
Jan Pochyla 2017-09-16 15:00:31 +02:00
parent a7b6ea808a
commit 49cc4651c2
20 changed files with 235 additions and 218 deletions

View File

@ -3,7 +3,8 @@ from trezor.utils import unimport
# used to confirm/cancel the dialogs from outside of this module (i.e. # used to confirm/cancel the dialogs from outside of this module (i.e.
# through debug link) # through debug link)
signal = loop.Signal() if __debug__:
signal = loop.signal()
@unimport @unimport
@ -20,7 +21,12 @@ async def confirm(ctx, content, code=None, *args, **kwargs):
if code is None: if code is None:
code = Other code = Other
await ctx.call(ButtonRequest(code=code), ButtonAck) await ctx.call(ButtonRequest(code=code), ButtonAck)
return await loop.Wait((signal, dialog)) == CONFIRMED
if __debug__:
waiter = loop.wait(signal, dialog)
else:
waiter = dialog
return await waiter == CONFIRMED
@unimport @unimport
@ -37,7 +43,12 @@ async def hold_to_confirm(ctx, content, code=None, *args, **kwargs):
if code is None: if code is None:
code = Other code = Other
await ctx.call(ButtonRequest(code=code), ButtonAck) await ctx.call(ButtonRequest(code=code), ButtonAck)
return await loop.Wait((signal, dialog)) == CONFIRMED
if __debug__:
waiter = loop.wait(signal, dialog)
else:
waiter = dialog
return await waiter == CONFIRMED
@unimport @unimport

View File

@ -1,4 +1,5 @@
from micropython import const from micropython import const
import ustruct import ustruct
import utime import utime

View File

@ -312,7 +312,7 @@ def send_cmd(cmd: Cmd, iface: io.HID) -> None:
def boot(iface: io.HID): def boot(iface: io.HID):
loop.schedule_task(handle_reports(iface)) loop.schedule(handle_reports(iface))
async def handle_reports(iface: io.HID): async def handle_reports(iface: io.HID):
@ -446,7 +446,7 @@ class ConfirmState:
self.deadline_ms = utime.ticks_ms() + _CONFIRM_STATE_TIMEOUT_MS self.deadline_ms = utime.ticks_ms() + _CONFIRM_STATE_TIMEOUT_MS
self.task = self.confirm() self.task = self.confirm()
workflow.onstart(self.task) workflow.onstart(self.task)
loop.schedule_task(self.task) loop.schedule(self.task)
def kill(self) -> None: def kill(self) -> None:
if self.task is not None: if self.task is not None:

View File

@ -10,10 +10,10 @@ async def swipe_to_rotate():
async def dim_screen(): async def dim_screen():
await loop.Sleep(5 * 1000000) await loop.sleep(5 * 1000000)
await ui.backlight_slide(ui.BACKLIGHT_DIM) await ui.backlight_slide(ui.BACKLIGHT_DIM)
while True: while True:
await loop.Sleep(1000000) await loop.sleep(1000000)
def display_homescreen(): def display_homescreen():
@ -35,4 +35,4 @@ def display_homescreen():
async def layout_homescreen(): async def layout_homescreen():
while True: while True:
display_homescreen() display_homescreen()
await loop.Wait([swipe_to_rotate(), dim_screen()]) await loop.wait(swipe_to_rotate(), dim_screen())

View File

@ -1,5 +1,3 @@
from micropython import const
from trezor import config from trezor import config
from trezor import io from trezor import io
from trezor import log from trezor import log

View File

@ -5,20 +5,20 @@ bytes, string, embedded message and repeated fields.
For de-sererializing (loading) protobuf types, object with `AsyncReader` For de-sererializing (loading) protobuf types, object with `AsyncReader`
interface is required: interface is required:
class AsyncReader: >>> class AsyncReader:
async def areadinto(self, buffer): >>> async def areadinto(self, buffer):
""" >>> """
Reads `len(buffer)` bytes into `buffer`, or raises `EOFError`. >>> Reads `len(buffer)` bytes into `buffer`, or raises `EOFError`.
""" >>> """
For serializing (dumping) protobuf types, object with `AsyncWriter` interface is For serializing (dumping) protobuf types, object with `AsyncWriter` interface is
required: required:
class AsyncWriter: >>> class AsyncWriter:
async def awrite(self, buffer): >>> async def awrite(self, buffer):
""" >>> """
Writes all bytes from `buffer`, or raises `EOFError`. >>> Writes all bytes from `buffer`, or raises `EOFError`.
""" >>> """
''' '''
from micropython import const from micropython import const

View File

@ -2,14 +2,15 @@
class Hmac: class Hmac:
def __init__(self, key, msg, digestmod): def __init__(self, key, msg, digestmod):
self.__digestmod = digestmod self.digestmod = digestmod
self.__inner = digestmod() self.inner = digestmod()
self.digest_size = self.__inner.digest_size self.digest_size = self.inner.digest_size
self.block_size = self.__inner.block_size self.block_size = self.inner.block_size
if len(key) > self.block_size: if len(key) > self.block_size:
key = digestmod(key).digest() key = digestmod(key).digest()
self.__key = key + bytes(self.block_size - len(key)) self.key = key + bytes(self.block_size - len(key))
self.__inner.update(bytes((x ^ 0x36) for x in self.__key)) self.inner.update(bytes((x ^ 0x36) for x in self.key))
if msg is not None: if msg is not None:
self.update(msg) self.update(msg)
@ -17,15 +18,15 @@ class Hmac:
''' '''
Update the context with data. Update the context with data.
''' '''
self.__inner.update(msg) self.inner.update(msg)
def digest(self) -> bytes: def digest(self) -> bytes:
''' '''
Returns the digest of processed data. Returns the digest of processed data.
''' '''
outer = self.__digestmod() outer = self.digestmod()
outer.update(bytes((x ^ 0x5C) for x in self.__key)) outer.update(bytes((x ^ 0x5C) for x in self.key))
outer.update(self.__inner.digest()) outer.update(self.inner.digest())
return outer.digest() return outer.digest()

View File

@ -4,8 +4,7 @@ the form of python coroutines (either plain generators or `async` functions) are
stepped through until completion, and can get asynchronously blocked by stepped through until completion, and can get asynchronously blocked by
`yield`ing or `await`ing a syscall. `yield`ing or `await`ing a syscall.
See `schedule_task`, `run`, and syscalls `Sleep`, `Select`, `Signal` See `schedule`, `run`, and syscalls `sleep`, `select`, `signal` and `wait`.
and `Wait`.
''' '''
import utime import utime
@ -14,21 +13,11 @@ from micropython import const
from trezor import log from trezor import log
from trezor import io from trezor import io
TOUCH = io.TOUCH
TOUCH_START = io.TOUCH_START
TOUCH_MOVE = io.TOUCH_MOVE
TOUCH_END = io.TOUCH_END
READ = io.POLL_READ
WRITE = io.POLL_WRITE
after_step_hook = None # function, called after each task step after_step_hook = None # function, called after each task step
_MAX_SELECT_DELAY = const(1000000) # usec delay if queue is empty _QUEUE_SIZE = const(64) # maximum number of scheduled tasks
_MAX_QUEUE_SIZE = const(64) # maximum number of scheduled tasks _queue = utimeq.utimeq(_QUEUE_SIZE)
_paused = {}
_paused_tasks = {} # {message interface: [task]}
_scheduled_tasks = utimeq.utimeq(_MAX_QUEUE_SIZE)
if __debug__: if __debug__:
# for performance stats # for performance stats
@ -38,47 +27,48 @@ if __debug__:
log_delay_rb = array.array('i', [0] * log_delay_rb_len) log_delay_rb = array.array('i', [0] * log_delay_rb_len)
def schedule_task(task, value=None, deadline=None): def schedule(task, value=None, deadline=None):
''' '''
Schedule task to be executed with `value` on given `deadline` (in Schedule task to be executed with `value` on given `deadline` (in
microseconds). Does not start the event loop itself, see `run`. microseconds). Does not start the event loop itself, see `run`.
''' '''
if deadline is None: if deadline is None:
deadline = utime.ticks_us() deadline = utime.ticks_us()
_scheduled_tasks.push(deadline, task, value) _queue.push(deadline, task, value)
def unschedule_task(task): def unschedule(task):
''' '''
Remove task from the time queue. Cancels previous `schedule_task`. Remove task from the time queue. Cancels previous `schedule`.
''' '''
global _scheduled_tasks global _queue
task_entry = [0, 0, 0] # deadline, task, value task_entry = [0, 0, 0] # deadline, task, value
queue_copy = utimeq.utimeq(_MAX_QUEUE_SIZE) queue_copy = utimeq.utimeq(_QUEUE_SIZE)
while _scheduled_tasks: while _queue:
_scheduled_tasks.pop(task_entry) _queue.pop(task_entry)
if task_entry[1] is not task: t, v, d = task_entry
queue_copy.push(task_entry[0], task_entry[1], task_entry[2]) if t is not task:
_scheduled_tasks = queue_copy queue_copy.push(t, v, d)
_queue = queue_copy
def _pause_task(task, iface): def pause(task, iface):
tasks = _paused_tasks.get(iface, None) tasks = _paused.get(iface, None)
if tasks is None: if tasks is None:
tasks = _paused_tasks[iface] = [] tasks = _paused[iface] = []
tasks.append(task) tasks.append(task)
def _unpause_task(task): def unpause(task):
for iface in _paused_tasks: for iface in _paused:
if task in _paused_tasks[iface]: if task in _paused[iface]:
_paused_tasks[iface].remove(task) _paused[iface].remove(task)
def run(): def run():
''' '''
Loop forever, stepping through scheduled tasks and awaiting I/O events Loop forever, stepping through scheduled tasks and awaiting I/O events
inbetween. Use `schedule_task` first to add a coroutine to the task queue. inbetween. Use `schedule` first to add a coroutine to the task queue.
Tasks yield back to the scheduler on any I/O, usually by calling `await` on Tasks yield back to the scheduler on any I/O, usually by calling `await` on
a `Syscall`. a `Syscall`.
''' '''
@ -86,34 +76,35 @@ def run():
if __debug__: if __debug__:
global log_delay_pos global log_delay_pos
max_delay = const(1000000) # usec delay if queue is empty
task_entry = [0, 0, 0] # deadline, task, value task_entry = [0, 0, 0] # deadline, task, value
msg_entry = [0, 0] # iface | flags, value msg_entry = [0, 0] # iface | flags, value
while True: while True:
# compute the maximum amount of time we can wait for a message # compute the maximum amount of time we can wait for a message
if _scheduled_tasks: if _queue:
delay = utime.ticks_diff( delay = utime.ticks_diff(_queue.peektime(), utime.ticks_us())
_scheduled_tasks.peektime(), utime.ticks_us())
else: else:
delay = _MAX_SELECT_DELAY delay = max_delay
if __debug__: if __debug__:
# add current delay to ring buffer for performance stats # add current delay to ring buffer for performance stats
log_delay_rb[log_delay_pos] = delay log_delay_rb[log_delay_pos] = delay
log_delay_pos = (log_delay_pos + 1) % log_delay_rb_len log_delay_pos = (log_delay_pos + 1) % log_delay_rb_len
if io.poll(_paused_tasks, msg_entry, delay): if io.poll(_paused, msg_entry, delay):
# message received, run tasks paused on the interface # message received, run tasks paused on the interface
msg_tasks = _paused_tasks.pop(msg_entry[0], ()) msg_tasks = _paused.pop(msg_entry[0], ())
for task in msg_tasks: for task in msg_tasks:
_step_task(task, msg_entry[1]) _step(task, msg_entry[1])
else: else:
# timeout occurred, run the first scheduled task # timeout occurred, run the first scheduled task
if _scheduled_tasks: if _queue:
_scheduled_tasks.pop(task_entry) _queue.pop(task_entry)
_step_task(task_entry[1], task_entry[2]) _step(task_entry[1], task_entry[2])
def _step_task(task, value): def _step(task, value):
try: try:
if isinstance(value, Exception): if isinstance(value, Exception):
result = task.throw(value) result = task.throw(value)
@ -129,7 +120,7 @@ def _step_task(task, value):
if isinstance(result, Syscall): if isinstance(result, Syscall):
result.handle(task) result.handle(task)
elif result is None: elif result is None:
schedule_task(task) schedule(task)
else: else:
if __debug__: if __debug__:
log.error(__name__, 'unknown syscall: %s', result) log.error(__name__, 'unknown syscall: %s', result)
@ -148,15 +139,16 @@ class Syscall:
return (yield self) return (yield self)
class Sleep(Syscall): class sleep(Syscall):
''' '''
Pause current task and resume it after given delay. Although the delay is Pause current task and resume it after given delay. Although the delay is
given in microseconds, sub-millisecond precision is not guaranteed. Result given in microseconds, sub-millisecond precision is not guaranteed. Result
value is the calculated deadline. value is the calculated deadline.
Example: Example:
planned = await loop.Sleep(1000 * 1000) # sleep for 1ms
print('missed by %d us', utime.ticks_diff(utime.ticks_us(), planned)) >>> planned = await loop.sleep(1000 * 1000) # sleep for 1ms
>>> print('missed by %d us', utime.ticks_diff(utime.ticks_us(), planned))
''' '''
def __init__(self, delay_us): def __init__(self, delay_us):
@ -164,43 +156,45 @@ class Sleep(Syscall):
def handle(self, task): def handle(self, task):
deadline = utime.ticks_add(utime.ticks_us(), self.delay_us) deadline = utime.ticks_add(utime.ticks_us(), self.delay_us)
schedule_task(task, deadline, deadline) schedule(task, deadline, deadline)
class Select(Syscall): class select(Syscall):
''' '''
Pause current task, and resume only after a message on `msg_iface` is Pause current task, and resume only after a message on `msg_iface` is
received. Messages are received either from an USB interface, or the received. Messages are received either from an USB interface, or the
touch display. Result value a tuple of message values. touch display. Result value a tuple of message values.
Example: Example:
hid_report, = await loop.Select(0xABCD) # await USB HID report
event, x, y = await loop.Select(loop.TOUCH) # await touch event >>> hid_report, = await loop.select(0xABCD) # await USB HID report
>>> event, x, y = await loop.select(io.TOUCH) # await touch event
''' '''
def __init__(self, msg_iface): def __init__(self, msg_iface):
self.msg_iface = msg_iface self.msg_iface = msg_iface
def handle(self, task): def handle(self, task):
_pause_task(task, self.msg_iface) pause(task, self.msg_iface)
_NO_VALUE = () _NO_VALUE = ()
class Signal(Syscall): class signal(Syscall):
''' '''
Pause current task, and let other running task to resume it later with a Pause current task, and let other running task to resume it later with a
result value or an exception. result value or an exception.
Example: Example:
# in task #1:
signal = loop.Signal() >>> # in task #1:
result = await signal >>> signal = loop.signal()
print('awaited result:', result) >>> result = await signal
# in task #2: >>> print('awaited result:', result)
signal.send('hello from task #2') >>> # in task #2:
# prints in the next iteration of the event loop >>> signal.send('hello from task #2')
>>> # prints in the next iteration of the event loop
''' '''
def __init__(self): def __init__(self):
@ -217,36 +211,37 @@ class Signal(Syscall):
def _deliver(self): def _deliver(self):
if self.task is not None and self.value is not _NO_VALUE: if self.task is not None and self.value is not _NO_VALUE:
schedule_task(self.task, self.value) schedule(self.task, self.value)
self.task = None self.task = None
self.value = _NO_VALUE self.value = _NO_VALUE
class Wait(Syscall): class wait(Syscall):
''' '''
Execute one or more children tasks and wait until one or more of them exit. Execute one or more children tasks and wait until one or more of them exit.
Return value of `Wait` is the return value of task that triggered the Return value of `wait` is the return value of task that triggered the
completion. By default, `Wait` returns after the first child completes, and completion. By default, `wait` returns after the first child completes, and
other running children are killed (by cancelling any pending schedules and other running children are killed (by cancelling any pending schedules and
calling `close()`). calling `close()`).
Example: Example:
# async def wait_for_touch(): ...
# async def animate_logo(): ...
touch_task = wait_for_touch()
animation_task = animate_logo()
waiter = loop.Wait((touch_task, animation_task))
result = await waiter
if animation_task in waiter.finished:
print('animation task returned', result)
else:
print('touch task returned', result)
Note: You should not directly `yield` a `Wait` instance, see logic in >>> # async def wait_for_touch(): ...
`Wait.__iter__` for explanation. Always use `await`. >>> # async def animate_logo(): ...
>>> touch_task = wait_for_touch()
>>> animation_task = animate_logo()
>>> waiter = loop.wait(touch_task, animation_task)
>>> result = await waiter
>>> if animation_task in waiter.finished:
>>> print('animation task returned', result)
>>> else:
>>> print('touch task returned', result)
Note: You should not directly `yield` a `wait` instance, see logic in
`wait.__iter__` for explanation. Always use `await`.
''' '''
def __init__(self, children, wait_for=1, exit_others=True): def __init__(self, *children, wait_for=1, exit_others=True):
self.children = children self.children = children
self.wait_for = wait_for self.wait_for = wait_for
self.exit_others = exit_others self.exit_others = exit_others
@ -259,13 +254,13 @@ class Wait(Syscall):
self.finished = [] self.finished = []
self.scheduled = [self._wait(c) for c in self.children] self.scheduled = [self._wait(c) for c in self.children]
for ct in self.scheduled: for ct in self.scheduled:
schedule_task(ct) schedule(ct)
def exit(self): def exit(self):
for task in self.scheduled: for task in self.scheduled:
if task not in self.finished: if task not in self.finished:
_unpause_task(task) unpause(task)
unschedule_task(task) unschedule(task)
task.close() task.close()
async def _wait(self, child): async def _wait(self, child):
@ -281,7 +276,7 @@ class Wait(Syscall):
if self.wait_for == len(self.finished) or isinstance(result, Exception): if self.wait_for == len(self.finished) or isinstance(result, Exception):
if self.exit_others: if self.exit_others:
self.exit() self.exit()
schedule_task(self.callback, result) schedule(self.callback, result)
def __iter__(self): def __iter__(self):
try: try:
@ -293,10 +288,10 @@ class Wait(Syscall):
raise raise
class Put(Syscall): class put(Syscall):
def __init__(self, chan, value=None): def __init__(self, ch, value=None):
self.chan = chan self.ch = ch
self.value = value self.value = value
def __call__(self, value): def __call__(self, value):
@ -304,30 +299,30 @@ class Put(Syscall):
return self return self
def handle(self, task): def handle(self, task):
self.chan.schedule_put(schedule_task, task, self.value) self.ch.schedule_put(schedule, task, self.value)
class Take(Syscall): class take(Syscall):
def __init__(self, chan): def __init__(self, ch):
self.chan = chan self.ch = ch
def __call__(self): def __call__(self):
return self return self
def handle(self, task): def handle(self, task):
if self.chan.schedule_take(schedule_task, task) and self.chan.id is not None: if self.ch.schedule_take(schedule, task) and self.ch.id is not None:
_pause_task(self.chan, self.chan.id) pause(self.ch, self.ch.id)
class Chan: class chan:
def __init__(self, id=None): def __init__(self, id=None):
self.id = id self.id = id
self.putters = [] self.putters = []
self.takers = [] self.takers = []
self.put = Put(self) self.put = put(self)
self.take = Take(self) self.take = take(self)
def schedule_publish(self, schedule, value): def schedule_publish(self, schedule, value):
if self.takers: if self.takers:
@ -357,9 +352,3 @@ class Chan:
else: else:
self.takers.append(taker) self.takers.append(taker)
return False return False
select = Select
sleep = Sleep
wait = Wait
signal = Signal

View File

@ -5,11 +5,14 @@ import math
import utime import utime
from trezorui import Display from trezorui import Display
from trezor import loop, res
from trezor import io
from trezor import loop
from trezor import res
display = Display() display = Display()
if sys.platform not in ('trezor', 'pyboard'): # stmhal if sys.platform != 'trezor':
loop.after_step_hook = display.refresh loop.after_step_hook = display.refresh
@ -72,7 +75,7 @@ ICON_WIPE = 'trezor/res/header_icons/wipe.toig'
ICON_RECOVERY = 'trezor/res/header_icons/recovery.toig' ICON_RECOVERY = 'trezor/res/header_icons/recovery.toig'
def in_area(pos: tuple, area: tuple) -> bool: def contains(pos: tuple, area: tuple) -> bool:
x, y = pos x, y = pos
ax, ay, aw, ah = area ax, ay, aw, ah = area
return ax <= x <= ax + aw and ay <= y <= ay + ah return ax <= x <= ax + aw and ay <= y <= ay + ah
@ -88,42 +91,35 @@ def blend(ca: int, cb: int, t: float) -> int:
lerpi((ca << 3) & 0xF8, (cb << 3) & 0xF8, t)) lerpi((ca << 3) & 0xF8, (cb << 3) & 0xF8, t))
def pulse(delay):
while True:
# normalize sin from interval -1:1 to 0:1
yield 0.5 + 0.5 * math.sin(utime.ticks_us() / delay)
async def alert(count=3): async def alert(count=3):
short_sleep = loop.sleep(20000)
long_sleep = loop.sleep(80000)
current = display.backlight() current = display.backlight()
for i in range(count * 2): for i in range(count * 2):
if i % 2 == 0: if i % 2 == 0:
display.backlight(BACKLIGHT_MAX) display.backlight(BACKLIGHT_MAX)
yield loop.Sleep(20000) yield short_sleep
else: else:
display.backlight(BACKLIGHT_NORMAL) display.backlight(BACKLIGHT_NORMAL)
yield loop.Sleep(80000) yield long_sleep
display.backlight(current) display.backlight(current)
async def backlight_slide(val, speed=20000): async def backlight_slide(val, delay=20000):
sleep = loop.sleep(delay)
current = display.backlight() current = display.backlight()
for i in range(current, val, -1 if current > val else 1): for i in range(current, val, -1 if current > val else 1):
display.backlight(i) display.backlight(i)
await loop.Sleep(speed) await sleep
def animate_pulse(func, ca, cb, speed=200000, delay=30000): def rotate(pos: tuple) -> tuple:
while True:
# normalize sin from interval -1:1 to 0:1
y = 0.5 + 0.5 * math.sin(utime.ticks_us() / speed)
c = blend(ca, cb, y)
func(c)
yield loop.Sleep(delay)
def header(title, icon=ICON_RESET, fg=BLACK, bg=BLACK):
display.bar(0, 0, 240, 32, bg)
if icon is not None:
display.icon(8, 4, res.load(icon), fg, bg)
display.text(8 + 24 + 2, 24, title, BOLD, fg, bg)
def rotate_coords(pos: tuple) -> tuple:
r = display.orientation() r = display.orientation()
if r == 0: if r == 0:
return pos return pos
@ -136,6 +132,13 @@ def rotate_coords(pos: tuple) -> tuple:
return (240 - y, x) return (240 - y, x)
def header(title, icon=ICON_RESET, fg=BLACK, bg=BLACK):
display.bar(0, 0, 240, 32, bg)
if icon is not None:
display.icon(8, 4, res.load(icon), fg, bg)
display.text(8 + 24 + 2, 24, title, BOLD, fg, bg)
class Widget: class Widget:
def render(self): def render(self):
@ -145,9 +148,10 @@ class Widget:
pass pass
def __iter__(self): def __iter__(self):
touch = loop.select(io.TOUCH)
while True: while True:
self.render() self.render()
event, *pos = yield loop.Select(loop.TOUCH) event, *pos = yield touch
result = self.touch(event, pos) result = self.touch(event, pos)
if result is not None: if result is not None:
return result return result

View File

@ -1,6 +1,12 @@
from micropython import const from micropython import const
from trezor import ui, loop
from . import display, in_area, rotate_coords, Widget from trezor import io
from trezor import ui
from trezor.ui import display
from trezor.ui import contains
from trezor.ui import rotate
from trezor.ui import Widget
DEFAULT_BUTTON = { DEFAULT_BUTTON = {
@ -142,18 +148,18 @@ class Button(Widget):
if self.state & BTN_DISABLED: if self.state & BTN_DISABLED:
return return
if not self.absolute: if not self.absolute:
pos = rotate_coords(pos) pos = rotate(pos)
if event == loop.TOUCH_START: if event == io.TOUCH_START:
if in_area(pos, self.area): if contains(pos, self.area):
self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE
elif event == loop.TOUCH_MOVE and self.state & BTN_STARTED: elif event == io.TOUCH_MOVE and self.state & BTN_STARTED:
if in_area(pos, self.area): if contains(pos, self.area):
if not self.state & BTN_ACTIVE: if not self.state & BTN_ACTIVE:
self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE
else: else:
if self.state & BTN_ACTIVE: if self.state & BTN_ACTIVE:
self.state = BTN_STARTED | BTN_DIRTY self.state = BTN_STARTED | BTN_DIRTY
elif event == loop.TOUCH_END and self.state & BTN_STARTED: elif event == io.TOUCH_END and self.state & BTN_STARTED:
self.state = BTN_DIRTY self.state = BTN_DIRTY
if in_area(pos, self.area): if contains(pos, self.area):
return BTN_CLICKED return BTN_CLICKED

View File

@ -41,7 +41,7 @@ class ConfirmDialog(Widget):
return CANCELLED return CANCELLED
async def __iter__(self): async def __iter__(self):
return await loop.Wait((super().__iter__(), self.content)) return await loop.wait(super().__iter__(), self.content)
_STARTED = const(-1) _STARTED = const(-1)
@ -82,5 +82,5 @@ class HoldToConfirmDialog(Widget):
else: else:
content_loop = self.content content_loop = self.content
confirm_loop = super().__iter__() # default loop (render on touch) confirm_loop = super().__iter__() # default loop (render on touch)
result = await loop.wait((content_loop, confirm_loop)) result = await loop.wait(content_loop, confirm_loop)
return result return result

View File

@ -1,4 +1,4 @@
from trezor import ui, res, loop from trezor import ui, res, loop, io
from trezor.crypto import bip39 from trezor.crypto import bip39
from trezor.ui import display from trezor.ui import display
from trezor.ui.button import Button, BTN_CLICKED, CLEAR_BUTTON, CLEAR_BUTTON_ACTIVE from trezor.ui.button import Button, BTN_CLICKED, CLEAR_BUTTON, CLEAR_BUTTON_ACTIVE
@ -136,9 +136,9 @@ class KeyboardMultiTap(ui.Widget):
btn.disable() btn.disable()
def __iter__(self): def __iter__(self):
timeout = loop.Sleep(1000 * 1000 * 1) timeout = loop.sleep(1000 * 1000 * 1)
touch = loop.Select(loop.TOUCH) touch = loop.select(io.TOUCH)
wait = loop.Wait((touch, timeout)) wait = loop.wait(touch, timeout)
while True: while True:
self.render() self.render()
result = yield wait result = yield wait
@ -223,9 +223,9 @@ class KeyboardZooming(ui.Widget):
break break
def __iter__(self): def __iter__(self):
timeout = loop.Sleep(1000 * 1000 * 1) timeout = loop.sleep(1000 * 1000 * 1)
touch = loop.Select(loop.TOUCH) touch = loop.select(io.TOUCH)
wait = loop.Wait((touch, timeout)) wait = loop.wait(touch, timeout)
while True: while True:
self.render() self.render()
result = yield wait result = yield wait

View File

@ -16,7 +16,7 @@ async def paginate(render_page, page_count, page=0, *args):
while True: while True:
changer = change_page(page, page_count) changer = change_page(page, page_count)
renderer = render_page(page, page_count, *args) renderer = render_page(page, page_count, *args)
waiter = loop.Wait([changer, renderer]) waiter = loop.wait(changer, renderer)
result = await waiter result = await waiter
if changer in waiter.finished: if changer in waiter.finished:
page = result page = result
@ -25,25 +25,28 @@ async def paginate(render_page, page_count, page=0, *args):
async def animate_swipe(): async def animate_swipe():
await ui.animate_pulse(render_swipe_icon, ui.GREY, ui.DARK_GREY, speed=300000, delay=200000) time_delay = const(30000)
draw_delay = const(200000)
sleep = loop.sleep(time_delay)
def render_swipe_icon(fg): for t in ui.pulse(draw_delay):
ui.display.bar_radius(102, 214, 36, 4, fg, ui.BLACK, 2) fg = ui.blend(ui.GREY, ui.DARK_GREY, t)
ui.display.bar_radius(106, 222, 28, 4, fg, ui.BLACK, 2) ui.display.bar_radius(102, 214, 36, 4, fg, ui.BLACK, 2)
ui.display.bar_radius(110, 230, 20, 4, fg, ui.BLACK, 2) ui.display.bar_radius(106, 222, 28, 4, fg, ui.BLACK, 2)
ui.display.bar_radius(110, 230, 20, 4, fg, ui.BLACK, 2)
await sleep
def render_scrollbar(page, page_count): def render_scrollbar(page, page_count):
screen_height = const(220) bbox = const(220)
size = const(10) size = const(10)
padding = 18 padding = 18
if page_count * padding > screen_height: if page_count * padding > bbox:
padding = screen_height // page_count padding = bbox // page_count
x = const(225) x = const(225)
y = (screen_height // 2) - (page_count // 2) * padding y = (bbox // 2) - (page_count // 2) * padding
for i in range(0, page_count): for i in range(0, page_count):
if i != page: if i != page:

View File

@ -1,7 +1,7 @@
import utime import utime
from micropython import const from micropython import const
from trezor import loop, ui from trezor import io, ui
from . import in_area, rotate_coords from . import contains, rotate
_SWIPE_DISTANCE_THRESHOLD = const(20) # Min pixels in the primary direction _SWIPE_DISTANCE_THRESHOLD = const(20) # Min pixels in the primary direction
_SWIPE_VELOCITY_THRESHOLD = const(200) # Min pixels per second _SWIPE_VELOCITY_THRESHOLD = const(200) # Min pixels per second
@ -26,12 +26,12 @@ class Swipe(ui.Widget):
def touch(self, event, pos): def touch(self, event, pos):
if not self.absolute: if not self.absolute:
pos = rotate_coords(pos) pos = rotate(pos)
temp_time = utime.ticks_ms() / 1000 temp_time = utime.ticks_ms() / 1000
# primary now for fading purposes # primary now for fading purposes
if event == loop.TOUCH_MOVE and self.start_pos is not None: if event == io.TOUCH_MOVE and self.start_pos is not None:
pdx = pos[0] - self.start_pos[0] pdx = pos[0] - self.start_pos[0]
pdy = pos[1] - self.start_pos[1] pdy = pos[1] - self.start_pos[1]
td = temp_time - self.start_time td = temp_time - self.start_time
@ -52,13 +52,13 @@ class Swipe(ui.Widget):
else: else:
ui.display.backlight(self.light_target) ui.display.backlight(self.light_target)
elif event == loop.TOUCH_START and in_area(pos, self.area): elif event == io.TOUCH_START and contains(pos, self.area):
self.start_time = temp_time self.start_time = temp_time
self.start_pos = pos self.start_pos = pos
self.light_origin = ui.BACKLIGHT_NORMAL self.light_origin = ui.BACKLIGHT_NORMAL
ui.display.backlight(self.light_origin) ui.display.backlight(self.light_origin)
elif event == loop.TOUCH_END and self.start_pos is not None: elif event == io.TOUCH_END and self.start_pos is not None:
td = temp_time - self.start_time td = temp_time - self.start_time
pdx = pos[0] - self.start_pos[0] pdx = pos[0] - self.start_pos[0]
pdy = pos[1] - self.start_pos[1] pdy = pos[1] - self.start_pos[1]

View File

@ -22,7 +22,7 @@ def setup(iface):
'''Initialize the wire stack on passed USB interface.''' '''Initialize the wire stack on passed USB interface.'''
session_supervisor = codec_v2.SesssionSupervisor(iface, session_handler) session_supervisor = codec_v2.SesssionSupervisor(iface, session_handler)
session_supervisor.open(codec_v1.SESSION_ID) session_supervisor.open(codec_v1.SESSION_ID)
loop.schedule_task(session_supervisor.listen()) loop.schedule(session_supervisor.listen())
class Context: class Context:

View File

@ -1,6 +1,7 @@
from micropython import const from micropython import const
import ustruct import ustruct
from trezor import io
from trezor import loop from trezor import loop
from trezor import utils from trezor import utils
@ -37,7 +38,7 @@ class Reader:
on this session. `self.type` and `self.size` are initialized and on this session. `self.type` and `self.size` are initialized and
available after `aopen()` returns. available after `aopen()` returns.
''' '''
read = loop.select(self.iface.iface_num() | loop.READ) read = loop.select(self.iface.iface_num() | io.POLL_READ)
while True: while True:
# wait for initial report # wait for initial report
report = await read report = await read
@ -63,7 +64,7 @@ class Reader:
if self.size < len(buf): if self.size < len(buf):
raise EOFError raise EOFError
read = loop.select(self.iface.iface_num() | loop.READ) read = loop.select(self.iface.iface_num() | io.POLL_READ)
nread = 0 nread = 0
while nread < len(buf): while nread < len(buf):
if self.ofs == len(self.data): if self.ofs == len(self.data):
@ -122,7 +123,7 @@ class Writer:
if self.size < len(buf): if self.size < len(buf):
raise EOFError raise EOFError
write = loop.select(self.iface.iface_num() | loop.WRITE) write = loop.select(self.iface.iface_num() | io.POLL_WRITE)
nwritten = 0 nwritten = 0
while nwritten < len(buf): while nwritten < len(buf):
# copy as much as possible to report buffer # copy as much as possible to report buffer
@ -148,5 +149,5 @@ class Writer:
self.data[self.ofs] = 0x00 self.data[self.ofs] = 0x00
self.ofs += 1 self.ofs += 1
await loop.select(self.iface.iface_num() | loop.WRITE) await loop.select(self.iface.iface_num() | io.POLL_WRITE)
self.iface.write(self.data) self.iface.write(self.data)

View File

@ -1,6 +1,7 @@
from micropython import const from micropython import const
import ustruct import ustruct
from trezor import io
from trezor import loop from trezor import loop
from trezor import utils from trezor import utils
from trezor.crypto import random from trezor.crypto import random
@ -59,7 +60,7 @@ class Reader:
on this session. `self.type` and `self.size` are initialized and on this session. `self.type` and `self.size` are initialized and
available after `aopen()` returns. available after `aopen()` returns.
''' '''
read = loop.select(self.iface.iface_num() | loop.READ) read = loop.select(self.iface.iface_num() | io.POLL_READ)
while True: while True:
# wait for initial report # wait for initial report
report = await read report = await read
@ -83,7 +84,7 @@ class Reader:
if self.size < len(buf): if self.size < len(buf):
raise EOFError raise EOFError
read = loop.select(self.iface.iface_num() | loop.READ) read = loop.select(self.iface.iface_num() | io.POLL_READ)
nread = 0 nread = 0
while nread < len(buf): while nread < len(buf):
if self.ofs == len(self.data): if self.ofs == len(self.data):
@ -148,7 +149,7 @@ class Writer:
if self.size < len(buf): if self.size < len(buf):
raise EOFError raise EOFError
write = loop.select(self.iface.iface_num() | loop.WRITE) write = loop.select(self.iface.iface_num() | io.POLL_WRITE)
nwritten = 0 nwritten = 0
while nwritten < len(buf): while nwritten < len(buf):
# copy as much as possible to report buffer # copy as much as possible to report buffer
@ -177,7 +178,7 @@ class Writer:
self.data[self.ofs] = 0x00 self.data[self.ofs] = 0x00
self.ofs += 1 self.ofs += 1
await loop.select(self.iface.iface_num() | loop.WRITE) await loop.select(self.iface.iface_num() | io.POLL_WRITE)
self.iface.write(self.data) self.iface.write(self.data)
@ -197,8 +198,8 @@ class SesssionSupervisor:
After close request, the handling task is closed and session terminated. After close request, the handling task is closed and session terminated.
Both requests receive responses confirming the operation. Both requests receive responses confirming the operation.
''' '''
read = loop.select(self.iface.iface_num() | loop.READ) read = loop.select(self.iface.iface_num() | io.POLL_READ)
write = loop.select(self.iface.iface_num() | loop.WRITE) write = loop.select(self.iface.iface_num() | io.POLL_WRITE)
while True: while True:
report = await read report = await read
repmarker, repsid = ustruct.unpack(_REP, report) repmarker, repsid = ustruct.unpack(_REP, report)
@ -221,7 +222,7 @@ class SesssionSupervisor:
def open(self, sid): def open(self, sid):
if sid not in self.handling_tasks: if sid not in self.handling_tasks:
task = self.handling_tasks[sid] = self.handler(self.iface, sid) task = self.handling_tasks[sid] = self.handler(self.iface, sid)
loop.schedule_task(task) loop.schedule(task)
def close(self, sid): def close(self, sid):
if sid in self.handling_tasks: if sid in self.handling_tasks:

View File

@ -38,6 +38,6 @@ def startdefault(handler):
if not default: if not default:
default_handler = handler default_handler = handler
default = handler() default = handler()
loop.schedule_task(default) loop.schedule(default)
ui.display.backlight(ui.BACKLIGHT_NORMAL) ui.display.backlight(ui.BACKLIGHT_NORMAL)
log.debug(__name__, 'startdefault') log.debug(__name__, 'startdefault')

View File

@ -6,7 +6,8 @@ from utest import *
from ustruct import pack, unpack from ustruct import pack, unpack
from ubinascii import hexlify, unhexlify from ubinascii import hexlify, unhexlify
from trezor.loop import Select, Syscall, READ, WRITE from trezor import io
from trezor.loop import select, Syscall
from trezor.crypto import random from trezor.crypto import random
from trezor.utils import chunks from trezor.utils import chunks
from trezor.wire import codec_v1 from trezor.wire import codec_v1
@ -39,7 +40,7 @@ def test_reader():
# open, expected one read # open, expected one read
first_report = report_header + message[:rep_len - len(report_header)] first_report = report_header + message[:rep_len - len(report_header)]
assert_async(reader.aopen(), [(None, Select(READ | interface_num)), (first_report, StopIteration()),]) assert_async(reader.aopen(), [(None, select(io.POLL_READ | interface_num)), (first_report, StopIteration()),])
assert_eq(reader.type, message_type) assert_eq(reader.type, message_type)
assert_eq(reader.size, message_len) assert_eq(reader.size, message_len)
@ -66,7 +67,7 @@ def test_reader():
next_report_header = bytearray(unhexlify('3f')) next_report_header = bytearray(unhexlify('3f'))
next_report = next_report_header + message[rep_len - len(report_header):][:rep_len - len(next_report_header)] next_report = next_report_header + message[rep_len - len(report_header):][:rep_len - len(next_report_header)]
onebyte_buffer = bytearray(1) onebyte_buffer = bytearray(1)
assert_async(reader.areadinto(onebyte_buffer), [(None, Select(READ | interface_num)), (next_report, StopIteration()),]) assert_async(reader.areadinto(onebyte_buffer), [(None, select(io.POLL_READ | interface_num)), (next_report, StopIteration()),])
assert_eq(onebyte_buffer, message[len(short_buffer):][len(aligned_buffer):][:len(onebyte_buffer)]) assert_eq(onebyte_buffer, message[len(short_buffer):][len(aligned_buffer):][:len(onebyte_buffer)])
assert_eq(reader.size, message_len - len(short_buffer) - len(aligned_buffer) - len(onebyte_buffer)) assert_eq(reader.size, message_len - len(short_buffer) - len(aligned_buffer) - len(onebyte_buffer))
@ -85,7 +86,7 @@ def test_reader():
expected_syscalls = [] expected_syscalls = []
for i, _ in enumerate(next_reports): for i, _ in enumerate(next_reports):
prev_report = next_reports[i - 1] if i > 0 else None prev_report = next_reports[i - 1] if i > 0 else None
expected_syscalls.append((prev_report, Select(READ | interface_num))) expected_syscalls.append((prev_report, select(io.POLL_READ | interface_num)))
expected_syscalls.append((next_reports[-1], StopIteration())) expected_syscalls.append((next_reports[-1], StopIteration()))
assert_async(reader.areadinto(long_buffer), expected_syscalls) assert_async(reader.areadinto(long_buffer), expected_syscalls)
assert_eq(long_buffer, message[-start_size:]) assert_eq(long_buffer, message[-start_size:])
@ -128,7 +129,7 @@ def test_writer():
# aligned write, expected one report # aligned write, expected one report
start_size = writer.size start_size = writer.size
aligned_payload = bytearray(range(rep_len - len(report_header) - len(short_payload))) aligned_payload = bytearray(range(rep_len - len(report_header) - len(short_payload)))
assert_async(writer.awrite(aligned_payload), [(None, Select(WRITE | interface_num)), (None, StopIteration()),]) assert_async(writer.awrite(aligned_payload), [(None, select(io.POLL_WRITE | interface_num)), (None, StopIteration()),])
assert_eq(interface.data, [report_header assert_eq(interface.data, [report_header
+ short_payload + short_payload
+ aligned_payload + aligned_payload
@ -154,7 +155,7 @@ def test_writer():
expected_reports[-1] += bytearray(bytes(1) * (rep_len - len(expected_reports[-1]))) expected_reports[-1] += bytearray(bytes(1) * (rep_len - len(expected_reports[-1])))
# test write # test write
expected_write_reports = expected_reports[:-1] expected_write_reports = expected_reports[:-1]
assert_async(writer.awrite(long_payload), len(expected_write_reports) * [(None, Select(WRITE | interface_num))] + [(None, StopIteration())]) assert_async(writer.awrite(long_payload), len(expected_write_reports) * [(None, select(io.POLL_WRITE | interface_num))] + [(None, StopIteration())])
assert_eq(interface.data, expected_write_reports) assert_eq(interface.data, expected_write_reports)
assert_eq(writer.size, start_size - len(long_payload)) assert_eq(writer.size, start_size - len(long_payload))
interface.data.clear() interface.data.clear()
@ -163,7 +164,7 @@ def test_writer():
assert_eq(interface.data, []) assert_eq(interface.data, [])
# test close # test close
expected_close_reports = expected_reports[-1:] expected_close_reports = expected_reports[-1:]
assert_async(writer.aclose(), len(expected_close_reports) * [(None, Select(WRITE | interface_num))] + [(None, StopIteration())]) assert_async(writer.aclose(), len(expected_close_reports) * [(None, select(io.POLL_WRITE | interface_num))] + [(None, StopIteration())])
assert_eq(interface.data, expected_close_reports) assert_eq(interface.data, expected_close_reports)
assert_eq(writer.size, 0) assert_eq(writer.size, 0)

View File

@ -6,7 +6,8 @@ from utest import *
from ustruct import pack, unpack from ustruct import pack, unpack
from ubinascii import hexlify, unhexlify from ubinascii import hexlify, unhexlify
from trezor.loop import Select, Syscall, READ, WRITE from trezor import io
from trezor.loop import select, Syscall
from trezor.utils import chunks from trezor.utils import chunks
from trezor.wire import codec_v2 from trezor.wire import codec_v2
@ -39,7 +40,7 @@ def test_reader():
# open, expected one read # open, expected one read
first_report = report_header + message[:rep_len - len(report_header)] first_report = report_header + message[:rep_len - len(report_header)]
assert_async(reader.aopen(), [(None, Select(READ | interface_num)), (first_report, StopIteration()),]) assert_async(reader.aopen(), [(None, select(io.POLL_READ | interface_num)), (first_report, StopIteration()),])
assert_eq(reader.type, message_type) assert_eq(reader.type, message_type)
assert_eq(reader.size, message_len) assert_eq(reader.size, message_len)
@ -66,7 +67,7 @@ def test_reader():
next_report_header = bytearray(unhexlify('021234567800000000')) next_report_header = bytearray(unhexlify('021234567800000000'))
next_report = next_report_header + message[rep_len - len(report_header):][:rep_len - len(next_report_header)] next_report = next_report_header + message[rep_len - len(report_header):][:rep_len - len(next_report_header)]
onebyte_buffer = bytearray(1) onebyte_buffer = bytearray(1)
assert_async(reader.areadinto(onebyte_buffer), [(None, Select(READ | interface_num)), (next_report, StopIteration()),]) assert_async(reader.areadinto(onebyte_buffer), [(None, select(io.POLL_READ | interface_num)), (next_report, StopIteration()),])
assert_eq(onebyte_buffer, message[len(short_buffer):][len(aligned_buffer):][:len(onebyte_buffer)]) assert_eq(onebyte_buffer, message[len(short_buffer):][len(aligned_buffer):][:len(onebyte_buffer)])
assert_eq(reader.size, message_len - len(short_buffer) - len(aligned_buffer) - len(onebyte_buffer)) assert_eq(reader.size, message_len - len(short_buffer) - len(aligned_buffer) - len(onebyte_buffer))
@ -85,7 +86,7 @@ def test_reader():
expected_syscalls = [] expected_syscalls = []
for i, _ in enumerate(next_reports): for i, _ in enumerate(next_reports):
prev_report = next_reports[i - 1] if i > 0 else None prev_report = next_reports[i - 1] if i > 0 else None
expected_syscalls.append((prev_report, Select(READ | interface_num))) expected_syscalls.append((prev_report, select(io.POLL_READ | interface_num)))
expected_syscalls.append((next_reports[-1], StopIteration())) expected_syscalls.append((next_reports[-1], StopIteration()))
assert_async(reader.areadinto(long_buffer), expected_syscalls) assert_async(reader.areadinto(long_buffer), expected_syscalls)
assert_eq(long_buffer, message[-start_size:]) assert_eq(long_buffer, message[-start_size:])
@ -129,7 +130,7 @@ def test_writer():
# aligned write, expected one report # aligned write, expected one report
start_size = writer.size start_size = writer.size
aligned_payload = bytearray(range(rep_len - len(report_header) - len(short_payload))) aligned_payload = bytearray(range(rep_len - len(report_header) - len(short_payload)))
assert_async(writer.awrite(aligned_payload), [(None, Select(WRITE | interface_num)), (None, StopIteration()),]) assert_async(writer.awrite(aligned_payload), [(None, select(io.POLL_WRITE | interface_num)), (None, StopIteration()),])
assert_eq(interface.data, [report_header assert_eq(interface.data, [report_header
+ short_payload + short_payload
+ aligned_payload + aligned_payload
@ -157,7 +158,7 @@ def test_writer():
expected_reports[-1] += bytearray(bytes(1) * (rep_len - len(expected_reports[-1]))) expected_reports[-1] += bytearray(bytes(1) * (rep_len - len(expected_reports[-1])))
# test write # test write
expected_write_reports = expected_reports[:-1] expected_write_reports = expected_reports[:-1]
assert_async(writer.awrite(long_payload), len(expected_write_reports) * [(None, Select(WRITE | interface_num))] + [(None, StopIteration())]) assert_async(writer.awrite(long_payload), len(expected_write_reports) * [(None, select(io.POLL_WRITE | interface_num))] + [(None, StopIteration())])
assert_eq(interface.data, expected_write_reports) assert_eq(interface.data, expected_write_reports)
assert_eq(writer.size, start_size - len(long_payload)) assert_eq(writer.size, start_size - len(long_payload))
interface.data.clear() interface.data.clear()
@ -166,7 +167,7 @@ def test_writer():
assert_eq(interface.data, []) assert_eq(interface.data, [])
# test close # test close
expected_close_reports = expected_reports[-1:] expected_close_reports = expected_reports[-1:]
assert_async(writer.aclose(), len(expected_close_reports) * [(None, Select(WRITE | interface_num))] + [(None, StopIteration())]) assert_async(writer.aclose(), len(expected_close_reports) * [(None, select(io.POLL_WRITE | interface_num))] + [(None, StopIteration())])
assert_eq(interface.data, expected_close_reports) assert_eq(interface.data, expected_close_reports)
assert_eq(writer.size, 0) assert_eq(writer.size, 0)
interface.data.clear() interface.data.clear()