diff --git a/lib/pysquared/pysquared.py b/lib/pysquared/pysquared.py index 24e07cd9..6f3ce938 100644 --- a/lib/pysquared/pysquared.py +++ b/lib/pysquared/pysquared.py @@ -8,7 +8,6 @@ """ # Common CircuitPython Libs -import asyncio # Add asyncio import import sys import time from collections import OrderedDict @@ -578,38 +577,11 @@ def date(self, ymdw: tuple[int, int, int, int]) -> None: """ def watchdog_pet(self) -> None: - """Pet the watchdog timer""" - self.logger.debug("Petting watchdog") self.watchdog_pin.value = True time.sleep(0.01) self.watchdog_pin.value = False - async def _watchdog_pet_task(self) -> None: - """Async task to continuously pet the watchdog""" - self.logger.info("Starting watchdog petting background task") - while self.hardware.get("WDT", False): - self.watchdog_pet() - await asyncio.sleep(1.0) # Pet watchdog every second - self.logger.info("Watchdog petting task stopped") - - def start_watchdog_background_task(self) -> None: - """Start the watchdog petting as a true background task using asyncio""" - self._last_watchdog_pet = time.monotonic() - self.hardware["WDT"] = True - # Create and schedule the task but don't wait for it - asyncio.create_task(self._watchdog_pet_task()) - self.logger.info("Watchdog background task created") - - def check_watchdog(self) -> None: - """ - Legacy method maintained for compatibility - The actual petting is now handled by the background task - """ - pass # No-op as this is now handled by the async task - def check_reboot(self) -> None: - """Check if system needs to be rebooted""" - # No need to check watchdog anymore as it's handled by the background task self.UPTIME: int = self.get_system_uptime self.logger.debug("Current up time stat:", uptime=self.UPTIME) if self.UPTIME > self.reboot_time: diff --git a/main.py b/main.py index 94b9256b..6a357909 100644 --- a/main.py +++ b/main.py @@ -8,7 +8,7 @@ Published: Nov 19, 2024 """ -import asyncio +import gc import time import digitalio @@ -53,10 +53,7 @@ config: Config = Config("config.json") c = pysquared.Satellite(config, logger, __version__) - - # Start the watchdog background task - c.start_watchdog_background_task() - + c.watchdog_pet() sleep_helper = SleepHelper(c, logger) radio_manager = RFM9xManager( @@ -72,107 +69,109 @@ f = functions.functions(c, logger, config, sleep_helper, radio_manager) - async def initial_boot(): + def initial_boot(): + c.watchdog_pet() f.beacon() + c.watchdog_pet() f.listen() + c.watchdog_pet() - async def critical_power_operations(): - await initial_boot() - # Convert blocking operation to a non-blocking one using run_in_executor - # Since this is a blocking function that will likely put the device to sleep, - # we accept that this will block the event loop as intended - logger.info("Entering long hibernation (this will block the event loop)") - sleep_helper.long_hibernate() - logger.info("Woke from long hibernation") + try: + c.boot_count.increment() - async def minimum_power_operations(): - await initial_boot() - # Same as above - this is a blocking operation by design - logger.info("Entering short hibernation (this will block the event loop)") - sleep_helper.short_hibernate() - logger.info("Woke from short hibernation") + logger.info( + "FC Board Stats", + bytes_remaining=gc.mem_free(), + boot_number=c.boot_count.get(), + ) + + initial_boot() + + except Exception as e: + logger.error("Error in Boot Sequence", e) - async def send_imu_data(): + finally: + pass + + def send_imu_data(): logger.info("Looking to get imu data...") IMUData = [] + c.watchdog_pet() + logger.info("IMU has baton") IMUData = f.get_imu_data() + c.watchdog_pet() f.send(IMUData) - async def main(): + def main(): f.beacon() + f.listen_loiter() + f.state_of_health() + f.listen_loiter() + f.all_face_data() + c.watchdog_pet() f.send_face() + f.listen_loiter() - await send_imu_data() + + send_imu_data() + f.listen_loiter() + f.joke() + f.listen_loiter() + def critical_power_operations(): + initial_boot() + c.watchdog_pet() + + sleep_helper.long_hibernate() + + def minimum_power_operations(): + initial_boot() + c.watchdog_pet() + + sleep_helper.short_hibernate() + ######################### MAIN LOOP ############################## - async def main_loop(): - """Async main loop that runs alongside the watchdog task""" - try: - while True: - # L0 automatic tasks no matter the battery level - c.check_reboot() # Now this only checks for reboot conditions - - if c.power_mode == "critical": - c.rgb = (0, 0, 0) - await critical_power_operations() - - elif c.power_mode == "minimum": - c.rgb = (255, 0, 0) - await minimum_power_operations() - - elif c.power_mode == "normal": - c.rgb = (255, 255, 0) - await main() - - elif c.power_mode == "maximum": - c.rgb = (0, 255, 0) - await main() - - else: - f.listen() - - # Small yield to allow other tasks to run - await asyncio.sleep(0.1) - - except Exception as e: - logger.critical("Critical in Main Loop", e) - time.sleep(10) - microcontroller.on_next_reset(microcontroller.RunMode.NORMAL) - microcontroller.reset() - finally: - logger.info("Going Neutral!") - c.rgb = (0, 0, 0) - c.hardware["WDT"] = False - - # Set up the asyncio event loop - async def run_tasks(): - # The watchdog task is already started by c.start_watchdog_background_task() - # Just run the main loop as a task - main_task = asyncio.create_task(main_loop()) - - try: - # Wait for the main task to complete (it should run forever) - await main_task - except asyncio.CancelledError: - logger.info("Main task was cancelled") - except Exception as e: - logger.critical("Error in run_tasks", e) - raise - - # Run the asyncio event loop try: - asyncio.run(run_tasks()) + while True: + # L0 automatic tasks no matter the battery level + c.check_reboot() + + if c.power_mode == "critical": + c.rgb = (0, 0, 0) + critical_power_operations() + + elif c.power_mode == "minimum": + c.rgb = (255, 0, 0) + minimum_power_operations() + + elif c.power_mode == "normal": + c.rgb = (255, 255, 0) + main() + + elif c.power_mode == "maximum": + c.rgb = (0, 255, 0) + main() + + else: + f.listen() + except Exception as e: - logger.critical("Error in asyncio.run", e) + logger.critical("Critical in Main Loop", e) + time.sleep(10) microcontroller.on_next_reset(microcontroller.RunMode.NORMAL) microcontroller.reset() + finally: + logger.info("Going Neutral!") + + c.rgb = (0, 0, 0) + c.hardware["WDT"] = False except Exception as e: logger.critical("An exception occured within main.py", e)