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 _);
            }
        }
예제 #3
0
        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;
            }
        }
예제 #4
0
        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);
            };
        }