diff --git a/adafruit_ble/__init__.py b/adafruit_ble/__init__.py index 4e5e660..693a47f 100755 --- a/adafruit_ble/__init__.py +++ b/adafruit_ble/__init__.py @@ -145,6 +145,9 @@ def pair(self, *, bond: bool = True) -> None: def disconnect(self) -> None: """Disconnect from peer.""" self._bleio_connection.disconnect() + # Clean up any services that need explicit cleanup. + for service in self._constructed_services.values(): + service.deinit() class BLERadio: diff --git a/adafruit_ble/characteristics/stream.py b/adafruit_ble/characteristics/stream.py index 76d5b42..5053971 100755 --- a/adafruit_ble/characteristics/stream.py +++ b/adafruit_ble/characteristics/stream.py @@ -69,7 +69,9 @@ def __init__( uuid=uuid, properties=properties, read_perm=read_perm, write_perm=write_perm ) - def bind(self, service: Service) -> Union[_bleio.Characteristic, BoundWriteStream]: + def bind( + self, service: Service + ) -> Union[_bleio.CharacteristicBuffer, BoundWriteStream]: """Binds the characteristic to the given Service.""" bound_characteristic = super().bind(service) # If we're given a remote service then we're the client and need to buffer in. diff --git a/adafruit_ble/services/__init__.py b/adafruit_ble/services/__init__.py index c246868..2fd0789 100644 --- a/adafruit_ble/services/__init__.py +++ b/adafruit_ble/services/__init__.py @@ -82,6 +82,9 @@ def __init__( else: getattr(self, class_attr) + def deinit(self): + """Override this method to do any explicit cleanup necessary on connection close.""" + @property def remote(self) -> bool: """True if the service is provided by a peer and accessed remotely.""" diff --git a/adafruit_ble/services/nordic.py b/adafruit_ble/services/nordic.py index 569ace9..d4db39b 100755 --- a/adafruit_ble/services/nordic.py +++ b/adafruit_ble/services/nordic.py @@ -62,6 +62,14 @@ def __init__(self, service: Optional[_bleio.Service] = None) -> None: self._tx = self._server_rx self._rx = self._server_tx + def deinit(self): + """The characteristic buffers must be deinitialized when no longer needed. + Otherwise they will leak storage. + """ + for obj in (self._tx, self._rx): + if hasattr(obj, "deinit"): + obj.deinit() + def read(self, nbytes: Optional[int] = None) -> Optional[bytes]: """ Read characters. If ``nbytes`` is specified then read at most that many bytes.