Merge pull request 'misc-stability-improvements' (#56) from misc-stability-improvements into main
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 4m36s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 10s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 5s
Run unit tests on host / Run-Unit-Tests (push) Successful in 7s
Run pytests / Check-Pytest (push) Successful in 10s
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 4m36s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 10s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 5s
Run unit tests on host / Run-Unit-Tests (push) Successful in 7s
Run pytests / Check-Pytest (push) Successful in 10s
Reviewed-on: #56 Reviewed-by: Stefan Kratochwil <kratochwil-la@gmx.de>
This commit was merged in pull request #56.
This commit is contained in:
@@ -53,6 +53,13 @@ def setup_wifi():
|
|||||||
print(f"ifconfig: {wlan.ifconfig()}")
|
print(f"ifconfig: {wlan.ifconfig()}")
|
||||||
|
|
||||||
|
|
||||||
|
async def wdt_task(wdt):
|
||||||
|
# TODO: more checking of app health
|
||||||
|
# Right now this only protects against the asyncio executor crashing completely
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep_ms(500)
|
||||||
|
wdt.feed()
|
||||||
|
|
||||||
DB_PATH = '/sd/tonberry.db'
|
DB_PATH = '/sd/tonberry.db'
|
||||||
|
|
||||||
config = Configuration()
|
config = Configuration()
|
||||||
@@ -97,8 +104,10 @@ def run():
|
|||||||
|
|
||||||
start_webserver(config, the_app)
|
start_webserver(config, the_app)
|
||||||
# Start
|
# Start
|
||||||
|
wdt = machine.WDT(timeout=1000)
|
||||||
asyncio.create_task(aiorepl.task({'timer_manager': TimerManager(),
|
asyncio.create_task(aiorepl.task({'timer_manager': TimerManager(),
|
||||||
'app': the_app}))
|
'app': the_app}))
|
||||||
|
asyncio.create_task(wdt_task(wdt))
|
||||||
asyncio.get_event_loop().run_forever()
|
asyncio.get_event_loop().run_forever()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Copyright (c) 2025 Matthias Blankertz <matthias@blankertz.org>
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
|
from utils import safe_callback
|
||||||
|
|
||||||
from mfrc522 import MFRC522
|
from mfrc522 import MFRC522
|
||||||
try:
|
try:
|
||||||
@@ -74,7 +75,7 @@ class Nfc:
|
|||||||
self.last_uid = uid
|
self.last_uid = uid
|
||||||
self.last_uid_timestamp = time.ticks_us()
|
self.last_uid_timestamp = time.ticks_us()
|
||||||
if self.cb is not None and last_callback_uid != uid:
|
if self.cb is not None and last_callback_uid != uid:
|
||||||
self.cb.onTagChange(uid)
|
safe_callback(lambda: self.cb.onTagChange(uid), "nfc tag change")
|
||||||
last_callback_uid = uid
|
last_callback_uid = uid
|
||||||
|
|
||||||
await asyncio.sleep_ms(poll_interval_ms)
|
await asyncio.sleep_ms(poll_interval_ms)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
# Copyright (c) 2025 Matthias Blankertz <matthias@blankertz.org>
|
# Copyright (c) 2025 Matthias Blankertz <matthias@blankertz.org>
|
||||||
|
|
||||||
|
from utils.helpers import safe_callback
|
||||||
from utils.buttons import Buttons
|
from utils.buttons import Buttons
|
||||||
from utils.config import Configuration
|
from utils.config import Configuration
|
||||||
from utils.leds import LedManager
|
from utils.leds import LedManager
|
||||||
@@ -11,4 +12,4 @@ from utils.sdcontext import SDContext
|
|||||||
from utils.timer import TimerManager
|
from utils.timer import TimerManager
|
||||||
|
|
||||||
__all__ = ["BTreeDB", "BTreeFileManager", "Buttons", "Configuration", "get_pin_index", "LedManager", "MBRPartition",
|
__all__ = ["BTreeDB", "BTreeFileManager", "Buttons", "Configuration", "get_pin_index", "LedManager", "MBRPartition",
|
||||||
"SDContext", "TimerManager"]
|
"safe_callback", "SDContext", "TimerManager"]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import asyncio
|
|||||||
import machine
|
import machine
|
||||||
import micropython
|
import micropython
|
||||||
import time
|
import time
|
||||||
|
from utils import safe_callback
|
||||||
try:
|
try:
|
||||||
from typing import TYPE_CHECKING # type: ignore
|
from typing import TYPE_CHECKING # type: ignore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -74,4 +75,4 @@ class Buttons:
|
|||||||
await self.int_flag.wait()
|
await self.int_flag.wait()
|
||||||
while len(self.pressed) > 0:
|
while len(self.pressed) > 0:
|
||||||
what = self.pressed.pop()
|
what = self.pressed.pop()
|
||||||
self.cb.onButtonPressed(what)
|
safe_callback(lambda: self.cb.onButtonPressed(what), "button callback")
|
||||||
|
|||||||
12
software/src/utils/helpers.py
Normal file
12
software/src/utils/helpers.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# Copyright (c) 2025 Matthias Blankertz <matthias@blankertz.org>
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def safe_callback(func, name="callback"):
|
||||||
|
try:
|
||||||
|
func()
|
||||||
|
except Exception as ex:
|
||||||
|
print(f"Uncaught exception in {name}")
|
||||||
|
sys.print_exception(ex)
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import heapq
|
import heapq
|
||||||
import time
|
import time
|
||||||
|
from utils import safe_callback
|
||||||
|
|
||||||
TIMER_DEBUG = True
|
TIMER_DEBUG = True
|
||||||
|
|
||||||
@@ -49,28 +50,36 @@ class TimerManager(object):
|
|||||||
heapq.heapify(self.timers)
|
heapq.heapify(self.timers)
|
||||||
return i
|
return i
|
||||||
|
|
||||||
|
def _next_timeout(self):
|
||||||
|
if len(self.timers) == 0:
|
||||||
|
if self.timer_debug:
|
||||||
|
print("timer: worker: queue empty")
|
||||||
|
return None
|
||||||
|
cur_nearest = self.timers[0][0]
|
||||||
|
next_timeout = cur_nearest - time.ticks_ms()
|
||||||
|
if self.timer_debug:
|
||||||
|
if next_timeout > 0:
|
||||||
|
print(f"timer: worker: next is {self.timers[0]}, sleep {next_timeout} ms")
|
||||||
|
else:
|
||||||
|
print(f"timer: worker: {self.timers[0]} elapsed @{cur_nearest}, delay {-next_timeout} ms")
|
||||||
|
return next_timeout
|
||||||
|
|
||||||
|
async def _wait(self, timeout):
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for_ms(self.worker_event.wait(), timeout)
|
||||||
|
if self.timer_debug:
|
||||||
|
print("timer: worker: event")
|
||||||
|
# got woken up due to event
|
||||||
|
self.worker_event.clear()
|
||||||
|
return True
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
return False
|
||||||
|
|
||||||
async def _timer_worker(self):
|
async def _timer_worker(self):
|
||||||
while True:
|
while True:
|
||||||
if len(self.timers) == 0:
|
next_timeout = self._next_timeout()
|
||||||
# Nothing to do
|
if next_timeout is None or next_timeout > 0:
|
||||||
await self.worker_event.wait()
|
await self._wait(next_timeout)
|
||||||
if self.timer_debug:
|
else:
|
||||||
print("_timer_worker: event 0")
|
_, callback = heapq.heappop(self.timers)
|
||||||
self.worker_event.clear()
|
safe_callback(callback, "timer callback")
|
||||||
continue
|
|
||||||
cur_nearest = self.timers[0][0]
|
|
||||||
wait_time = cur_nearest - time.ticks_ms()
|
|
||||||
if wait_time > 0:
|
|
||||||
if self.timer_debug:
|
|
||||||
print(f"_timer_worker: next is {self.timers[0]}, sleep {wait_time} ms")
|
|
||||||
try:
|
|
||||||
await asyncio.wait_for_ms(self.worker_event.wait(), wait_time)
|
|
||||||
if self.timer_debug:
|
|
||||||
print("_timer_worker: event 1")
|
|
||||||
# got woken up due to event
|
|
||||||
self.worker_event.clear()
|
|
||||||
continue
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
pass
|
|
||||||
_, callback = heapq.heappop(self.timers)
|
|
||||||
callback()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user