diff --git a/digi/xbee/devices.py b/digi/xbee/devices.py index e652bca..5bf1244 100644 --- a/digi/xbee/devices.py +++ b/digi/xbee/devices.py @@ -2437,6 +2437,14 @@ def __init__(self, port=None, baud_rate=None, data_bits=serial.EIGHTBITS, self.__route_received = RouteReceived() self.__stats = Statistics() + def add_error_callback(self, callback): + """Public method to handle serial errors (e.g., disconnections).""" + self._packet_listener.add_error_callback(callback) + + def remove_error_callback(self, callback): + """Remove an error callback.""" + self._packet_listener.remove_error_callback(callback) + @classmethod def create_xbee_device(cls, comm_port_data): """ diff --git a/digi/xbee/reader.py b/digi/xbee/reader.py index b670eea..ff01ea1 100644 --- a/digi/xbee/reader.py +++ b/digi/xbee/reader.py @@ -577,6 +577,8 @@ def __init__(self, comm_iface, xbee_device, queue_max_size=None): self.__ble_gap_scan_received = BLEGAPScanReceived() self.__ble_gap_scan_status_received = BLEGAPScanStatusReceived() + self.__error_callbacks = [] + # API internal callbacks: self.__packet_received_api = xbee_device.get_xbee_device_callbacks() @@ -592,6 +594,25 @@ def __init__(self, comm_iface, xbee_device, queue_max_size=None): self.__explicit_xbee_queue = XBeeQueue(self.__queue_max_size) self.__ip_xbee_queue = XBeeQueue(self.__queue_max_size) + def _trigger_error_callbacks(self, error): + """Call all registered error callbacks with the exception.""" + for callback in self.__error_callbacks: + try: + callback(error) + except Exception as e: + # Log errors in user callbacks without crashing + self._log.error("Error in callback: %s", str(e)) + + def add_error_callback(self, callback): + """Public method to let users register error callbacks.""" + if callback not in self.__error_callbacks: + self.__error_callbacks.append(callback) + + def remove_error_callback(self, callback): + """Public method to remove a callback.""" + if callback in self.__error_callbacks: + self.__error_callbacks.remove(callback) + def wait_until_started(self, timeout=None): """ Blocks until the thread has fully started. If already started, returns @@ -620,10 +641,13 @@ def run(self): except SerialException as exc: # SerialException: device reports readiness to read but # returned no data (device disconnected or multiple access on port?) - if "device reports readiness to read but returned no data" in str(exc): - self._log.warning("Serial exception while reading: %s", exc) - continue - raise exc + # if "device reports readiness to read but returned no data" in str(exc): + # self._log.warning("Serial exception while reading: %s", exc) + # continue + # raise exc + self._trigger_error_callbacks(exec) + self.__stop = True + break if raw_packet is not None: # If the current protocol is 802.15.4, the packet may have diff --git a/digi/xbee/serial.py b/digi/xbee/serial.py index 78c2ac9..3d2a7bc 100644 --- a/digi/xbee/serial.py +++ b/digi/xbee/serial.py @@ -271,6 +271,10 @@ def wait_for_frame(self, operating_mode): return xbee_packet except TimeoutException: return None + + except SerialException as e: + + raise def read_existing(self): """