1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-02 20:48:30 +00:00
trezor-firmware/src/trezor/loop.py

154 lines
3.7 KiB
Python
Raw Normal View History

import utime
2016-04-29 19:19:25 +00:00
from uheapq import heappop, heappush
from .utils import type_gen
2016-04-29 12:49:47 +00:00
from . import msg
2016-04-29 20:24:27 +00:00
from . import log
2016-05-05 12:28:10 +00:00
TOUCH_START = const(-1)
TOUCH_MOVE = const(-2)
TOUCH_END = const(-3)
MESSAGE = const(-4)
2016-04-29 19:19:25 +00:00
event_handlers = {
2016-05-05 12:28:10 +00:00
TOUCH_START: None,
TOUCH_MOVE: None,
TOUCH_END: None,
MESSAGE: None,
2016-04-30 13:57:08 +00:00
}
2016-04-29 19:19:25 +00:00
time_queue = []
if __debug__:
# For performance stats
import array
log_delay_pos = 0
log_delay_rb_len = const(10)
log_delay_rb = array.array('i', [0] * log_delay_rb_len)
def __schedule(gen, args=(), time=None):
if __debug__:
2016-04-29 23:20:57 +00:00
log.debug(__name__, 'Scheduling %s %s', time, gen)
if not time:
time = utime.ticks_us()
2016-05-03 16:58:10 +00:00
heappush(time_queue, (time, gen, args))
2016-04-29 23:20:57 +00:00
2016-05-02 14:06:08 +00:00
class Wait():
def __init__(self, gens, wait_for=1, exit_others=True):
self.wait_for = wait_for
self.exit_others = exit_others
self.received = 0
self.callback = None
self.gens = gens
for g in gens:
2016-05-03 16:58:10 +00:00
__schedule(self._wait(g))
2016-05-02 14:06:08 +00:00
def _wait(self, gen):
if isinstance(gen, type_gen):
ret = yield from gen
else:
ret = yield gen
2016-04-29 23:20:57 +00:00
2016-05-02 14:06:08 +00:00
self.finish(gen, ret)
2016-04-29 23:20:57 +00:00
2016-05-02 14:06:08 +00:00
def finish(self, gen, result):
self.received += 1
2016-04-30 13:57:08 +00:00
2016-05-02 14:21:50 +00:00
if self.received == self.wait_for:
__schedule(self.callback, (gen, result))
2016-05-02 14:06:08 +00:00
self.callback = None
2016-05-02 14:06:08 +00:00
if self.exit_others:
for g in self.gens:
try:
g.throw(StopIteration())
except:
pass
def sleep(us):
return utime.ticks_us() + us
2016-04-29 19:19:25 +00:00
def run_forever(start_gens):
if __debug__:
global log_delay_pos
global log_delay_rb
global log_delay_rb_len
2016-04-29 19:19:25 +00:00
delay_max = const(1000000)
for gen in start_gens:
2016-05-03 16:58:10 +00:00
__schedule(gen)
2016-04-29 19:19:25 +00:00
while True:
if time_queue:
t, _, _ = time_queue[0]
2016-04-29 19:19:25 +00:00
delay = t - utime.ticks_us()
else:
delay = delay_max
if __debug__:
# Adding current delay to ring buffer for performance stats
log_delay_rb[log_delay_pos] = delay
log_delay_pos = (log_delay_pos + 1) % log_delay_rb_len
event = msg.select(delay)
2016-04-29 19:19:25 +00:00
if event:
# Run interrupt handler
event_id, *args = event
event_id = -event_id
gen = event_handlers.get(event_id, None)
event_handlers[event_id] = None
if not gen:
log.info(__name__, 'No handler for event: %s', event)
continue
2016-04-29 19:19:25 +00:00
else:
if time_queue:
# Run something from the time queue
_, gen, args = heappop(time_queue)
else:
# Sleep again
delay = delay_max
continue
2016-04-29 19:19:25 +00:00
if not args:
args = None
2016-04-29 19:19:25 +00:00
try:
ret = gen.send(args)
2016-04-30 13:57:08 +00:00
2016-04-29 19:19:25 +00:00
except StopIteration as e:
log.debug(__name__, '%s finished', gen)
2016-04-29 19:19:25 +00:00
continue
2016-04-30 13:57:08 +00:00
2016-04-29 23:20:57 +00:00
except Exception as e:
log.exception(__name__, e)
2016-04-29 23:20:57 +00:00
continue
2016-04-29 19:19:25 +00:00
if isinstance(ret, int) and ret >= 0:
# Sleep until ret, call us later
__schedule(gen, (), ret)
elif isinstance(ret, int) and ret in event_handlers:
# Wait for event
if event_handlers[ret]:
event_handlers[ret].close()
event_handlers[ret] = gen
2016-04-29 19:19:25 +00:00
2016-05-02 14:06:08 +00:00
elif isinstance(ret, Wait):
# Register the origin generator as a waiting callback
2016-05-02 14:06:08 +00:00
ret.callback = gen
2016-04-30 13:57:08 +00:00
2016-04-29 19:19:25 +00:00
elif ret is None:
# Just call us asap
2016-05-03 16:58:10 +00:00
__schedule(gen)
2016-04-29 23:20:57 +00:00
2016-04-30 13:57:08 +00:00
else:
raise Exception('Unhandled result %s by %s' % (ret, gen))