async def alert(count: int = 3) -> None: short_sleep = loop.sleep(20000) long_sleep = loop.sleep(80000) for i in range(count * 2): if i % 2 == 0: display.backlight(style.BACKLIGHT_MAX) await short_sleep else: display.backlight(style.BACKLIGHT_DIM) await long_sleep display.backlight(style.BACKLIGHT_NORMAL)
async def alert(count: int = 3): short_sleep = loop.sleep(20000) long_sleep = loop.sleep(80000) current = display.backlight() for i in range(count * 2): if i % 2 == 0: display.backlight(BACKLIGHT_MAX) yield short_sleep else: display.backlight(BACKLIGHT_NORMAL) yield long_sleep display.backlight(current)
async def _alert(count: int) -> None: short_sleep = loop.sleep(20) long_sleep = loop.sleep(80) for i in range(count * 2): if i % 2 == 0: display.backlight(style.BACKLIGHT_MAX) await short_sleep else: display.backlight(style.BACKLIGHT_DIM) await long_sleep display.backlight(style.BACKLIGHT_NORMAL) global _alert_in_progress _alert_in_progress = False
def __iter__(self): sleep = loop.sleep(1000000 // 30) # 30 fps ui.display.bar(0, 32, 240, 240 - 80, ui.BG) # clear while self.is_active(): self.render() yield sleep ui.display.bar(0, 32, 240, 240 - 80, ui.BG) # clear
def __iter__(self): sleep = loop.sleep(1000000 // 30) # 30 fps ui.display.bar(0, 32, ui.WIDTH, ui.HEIGHT - 83, ui.BG) # clear while self.is_active(): self.render() yield sleep ui.display.bar(0, 32, ui.WIDTH, ui.HEIGHT - 83, ui.BG) # clear
async def __iter__(self): timeout = loop.sleep(1000 * 1000 * 1) touch = loop.select(io.TOUCH) wait_timeout = loop.wait(touch, timeout) wait_touch = loop.wait(touch) content = None self.back.taint() self.input.taint() while content is None: self.render() if self.pbutton is not None: wait = wait_timeout else: wait = wait_touch result = await wait if touch in wait.finished: event, *pos = result content = self.touch(event, pos) else: if self.input.word: # just reset the pending state self.edit(self.input.content) else: # invalid character, backspace it self.edit(self.input.content[:-1]) return content
async def memory_stats(interval): import micropython import gc sleep = loop.sleep(interval * 1000 * 1000) while True: micropython.mem_info() gc.collect() await sleep
async def animate_swipe(): time_delay = const(40000) draw_delay = const(200000) sleep = loop.sleep(time_delay) for t in ui.pulse(draw_delay): fg = ui.blend(ui.GREY, ui.DARK_GREY, t) ui.display.icon(110, 210, res.load(ui.ICON_SWIPE), fg, ui.BG) await sleep
def handle_rendering(self) -> loop.Task: # type: ignore backlight_fade(style.BACKLIGHT_DIM) display.clear() self.dispatch(RENDER, 0, 0) display.refresh() backlight_fade(style.BACKLIGHT_NORMAL) sleep = loop.sleep(_RENDER_DELAY_US) while True: self.dispatch(RENDER, 0, 0) yield sleep
async def animate_swipe(): time_delay = const(40000) draw_delay = const(200000) ui.display.text_center(130, 220, 'Swipe', ui.BOLD, ui.GREY, ui.BG) sleep = loop.sleep(time_delay) icon = res.load(ui.ICON_SWIPE) for t in ui.pulse(draw_delay): fg = ui.blend(ui.GREY, ui.DARK_GREY, t) ui.display.icon(70, 205, icon, fg, ui.BG) yield sleep
def __iter__(self): timeout = loop.sleep(1000 * 1000 * 1) touch = loop.select(io.TOUCH) wait = loop.wait(touch, timeout) while True: self.render() result = yield wait if touch in wait.finished: event, *pos = result self.touch(event, pos) elif self.zoom_buttons: self.zoom_buttons = None for btn in self.key_buttons: btn.taint()
def __iter__(self): timeout = loop.sleep(1000 * 1000 * 1) touch = loop.select(io.TOUCH) wait = loop.wait(touch, timeout) while True: self.render() result = yield wait if touch in wait.finished: event, *pos = result self.touch(event, pos) else: self.pending_button = None self.pending_index = 0 self._update_suggestion() self._update_buttons()
async def handle_input(self) -> None: touch = loop.wait(io.TOUCH) timeout = loop.sleep(1000) race_touch = loop.race(touch) race_timeout = loop.race(touch, timeout) while True: if self.pending_button is not None: race = race_timeout else: race = race_touch result = await race if touch in race.finished: event, x, y = result self.dispatch(event, x, y) else: self.on_timeout()
async def handle_input(self): touch = loop.wait(io.TOUCH) timeout = loop.sleep(1000 * 1000 * 1) spawn_touch = loop.spawn(touch) spawn_timeout = loop.spawn(touch, timeout) while True: if self.pending_button is not None: spawn = spawn_timeout else: spawn = spawn_touch result = await spawn if touch in spawn.finished: event, x, y = result self.dispatch(event, x, y) else: self.on_timeout()
async def enter_text(self): timeout = loop.sleep(1000 * 1000 * 1) touch = loop.wait(io.TOUCH) wait_timeout = loop.spawn(touch, timeout) wait_touch = loop.spawn(touch) content = None while content is None: self.render() if self.pbutton is not None: wait = wait_timeout else: wait = wait_touch result = await wait if touch in wait.finished: event, *pos = result content = self.touch(event, pos) else: # disable the pending buttons self.edit(self.input.content) return content
def handle_rendering(self) -> loop.Task: # type: ignore """Task that is rendering the layout in a busy loop.""" # Before the first render, we dim the display. backlight_fade(style.BACKLIGHT_DIM) # Clear the screen of any leftovers, make sure everything is marked for # repaint (we can be running the same layout instance multiple times) # and paint it. display.clear() self.dispatch(REPAINT, 0, 0) self.dispatch(RENDER, 0, 0) # Display is usually refreshed after every loop step, but here we are # rendering everything synchronously, so refresh it manually and turn # the brightness on again. refresh() backlight_fade(style.BACKLIGHT_NORMAL) sleep = loop.sleep(_RENDER_DELAY_US) while True: # Wait for a couple of ms and render the layout again. Because # components use re-paint marking, they do not really draw on the # display needlessly. Using `yield` instead of `await` to avoid allocations. # TODO: remove the busy loop yield sleep self.dispatch(RENDER, 0, 0)
def handle_timeout(self): yield loop.sleep(self.time_ms * 1000) raise ui.Result(None)
def handle_timeout(self) -> loop.Task: # type: ignore yield loop.sleep(self.time_ms) raise ui.Result(None)
async def backlight_slide(val: int, delay: int = 20000, step: int = 1): sleep = loop.sleep(delay) current = display.backlight() for i in range(current, val, -step if current > val else step): display.backlight(i) await sleep
def __iter__(self): sleep = loop.sleep(1000000 // 60) # 60 fps while self.is_active(): self.render() yield sleep
class Layout(Component): """ Abstract class. Layouts are top-level components. Only one layout can be running at the same time. Layouts provide asynchronous interface, so a running task can wait for the layout to complete. Layouts complete when a `Result` is raised, usually from some of the child components. """ BACKLIGHT_LEVEL = style.BACKLIGHT_NORMAL RENDER_SLEEP = loop.sleep(_RENDER_DELAY_MS) # type: loop.Syscall async def __iter__(self) -> ResultValue: """ Run the layout and wait until it completes. Returns the result value. Usually not overridden. """ if __debug__: # we want to call notify_layout_change() when the rendering is done; # but only the first time the layout is awaited. Here we indicate that we # are being awaited, and in handle_rendering() we send the appropriate event self.should_notify_layout_change = True value = None try: # If any other layout is running (waiting on the layout channel), # we close it with the Cancelled exception, and wait until it is # closed, just to be sure. if layout_chan.takers: await layout_chan.put(Cancelled()) # Now, no other layout should be running. In a loop, we create new # layout tasks and execute them in parallel, while waiting on the # layout channel. This allows other layouts to cancel us, and the # layout tasks to trigger restart by exiting (new tasks are created # and we continue, because we are in a loop). while True: await loop.race(layout_chan.take(), *self.create_tasks()) except Result as result: # Result exception was raised, this means this layout is complete. value = result.value return value def __await__(self) -> Generator[Any, Any, ResultValue]: return self.__iter__() # type: ignore def create_tasks(self) -> Tuple[loop.Task, ...]: """ Called from `__iter__`. Creates and returns a sequence of tasks that run this layout. Tasks are executed in parallel. When one of them returns, the others are closed and `create_tasks` is called again. Usually overridden to add another tasks to the list.""" return self.handle_input(), self.handle_rendering() def handle_input(self) -> loop.Task: # type: ignore """Task that is waiting for the user input.""" touch = loop.wait(io.TOUCH) while True: # Using `yield` instead of `await` to avoid allocations. event, x, y = yield touch workflow.idle_timer.touch() self.dispatch(event, x, y) # We dispatch a render event right after the touch. Quick and dirty # way to get the lowest input-to-render latency. self.dispatch(RENDER, 0, 0) def handle_rendering(self) -> loop.Task: # type: ignore """Task that is rendering the layout in a busy loop.""" # Before the first render, we dim the display. backlight_fade(style.BACKLIGHT_DIM) # Clear the screen of any leftovers, make sure everything is marked for # repaint (we can be running the same layout instance multiple times) # and paint it. display.clear() self.dispatch(REPAINT, 0, 0) self.dispatch(RENDER, 0, 0) if __debug__ and self.should_notify_layout_change: # notify about change and do not notify again until next await. # (handle_rendering might be called multiple times in a single await, # because of the endless loop in __iter__) self.should_notify_layout_change = False notify_layout_change(self) # Display is usually refreshed after every loop step, but here we are # rendering everything synchronously, so refresh it manually and turn # the brightness on again. refresh() backlight_fade(self.BACKLIGHT_LEVEL) sleep = self.RENDER_SLEEP while True: # Wait for a couple of ms and render the layout again. Because # components use re-paint marking, they do not really draw on the # display needlessly. Using `yield` instead of `await` to avoid allocations. # TODO: remove the busy loop yield sleep self.dispatch(RENDER, 0, 0)