From 8e5dae5a32c589daf0339ee0941ca199ffa11c29 Mon Sep 17 00:00:00 2001 From: Sebastian Krzyszkowiak <dos@dosowisko.net> Date: Wed, 20 Sep 2023 21:07:51 +0200 Subject: [PATCH] py,st3m: Move WiFi and LED state handling out of Application class Application class is the user's code, we shouldn't rely on it implementing system-level functionality as there are several ways for the user to accidentally break it. This isn't a perfect place for it either, but it's at least better than before. It's going to be revisited in the future, perhaps by giving each app their own ViewManager instance that could then properly track application's lifecycle. One functional difference is that st3m.wifi._onoff_wifi_update() is now being called when quitting any app, not just those that request a particular WiFi state in their config. --- python_payload/st3m/application.py | 59 ++++++++---------------------- python_payload/st3m/run.py | 39 ++++++++++++++++++-- 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/python_payload/st3m/application.py b/python_payload/st3m/application.py index d91306e3b3..da27f383be 100644 --- a/python_payload/st3m/application.py +++ b/python_payload/st3m/application.py @@ -2,7 +2,6 @@ from st3m.ui.view import ( BaseView, ViewTransitionSwipeLeft, ViewManager, - ViewTransitionDirection, ) from st3m.ui.menu import MenuItem from st3m.input import InputState @@ -50,51 +49,21 @@ class ApplicationContext: return self._bundle_metadata +def setup_for_app(app_ctx: Optional[ApplicationContext]) -> None: + if app_ctx and app_ctx.bundle_metadata and settings.onoff_wifi_preference.value: + wifi_preference = app_ctx.bundle_metadata["app"].get("wifi_preference") + if wifi_preference is True and not st3m.wifi.is_connected(): + st3m.wifi.setup_wifi() + elif wifi_preference is False: + st3m.wifi.disable() + leds.set_slew_rate(settings.num_leds_speed.value) + + class Application(BaseView): def __init__(self, app_ctx: ApplicationContext) -> None: self._app_ctx = app_ctx - if app_ctx and app_ctx.bundle_metadata and settings.onoff_wifi_preference.value: - self._wifi_preference = app_ctx.bundle_metadata["app"].get( - "wifi_preference" - ) - else: - self._wifi_preference = None super().__init__() - def on_enter(self, vm: Optional[ViewManager]) -> None: - # Try to connect/disconnect from wifi if requested by app - if self._wifi_preference is True and not st3m.wifi.is_connected(): - st3m.wifi.setup_wifi() - elif self._wifi_preference is False: - st3m.wifi.disable() - leds.set_slew_rate(settings.num_leds_speed.value) - super().on_enter(vm) - - def on_exit(self) -> None: - fully_exiting = self.vm.direction == ViewTransitionDirection.BACKWARD - # If the app requested to change wifi state - # fall back to system defaults on exit - if fully_exiting and self._wifi_preference is not None: - st3m.wifi._onoff_wifi_update() - super().on_exit() - # set the default graphics mode, this is a no-op if - # it is already set - if fully_exiting: - sys_display.set_mode(0) - if fully_exiting: - leds.set_slew_rate(100) - led_patterns.set_menu_colors() - - def on_exit_done(self): - fully_exiting = self.vm.direction == ViewTransitionDirection.BACKWARD - if fully_exiting: - leds.set_slew_rate(100) - led_patterns.set_menu_colors() - leds.update() - - def think(self, ins: InputState, delta_ms: int) -> None: - super().think(ins, delta_ms) - class BundleLoadException(BaseException): MSG = "failed to load" @@ -149,7 +118,7 @@ class BundleMetadata: This data is used to discover bundles and load them as applications. """ - __slots__ = ["path", "name", "menu", "_t", "version"] + __slots__ = ["path", "name", "menu", "_t", "version", "ctx"] def __init__(self, path: str) -> None: self.path = path.rstrip("/") @@ -188,6 +157,8 @@ class BundleMetadata: self._t = t + self.ctx = ApplicationContext(self.path, self._t) + @staticmethod def _sys_path_set(v: List[str]) -> None: # Can't just assign to sys.path in Micropython. @@ -221,7 +192,7 @@ class BundleMetadata: log.info(f"Loaded {self.name} module: {m}") klass = getattr(m, class_entry) log.info(f"Loaded {self.name} class: {klass}") - inst = klass(ApplicationContext(self.path, self._t)) + inst = klass(self.ctx) log.info(f"Instantiated {self.name} class: {inst}") return inst # type: ignore except Exception as e: @@ -350,6 +321,8 @@ class MenuItemAppLaunch(MenuItem): vm.push(err) return assert self._instance is not None + + setup_for_app(self._bundle.ctx) vm.push(self._instance, ViewTransitionSwipeLeft()) def label(self) -> str: diff --git a/python_payload/st3m/run.py b/python_payload/st3m/run.py index 8be8c1c9ef..54f259f9f3 100644 --- a/python_payload/st3m/run.py +++ b/python_payload/st3m/run.py @@ -9,17 +9,19 @@ from st3m.ui.menu import ( MenuItemLaunchPersistentView, ) from st3m.ui.elements import overlays -from st3m.ui.view import View, ViewManager, ViewTransitionBlend +from st3m.ui.view import View, ViewManager, ViewTransitionBlend, ViewTransitionDirection from st3m.ui.elements.menus import SimpleMenu, SunMenu from st3m.application import ( BundleManager, BundleMetadata, MenuItemAppLaunch, ApplicationContext, + setup_for_app, ) from st3m.about import About from st3m import settings_menu as settings, logging, processors, wifi from st3m import led_patterns +import st3m.wifi import captouch, audio, leds, gc, sys_buttons, sys_display, sys_mode import os @@ -60,13 +62,40 @@ def run_responder(r: Responder) -> None: reactor.run() +class ApplicationMenu(SimpleMenu): + def _restore_sys_defaults(self) -> None: + if ( + not self.vm + or not self.is_active() + or self.vm.direction != ViewTransitionDirection.BACKWARD + ): + return + # fall back to system defaults on app exit + st3m.wifi._onoff_wifi_update() + # set the default graphics mode, this is a no-op if + # it is already set + sys_display.set_mode(0) + leds.set_slew_rate(100) + led_patterns.set_menu_colors() + + def on_enter(self, vm: Optional[ViewManager]) -> None: + super().on_enter(vm) + self._restore_sys_defaults() + + def on_enter_done(self): + # set the defaults again in case the app continued + # doing stuff during the transition + self._restore_sys_defaults() + leds.update() + + def _make_bundle_menu(mgr: BundleManager, kind: str) -> SimpleMenu: entries: List[MenuItem] = [MenuItemBack()] ids = sorted(mgr.bundles.keys()) for id in ids: bundle = mgr.bundles[id] entries += bundle.menu_entries(kind) - return SimpleMenu(entries) + return ApplicationMenu(entries) def _make_compositor(reactor: Reactor, vm: ViewManager) -> overlays.Compositor: @@ -134,7 +163,9 @@ def run_view(v: View, debug_vm=True) -> None: def run_app(klass, bundle_path=None): - run_view(klass(ApplicationContext(bundle_path)), debug_vm=True) + app_ctx = ApplicationContext(bundle_path) + setup_for_app(app_ctx) + run_view(klass(app_ctx), debug_vm=True) def _yeet_local_changes() -> None: @@ -176,7 +207,7 @@ def run_main() -> None: log.error(f"Failed to set hostname {e}") menu_settings = settings.build_menu() - menu_system = SimpleMenu( + menu_system = ApplicationMenu( [ MenuItemBack(), MenuItemForeground("Settings", menu_settings), -- GitLab