From bae93b0b1f6828ed6942cd367a3a5841a6f1c6c9 Mon Sep 17 00:00:00 2001
From: Andreas Gattringer <andreas.gattringer@univie.ac.at>
Date: Sun, 7 Jul 2024 19:22:48 +0200
Subject: [PATCH] made UDPCommunicator "work" without network adapter present

---
 .../communication/udp_communicator.py         | 42 ++++++++++++++-----
 umnp/microcontroller/measurementdevice.py     | 13 +++++-
 2 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/umnp/microcontroller/communication/udp_communicator.py b/umnp/microcontroller/communication/udp_communicator.py
index a713209..54e835f 100644
--- a/umnp/microcontroller/communication/udp_communicator.py
+++ b/umnp/microcontroller/communication/udp_communicator.py
@@ -22,8 +22,8 @@ else:
 class UDPCommunicator:
     def __init__(
         self,
-        sender: UDPSender,
-        receiver: UDPReceiver,
+        sender: UDPSender | None,
+        receiver: UDPReceiver | None,
         device: "MeasurementDevice",
         max_msgs: int = 10,
     ):
@@ -44,18 +44,28 @@ class UDPCommunicator:
 
     @property
     def network_error(self):
-        return self._sender.error
+        if self._sender:
+            return self._sender.error
+        else:
+            return None
 
     def clear_network_error(self):
-        self._sender.reset_error()
+        if self._sender:
+            self._sender.reset_error()
 
     async def queue_incoming_message(self, msg, source):
+        if self._receiver is None:
+            return
+
         async with self._receive_lock:
             self._messages_received.append((msg, source, time.time()))
             while len(self._messages_received) > self._max_msgs:
                 self._messages_received.pop(0)
 
     async def get_newest_message(self):
+        if self._receiver is None:
+            return
+
         async with self._receive_lock:
             if len(self._messages_received):
                 return self._messages_received.pop(0)
@@ -64,7 +74,8 @@ class UDPCommunicator:
 
     async def receive_task(self):
         while True:
-            await self._receiver.receive(self)
+            if self._receiver:
+                await self._receiver.receive(self)
             await asyncio.sleep(0.500)
 
     async def send_task(self):
@@ -78,12 +89,19 @@ class UDPCommunicator:
                 await asyncio.sleep(0.5)
                 continue
 
+            if self._sender is None:
+                await asyncio.sleep(0.1)
+                continue
+
             if isinstance(msg, Message):
                 await self._sender.broadcast(msg.encode())
 
             await asyncio.sleep(0.5)
 
     async def send_message(self, msg: Message):
+        if self._sender is None:
+            return
+
         self._messages_send_queue.append(msg)
 
     async def control_task(self):
@@ -95,10 +113,12 @@ class UDPCommunicator:
             await asyncio.sleep(0.5)
 
     async def start(self):
-        receiver = asyncio.create_task(self.receive_task())
-        sender = asyncio.create_task(self.send_task())
-        controller = asyncio.create_task(self.control_task())
+        receive_task = asyncio.create_task(self.receive_task())
+        send_task = asyncio.create_task(self.send_task())
+        control_task = asyncio.create_task(self.control_task())
+
         tasks = []
+
         for name, task in self._tasks.items():
             result = asyncio.create_task(task.run())
             tasks.append(result)
@@ -106,9 +126,9 @@ class UDPCommunicator:
         for t in tasks:
             await t
 
-        await receiver
-        await sender
-        await controller
+        await receive_task
+        await send_task
+        await control_task
 
     def add_task(self, task: PeriodicTask, name: str):
         self._tasks[name] = task
diff --git a/umnp/microcontroller/measurementdevice.py b/umnp/microcontroller/measurementdevice.py
index 72aba17..bf27ad2 100644
--- a/umnp/microcontroller/measurementdevice.py
+++ b/umnp/microcontroller/measurementdevice.py
@@ -11,6 +11,7 @@ from umnp.microcontroller.devices.network.udp import (
     DEFAULT_UMNP_COMMAND_IN_PORT,
 )
 from umnp.proto import DeviceMessage
+from umnp.proto.common.logging import log_error
 from umnp.proto.constants import MSG_STRING_ENCODING
 from umnp.proto.device_message import MSG_TYPE_LIFE_SIGN, MSG_TYPE_INFO
 
@@ -160,10 +161,18 @@ class MeasurementDevice:
         data_port: int = DEFAULT_UMNP_DATA_IN_PORT,
         cmd_port: int = DEFAULT_UMNP_COMMAND_IN_PORT,
     ):
+
+        r = None
+        s = None
         if not self._communicator:
-            s = self.create_sender(port=data_port)
-            r = self.create_receiver(port=cmd_port)
+            try:
+                s = self.create_sender(port=data_port)
+                r = self.create_receiver(port=cmd_port)
+            except ValueError:
+                log_error("No network hardware available")
+                
             self._communicator = UDPCommunicator(receiver=r, sender=s, device=self)
+
         return self._communicator
 
     @property
-- 
GitLab