1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-30 03:18:20 +00:00

add touch event rotation, msg dispatcher, wallet app

This commit is contained in:
Jan Pochyla 2016-05-25 14:27:22 +02:00 committed by Pavol Rusnak
parent b34b8e6959
commit 3677b8142b
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
11 changed files with 179 additions and 82 deletions

View File

@ -1,15 +1,11 @@
# Every application is supposed to have two entry points: from trezor.dispatcher import register
# from trezor.messages.Initialize import Initialize
# boot() is called during device boot time and it should prepare
# all global things necessary to run.
# def dispatch(message):
# dispatch() is called once event subscribed in boot() is received. from .layout_homescreen import layout_homescreen
return layout_homescreen(message)
def dispatch():
# Callback for HID messages
print("Dispatch homescreen")
def boot(): def boot():
# Initilize app on boot time. register(Initialize, dispatch)
# This should hookup HID message types dispatcher() wants to receive.
print("Boot homescreen")

View File

@ -1,30 +1,45 @@
from trezor import ui from trezor import ui
from trezor.ui.swipe import Swipe from trezor.ui.swipe import Swipe
from trezor import loop from trezor.utils import unimport_gen
from trezor.res import loadres from trezor.res import loadres
from trezor import dispatcher
from trezor import loop
from trezor import msg
def swipe_to_change_orientation(): def swipe_to_rotate():
while True: while True:
degrees = yield from Swipe().wait() degrees = yield from Swipe(absolute=True).wait()
ui.display.orientation(degrees) ui.display.orientation(degrees)
def layout_homescreen(): def animate_logo():
print("Homescreen layout!")
def func(foreground): def func(foreground):
ui.display.icon(0, 0, loadres('apps/homescreen/res/trezor.toig'), foreground, ui.BLACK) ui.display.icon(0, 0, loadres('apps/homescreen/res/trezor.toig'), foreground, ui.BLACK)
yield from ui.animate_pulse(func, ui.WHITE, ui.GREY, speed=400000)
orientation = swipe_to_change_orientation()
animation = ui.animate_pulse(func, ui.WHITE, ui.GREY, speed=400000)
timeout = loop.Sleep(5000 * 1000)
yield loop.Wait([ @unimport_gen
orientation, def layout_homescreen(initialize_msg=None):
animation, if initialize_msg is not None:
timeout from trezor.messages.Features import Features
]) features = Features()
features.revision = 'deadbeef'
from apps import playground features.bootloader_hash = 'deadbeef'
return playground.layout_tap_to_confirm('1BitkeyP2nDd5oa64x7AjvBbbwST54W5Zmx2', 110.126967, 'BTC') features.device_id = 'DEADBEEF'
features.coins = []
features.imported = False
features.initialized = True
features.label = 'My TREZOR'
features.major_version = 2
features.minor_version = 0
features.patch_version = 0
features.pin_cached = False
features.pin_protection = True
features.passphrase_cached = False
features.passphrase_protection = False
features.vendor = 'bitcointrezor.com'
msg.write_msg(features)
yield loop.Wait([dispatcher.dispatch(),
swipe_to_rotate(),
animate_logo()])

View File

@ -0,0 +1,12 @@
from trezor.dispatcher import register
from trezor.messages.GetPublicKey import GetPublicKey
def dispatch(message):
if message.message_type is GetPublicKey:
from .layout_get_public_key import layout_get_public_key
return layout_get_public_key(message)
def boot():
register(GetPublicKey, dispatch)

View File

@ -0,0 +1,26 @@
from trezor import msg
from trezor import ui
from trezor.ui.button import Button, CONFIRM_BUTTON, CONFIRM_BUTTON_ACTIVE
from trezor.ui.pin import PinDialog
from trezor.utils import unimport_gen
@unimport_gen
def layout_get_public_key(message):
confirm = Button((0, 0, 240, 240), 'Export public key?',
normal_style=CONFIRM_BUTTON,
active_style=CONFIRM_BUTTON_ACTIVE)
yield from confirm.wait()
from trezor.messages.PublicKey import PublicKey
from trezor.messages.HDNodeType import HDNodeType
pubkey = PublicKey()
pubkey.node = HDNodeType()
pubkey.node.depth = 0
pubkey.node.child_num = 0
pubkey.node.fingerprint = 0
pubkey.node.chain_code = 'deadbeef'
pubkey.node.public_key = 'deadbeef'
msg.write_msg(pubkey)

View File

@ -2,14 +2,14 @@ import trezor.main
from trezor import msg from trezor import msg
# Load all applications # Load all applications
from apps import homescreen
from apps import playground from apps import playground
# from apps import wallet from apps import homescreen
from apps import wallet
# Initialize all applications # Initialize all applications
homescreen.boot()
playground.boot() playground.boot()
# wallet.boot() homescreen.boot()
wallet.boot()
# just a demo to show how to register USB ifaces # just a demo to show how to register USB ifaces
msg.setup( [ (1, 0xF53C), (2, 0xF1D0) ] ) msg.setup( [ (1, 0xF53C), (2, 0xF1D0) ] )

20
src/trezor/dispatcher.py Normal file
View File

@ -0,0 +1,20 @@
from . import msg
from . import layout
message_handlers = {}
def register(message_type, handler):
message_handlers[message_type] = handler
def unregister(message_type):
del message_handlers[message_type]
def dispatch():
mtypes = message_handlers.keys()
message = yield from msg.read_msg(*mtypes)
handler = message_handlers[message.message_type]
layout.change(handler(message))

View File

@ -1,44 +1,33 @@
import sys
import utime import utime
from . import log from . import log
from . import utils from . import utils
_new_layout = None
_current_layout = None class ChangeLayoutException(Exception):
def __init__(self, layout):
self.layout = layout
def change(layout): def change(layout):
global _new_layout raise ChangeLayoutException(layout)
log.debug(__name__, "Changing layout to %s", layout)
_new_layout = layout
yield _current_layout.throw(StopIteration())
def set_main(main_layout): def set_main(main_layout):
global _new_layout layout = main_layout()
global _current_layout
_current_layout = main_layout()
while True: while True:
try: try:
_current_layout = yield from _current_layout layout = yield from layout
except ChangeLayoutException as e:
layout = e.layout
except Exception as e: except Exception as e:
sys.print_exception(e) log.exception(__name__, e)
utime.sleep(1) # Don't produce wall of exceptions utime.sleep(1) # Don't produce wall of exceptions
# if _current_layout == main_layout:
# # Main layout thrown exception, what to do?
# sys.exit()
_current_layout = main_layout()
continue
if _new_layout != None: if not isinstance(layout, utils.type_gen):
log.info(__name__, "Switching to new layout %s", _new_layout) log.info(__name__, 'Switching to main layout %s', main_layout)
_current_layout = _new_layout layout = main_layout()
_new_layout = None
elif type(_current_layout) != utils.type_gen:
log.info(__name__, "Switching to main layout %s", main_layout)
_current_layout = main_layout()
else: else:
log.info(__name__, "Switching to proposed layout %s", _current_layout) log.info(__name__, 'Switching to proposed layout %s', layout)

View File

@ -73,31 +73,39 @@ class Wait():
self.gens = gens self.gens = gens
self.wait_for = wait_for self.wait_for = wait_for
self.exit_others = exit_others self.exit_others = exit_others
self.received = 0 self.scheduled = []
self.scheduled = None self.finished = []
self.callback = None self.callback = None
def handle(self, gen): def handle(self, gen):
self.scheduled = [schedule(self._wait(g)) for g in self.gens] self.scheduled = [schedule(self._wait(gen)) for gen in self.gens]
self.callback = gen self.callback = gen
def exit(self):
for gen in self.scheduled:
if gen not in self.finished and isinstance(gen, type_gen):
unschedule(gen)
unblock(gen)
gen.close()
def _wait(self, gen): def _wait(self, gen):
if isinstance(gen, type_gen): try:
result = yield from gen if isinstance(gen, type_gen):
result = yield from gen
else:
result = yield gen
except Exception as exc:
self._finish(gen, exc)
else: else:
result = yield gen self._finish(gen, result)
self._finish(gen, result)
def _finish(self, gen, result): def _finish(self, gen, result):
self.received += 1 self.finished.append(gen)
if self.received == self.wait_for: if self.wait_for == len(self.finished) or isinstance(result, Exception):
schedule(self.callback, (gen, result))
if self.exit_others: if self.exit_others:
for g in self.scheduled: self.exit()
if g is not gen and isinstance(g, type_gen): schedule(self.callback, result)
unschedule(g) self.callback = None
unblock(g)
g.close()
def run_forever(): def run_forever():
@ -140,7 +148,10 @@ def run_forever():
continue continue
try: try:
result = gen.send(data) if isinstance(data, Exception):
result = gen.throw(data)
else:
result = gen.send(data)
except StopIteration as e: except StopIteration as e:
log.debug(__name__, '%s finished', gen) log.debug(__name__, '%s finished', gen)
continue continue

View File

@ -62,3 +62,16 @@ def animate_pulse(func, ca, cb, speed=200000, delay=30000):
c = blend(ca, cb, y) c = blend(ca, cb, y)
func(c) func(c)
yield loop.Sleep(delay) yield loop.Sleep(delay)
def rotate_coords(pos: tuple) -> tuple:
r = display.orientation()
if r == 0:
return pos
x, y = pos
if r == 90:
return (240 - y, x)
if r == 180:
return (240 - x, 240 - y)
if r == 270:
return (y, 240 - x)

View File

@ -1,4 +1,4 @@
from . import display, in_area from . import display, in_area, rotate_coords
from trezor import ui from trezor import ui
from trezor import loop from trezor import loop
@ -51,13 +51,12 @@ BTN_DIRTY = const(4)
class Button(): class Button():
def __init__(self, area, text, normal_style=None, active_style=None, absolute=False):
def __init__(self, area, text, normal_style=None, active_style=None):
self.area = area self.area = area
self.text = text self.text = text
self.normal_style = normal_style or DEFAULT_BUTTON self.normal_style = normal_style or DEFAULT_BUTTON
self.active_style = active_style or DEFAULT_BUTTON_ACTIVE self.active_style = active_style or DEFAULT_BUTTON_ACTIVE
self.absolute = absolute
self.state = BTN_DIRTY self.state = BTN_DIRTY
def render(self): def render(self):
@ -77,6 +76,8 @@ class Button():
self.state = state self.state = state
def send(self, event, pos): def send(self, event, pos):
if not self.absolute:
pos = rotate_coords(pos)
if event is loop.TOUCH_START: if event is loop.TOUCH_START:
if in_area(pos, self.area): if in_area(pos, self.area):
self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE self.state = BTN_STARTED | BTN_DIRTY | BTN_ACTIVE
@ -91,3 +92,13 @@ class Button():
self.state = BTN_DIRTY self.state = BTN_DIRTY
if in_area(pos, self.area): if in_area(pos, self.area):
return BTN_CLICKED return BTN_CLICKED
def wait(self):
while True:
self.render()
event, *pos = yield loop.Select(loop.TOUCH_START,
loop.TOUCH_MOVE,
loop.TOUCH_END)
result = self.send(event, pos)
if result is not None:
return result

View File

@ -1,6 +1,6 @@
import utime import utime
from . import in_area from . import in_area, rotate_coords
from trezor import loop from trezor import loop
@ -16,8 +16,9 @@ SWIPE_RIGHT = const(270)
class Swipe(): class Swipe():
def __init__(self, area=None): def __init__(self, area=None, absolute=False):
self.area = area or (0, 0, 240, 240) self.area = area or (0, 0, 240, 240)
self.absolute = absolute
self.start_pos = None self.start_pos = None
self.start_time = 0 self.start_time = 0
self.end_pos = None self.end_pos = None
@ -25,6 +26,9 @@ class Swipe():
def send(self, event, pos): def send(self, event, pos):
if not self.absolute:
pos = rotate_coords(pos)
if event is loop.TOUCH_START and in_area(pos, self.area): if event is loop.TOUCH_START and in_area(pos, self.area):
self.start_time = utime.time() self.start_time = utime.time()
self.start_pos = pos self.start_pos = pos