Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
01311682cThis file is pinned to the selected release. Download the original to open it in your design tool.
##############################################################################
# Event Loop module: advancing tick count and scheduling lvgl task handler.
# Import after lvgl module.
# This should be imported and used by display driver.
# Display driver should first check if an event loop is already running.
#
# Usage example with SDL:
#
# SDL.init(auto_refresh=False)
# # Register SDL display driver.
# # Register SDL mouse driver
# event_loop = lv_utils.event_loop()
#
#
# uasyncio example with SDL:
#
# SDL.init(auto_refresh=False)
# # Register SDL display driver.
# # Register SDL mouse driver
# event_loop = lv_utils.event_loop(asynchronous=True)
# uasyncio.Loop.run_forever()
#
# uasyncio example with ili9341:
#
# event_loop = lv_utils.event_loop(asynchronous=True) # Optional!
# self.disp = ili9341(asynchronous=True)
# uasyncio.Loop.run_forever()
#
# MIT license; Copyright (c) 2021 Amir Gonnen
#
##############################################################################
import lvgl as lv
import micropython
import usys
# Try standard machine.Timer, or custom timer from lv_timer, if available
try:
from machine import Timer
except:
try:
from lv_timer import Timer
except:
raise RuntimeError("Missing machine.Timer implementation!")
# Try to determine default timer id
default_timer_id = 0
if usys.platform == 'pyboard':
# stm32 only supports SW timer -1
default_timer_id = -1
if usys.platform == 'rp2':
# rp2 only supports SW timer -1
default_timer_id = -1
# Try importing uasyncio, if available
try:
import uasyncio
uasyncio_available = True
except:
uasyncio_available = False
##############################################################################
class event_loop():
_current_instance = None
def __init__(self, freq=25, timer_id=default_timer_id, max_scheduled=2, refresh_cb=None, asynchronous=False, exception_sink=None):
if self.is_running():
raise RuntimeError("Event loop is already running!")
if not lv.is_initialized():
lv.init()
event_loop._current_instance = self
self.delay = 1000 // freq
self.refresh_cb = refresh_cb
self.exception_sink = exception_sink if exception_sink else self.default_exception_sink
self.asynchronous = asynchronous
if self.asynchronous:
if not uasyncio_available:
raise RuntimeError("Cannot run asynchronous event loop. uasyncio is not available!")
self.refresh_event = uasyncio.Event()
self.refresh_task = uasyncio.create_task(self.async_refresh())
self.timer_task = uasyncio.create_task(self.async_timer())
else:
self.timer = Timer(timer_id)
self.task_handler_ref = self.task_handler # Allocation occurs here
self.timer.init(mode=Timer.PERIODIC, period=self.delay, callback=self.timer_cb)
self.max_scheduled = max_scheduled
self.scheduled = 0
def deinit(self):
if self.asynchronous:
self.refresh_task.cancel()
self.timer_task.cancel()
else:
self.timer.deinit()
event_loop._current_instance = None
def disable(self):
self.scheduled += self.max_scheduled
def enable(self):
self.scheduled -= self.max_scheduled
@staticmethod
def is_running():
return event_loop._current_instance is not None
@staticmethod
def current_instance():
return event_loop._current_instance
def task_handler(self, _):
try:
if lv._nesting.value == 0:
lv.task_handler()
if self.refresh_cb: self.refresh_cb()
self.scheduled -= 1
except Exception as e:
if self.exception_sink:
self.exception_sink(e)
def timer_cb(self, t):
# Can be called in Interrupt context
# Use task_handler_ref since passing self.task_handler would cause allocation.
lv.tick_inc(self.delay)
if self.scheduled < self.max_scheduled:
try:
micropython.schedule(self.task_handler_ref, 0)
self.scheduled += 1
except:
pass
async def async_refresh(self):
while True:
await self.refresh_event.wait()
if lv._nesting.value == 0:
self.refresh_event.clear()
try:
lv.task_handler()
except Exception as e:
if self.exception_sink:
self.exception_sink(e)
if self.refresh_cb: self.refresh_cb()
async def async_timer(self):
while True:
await uasyncio.sleep_ms(self.delay)
lv.tick_inc(self.delay)
self.refresh_event.set()
def default_exception_sink(self, e):
usys.print_exception(e)
event_loop.current_instance().deinit()