private void Device_ConnectionStatusChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) { if (!(sender is ObservableBluetoothLEDevice nativeDevice) || nativeDevice.BluetoothLEDevice == null) { return; } if (propertyChangedEventArgs.PropertyName != nameof(nativeDevice.IsConnected)) { return; } var address = ParseDeviceId(nativeDevice.BluetoothLEDevice.BluetoothAddress).ToString(); if (nativeDevice.IsConnected && ConnectedDeviceRegistry.TryGetValue(address, out var connectedDevice)) { HandleConnectedDevice(connectedDevice); return; } if (!nativeDevice.IsConnected && ConnectedDeviceRegistry.TryRemove(address, out var disconnectedDevice)) { HandleDisconnectedDevice(false, disconnectedDevice); } }
protected void DisconnectDeviceNative(Device device) { // Windows doesn't support disconnecting, so currently just dispose of the device Trace.Message($"Disconnected from device with ID: {device.Id.ToString()}"); ((Device)device).ClearServices(); if (device.NativeDevice is ObservableBluetoothLEDevice nativeDevice) { nativeDevice.BluetoothLEDevice.Dispose(); ConnectedDeviceRegistry.TryRemove(device.Id.ToString(), out _); } }
public override void OnConnectionStateChange(BluetoothGatt gatt, GattStatus status, ProfileState newState) { base.OnConnectionStateChange(gatt, status, newState); IDevice device = null; if (status != GattStatus.Success) { Mvx.TaggedError("OnConnectionStateChange", "GattCallback error: {0}", status); device = new Device(gatt.Device, gatt, this, 0); DeviceConnectionError(this, new DeviceConnectionEventArgs() { Device = device }); // We don't return. Allowing to fall-through to the SWITCH, which will assume a disconnect, close GATT and clean up. // The above error event handles the case where the error happened during a Connect call, which will close out any waiting asyncs. } else { Mvx.Trace("GattCallback state: {0}", newState.ToString()); } switch (newState) { // disconnected case ProfileState.Disconnected: if (DeviceOperationRegistry.TryGetValue(gatt.Device.Address, out device)) { Mvx.Trace("Disconnected by user"); //Found so we can remove it DeviceOperationRegistry.Remove(gatt.Device.Address); ConnectedDeviceRegistry.Remove(gatt.Device.Address); gatt.Close(); DeviceDisconnected(this, new DeviceConnectionEventArgs { Device = device }); break; } //connection must have been lost, bacause our device was not found in the registry but was still connected if (ConnectedDeviceRegistry.TryGetValue(gatt.Device.Address, out device)) { Mvx.Trace("Disconnected by lost connection"); ConnectedDeviceRegistry.Remove(gatt.Device.Address); gatt.Close(); DeviceConnectionLost(this, new DeviceConnectionEventArgs() { Device = device }); break; } gatt.Close(); // Close GATT regardless, else we can accumulate zombie gatts. Mvx.Trace("Disconnect. Device not found in registry. Not raising disconnect/lost event."); break; // connecting case ProfileState.Connecting: Mvx.Trace("Connecting"); break; // connected case ProfileState.Connected: Mvx.Trace("Connected"); //Try to find the device in the registry so that the same instance is updated if (DeviceOperationRegistry.TryGetValue(gatt.Device.Address, out device)) { ((Device)device).Update(gatt.Device, gatt, this); //Found so we can remove it DeviceOperationRegistry.Remove(gatt.Device.Address); } else { //only for on auto-reconnect (device is not in operation registry) device = new Device(gatt.Device, gatt, this, 0); } ConnectedDeviceRegistry[gatt.Device.Address] = device; DeviceConnected(this, new DeviceConnectionEventArgs() { Device = device }); break; // disconnecting case ProfileState.Disconnecting: Mvx.Trace("Disconnecting"); break; } }
public Adapter(CBCentralManager centralManager, IBleCentralManagerDelegate bleCentralManagerDelegate) { _centralManager = centralManager; _bleCentralManagerDelegate = bleCentralManagerDelegate; _bleCentralManagerDelegate.DiscoveredPeripheral += (sender, e) => { Trace.Message("DiscoveredPeripheral: {0}, Id: {1}", e.Peripheral.Name, e.Peripheral.Identifier); var name = e.Peripheral.Name; if (e.AdvertisementData.ContainsKey(CBAdvertisement.DataLocalNameKey)) { // iOS caches the peripheral name, so it can become stale (if changing) // keep track of the local name key manually name = ((NSString)e.AdvertisementData.ValueForKey(CBAdvertisement.DataLocalNameKey)).ToString(); } var device = new Device(this, e.Peripheral, _bleCentralManagerDelegate, name, e.RSSI.Int32Value, ParseAdvertismentData(e.AdvertisementData)); HandleDiscoveredDevice(device); }; _bleCentralManagerDelegate.UpdatedState += (sender, e) => { Trace.Message("UpdatedState: {0}", _centralManager.State); _stateChanged.Set(); //handle PoweredOff state //notify subscribers about disconnection if (_centralManager.State == CBCentralManagerState.PoweredOff) { foreach (var device in ConnectedDeviceRegistry.Values.ToList()) { ((Device)device).ClearServices(); HandleDisconnectedDevice(false, device); } ConnectedDeviceRegistry.Clear(); } }; _bleCentralManagerDelegate.ConnectedPeripheral += (sender, e) => { Trace.Message("ConnectedPeripherial: {0}", e.Peripheral.Name); // when a peripheral gets connected, add that peripheral to our running list of connected peripherals var guid = ParseDeviceGuid(e.Peripheral).ToString(); IDevice device; if (_deviceOperationRegistry.TryGetValue(guid, out device)) { _deviceOperationRegistry.Remove(guid); ((Device)device).Update(e.Peripheral); } else { Trace.Message("Device not found in operation registry. Creating a new one."); device = new Device(this, e.Peripheral, _bleCentralManagerDelegate); } ConnectedDeviceRegistry[guid] = device; HandleConnectedDevice(device); }; _bleCentralManagerDelegate.DisconnectedPeripheral += (sender, e) => { if (e.Error != null) { Trace.Message("Disconnect error {0} {1} {2}", e.Error.Code, e.Error.Description, e.Error.Domain); } // when a peripheral disconnects, remove it from our running list. var id = ParseDeviceGuid(e.Peripheral); var stringId = id.ToString(); IDevice foundDevice; // normal disconnect (requested by user) var isNormalDisconnect = _deviceOperationRegistry.TryGetValue(stringId, out foundDevice); if (isNormalDisconnect) { _deviceOperationRegistry.Remove(stringId); } // check if it is a peripheral disconnection, which would be treated as normal if (e.Error != null && e.Error.Code == 7 && e.Error.Domain == "CBErrorDomain") { isNormalDisconnect = true; } // remove from connected devices if (!ConnectedDeviceRegistry.TryRemove(stringId, out foundDevice)) { Trace.Message($"Device with id '{stringId}' was not found in the connected device registry. Nothing to remove."); } foundDevice = foundDevice ?? new Device(this, e.Peripheral, _bleCentralManagerDelegate); //make sure all cached services are cleared this will also clear characteristics and descriptors implicitly ((Device)foundDevice).ClearServices(); HandleDisconnectedDevice(isNormalDisconnect, foundDevice); }; _bleCentralManagerDelegate.FailedToConnectPeripheral += (sender, e) => { var id = ParseDeviceGuid(e.Peripheral); var stringId = id.ToString(); IDevice foundDevice; // remove instance from registry if (_deviceOperationRegistry.TryGetValue(stringId, out foundDevice)) { _deviceOperationRegistry.Remove(stringId); } foundDevice = foundDevice ?? new Device(this, e.Peripheral, _bleCentralManagerDelegate); HandleConnectionFail(foundDevice, e.Error.Description); }; }