diff --git a/firmware/hardware.py b/firmware/hardware.py index d4065e1..4cd0ccc 100644 --- a/firmware/hardware.py +++ b/firmware/hardware.py @@ -1,3 +1,5 @@ +import asyncio + import async_button import async_buzzer @@ -26,6 +28,9 @@ class HardwareBase: bt: bluetooth.BluetoothServices batt_voltage: float + def __init__(self): + self.laser_task: Optional[asyncio.Task] = None + def __enter__(self): return self @@ -41,11 +46,24 @@ def laser_enable(self, value): pass @abstractmethod - def laser_on(self, value): + async def laser_on(self, value): pass + def flash_laser(self, count: int, speed: float): + if self.laser_task: + if not self.laser_task.done(): + self.laser_task.cancel() + self.laser_task = asyncio.create_task(self._flash_laser(count, speed)) + + async def _flash_laser(self, count: int, speed: float): + for _ in range(count): + await self.laser_on(False) + await asyncio.sleep(speed) + await self.laser_on(True) + await asyncio.sleep(speed) + @abstractmethod - def laser_measure(self): + async def laser_measure(self): pass @abstractmethod diff --git a/firmware/measure.py b/firmware/measure.py index a3b39bb..0dd5c1d 100644 --- a/firmware/measure.py +++ b/firmware/measure.py @@ -106,7 +106,6 @@ async def get_raw_measurement(devices: hardware.HardwareBase, disp: display.Disp logger.debug(f"Mag: {mag}") grav = devices.accelerometer.acceleration logger.debug(f"Grav: {grav}") - await asyncio.sleep(0.1) await devices.laser_on(True) finally: disp.sleep(wake=True) @@ -135,26 +134,20 @@ async def take_reading(devices: hardware.HardwareBase, logger.info(f"Measurement error: {repr(exc)}") if not isinstance(exc, asyncio.TimeoutError): # don't wibble the laser if it's timed out, it'll just get more confused - for i in range(5): - await devices.laser_on(False) - await asyncio.sleep(0.1) - await devices.laser_on(True) - await asyncio.sleep(0.1) + devices.flash_laser(5,0.1) devices.beep_sad() + await asyncio.sleep(0) return False else: leg = Leg(azimuth, inclination, distance) readings.store_reading(leg, cfg) devices.bt.disto.send_data(azimuth, inclination, distance) if readings.triple_shot(): - for _ in range(2): - await devices.laser_on(False) - await asyncio.sleep(0.2) - await devices.laser_on(True) - await asyncio.sleep(0.2) + devices.flash_laser(2,0.2) devices.beep_happy() else: devices.beep_bip() + await asyncio.sleep(0) return True diff --git a/firmware/versions/hardware_v1.py b/firmware/versions/hardware_v1.py index 21c6858..89550d1 100644 --- a/firmware/versions/hardware_v1.py +++ b/firmware/versions/hardware_v1.py @@ -1,3 +1,4 @@ +import asyncio import time import async_button @@ -21,6 +22,7 @@ class Hardware(HardwareBase): def __init__(self, pins): logger.debug("Initialising hardware") + super().__init__() import displayio displayio.release_displays() self._las_en_pin = digitalio.DigitalInOut(pins.LASER_EN) @@ -36,7 +38,7 @@ def __init__(self, pins): self._drdy_io.direction = digitalio.Direction.INPUT # noinspection PyTypeChecker self.magnetometer = rm3100.RM3100_I2C(self._i2c, drdy_pin=self._drdy_io, cycle_count=2000) - self._uart = busio.UART(pins.TX, pins.RX, baudrate=9600) + self._uart = busio.UART(pins.TX, pins.RX, baudrate=9600, timeout=0.1) self._uart.reset_input_buffer() self._laser = laser_egismos.AsyncLaser(self._uart) if pins.BUZZER_B is None: @@ -73,9 +75,18 @@ def laser_enable(self, value: bool) -> None: self._las_en_pin.value = value async def laser_on(self, value: bool) -> None: + await self._laser_mutex() await self._laser.set_laser(value) + async def _laser_mutex(self): + """This function waits for the laser task to complete before proceeding""" + if self.laser_task and not self.laser_task.done(): + if asyncio.current_task() is not self.laser_task: + #don't wait if we're actually *in* the laser task + await self.laser_task + async def laser_measure(self) -> float: + await self._laser_mutex() self._laser.async_reader.s.read() # clear the buffer return await self._laser.measure()