Example #1
0
        public async Task <IButtplugDevice> CreateDeviceAsync([NotNull] BluetoothLEDevice aDevice)
        {
            // GetGattServicesForUuidAsync is 15063 only
            var services = await aDevice.GetGattServicesAsync(BluetoothCacheMode.Cached);

            List <Guid> uuids = new List <Guid>();

            foreach (var s in services.Services)
            {
                _bpLogger.Trace($"Found service UUID: {s.Uuid} ({aDevice.Name})");
                uuids.Add(s.Uuid);
            }

            var srvs = (from x in services.Services
                        from y in _deviceInfo.Services
                        where x.Uuid == y
                        select x).ToArray();

            if (srvs.Length != 1)
            {
                // Somehow we've gotten multiple services back, something we don't currently support.
                _bpLogger.Error($"Found {srvs.Length} services for {aDevice.Name}, which is more/less than 1. Please fix this in the bluetooth definition.");
                return(null);
            }

            var service = srvs[0];

            var chrResult = await service.GetCharacteristicsAsync();

            if (chrResult.Status != GattCommunicationStatus.Success)
            {
                _bpLogger.Error($"Cannot connect to service {service.Uuid} of {aDevice.Name}.");
                return(null);
            }

            foreach (var s in chrResult.Characteristics)
            {
                _bpLogger.Trace($"Found characteristics UUID: {s.Uuid} ({aDevice.Name})");
            }

            var chrs = chrResult.Characteristics.ToArray();

            // If there aren't any characteristics by this point, something has gone wrong.
            if (!chrs.Any())
            {
                _bpLogger.Error($"Cannot find characteristics for service {service.Uuid} of {aDevice.Name}.");
                return(null);
            }

            var bleInterface = new UWPBluetoothDeviceInterface(_buttplugLogManager, _deviceInfo, aDevice, chrs);

            var device = _deviceInfo.CreateDevice(_buttplugLogManager, bleInterface);

            // If initialization fails, don't actually send the message back. Just return null, we'll
            // have the info in the logs.
            return(await device.InitializeAsync().ConfigureAwait(false) is Ok ? device : null);
        }
        public async Task <IButtplugDevice> CreateDeviceAsync([NotNull] BluetoothLEDevice aDevice)
        {
            // GetGattServicesForUuidAsync is 15063 only
            var services = await aDevice.GetGattServicesAsync(BluetoothCacheMode.Cached);

            foreach (var s in services.Services)
            {
                _bpLogger.Debug("Found service UUID: " + s.Uuid + " (" + aDevice.Name + ")");
            }

            var srvResult = await aDevice.GetGattServicesForUuidAsync(_deviceInfo.Services[0], BluetoothCacheMode.Cached);

            if (srvResult.Status != GattCommunicationStatus.Success || !srvResult.Services.Any())
            {
                _bpLogger.Debug("Cannot find service for device (" + aDevice.Name + ")");
                return(null);
            }

            var service = srvResult.Services.First();

            var chrResult = await service.GetCharacteristicsAsync();

            if (chrResult.Status != GattCommunicationStatus.Success)
            {
                return(null);
            }

            foreach (var s in chrResult.Characteristics)
            {
                _bpLogger.Trace("Found characteristics UUID: " + s.Uuid + " (" + aDevice.Name + ")");
            }

            var chrs = from x in chrResult.Characteristics
                       where _deviceInfo.Characteristics.Contains(x.Uuid)
                       select x;

            var gattCharacteristics = chrs as GattCharacteristic[] ?? chrs.ToArray();

            if (!gattCharacteristics.Any())
            {
                return(null);
            }

            // TODO This assumes we're always planning on having the UUIDs sorted in the Info classes, which is probably not true.
            var bleInterface = new UWPBluetoothDeviceInterface(_buttplugLogManager,
                                                               aDevice, gattCharacteristics.OrderBy((aChr) => aChr.Uuid).ToArray());

            var device = _deviceInfo.CreateDevice(_buttplugLogManager, bleInterface);

            if (await device.Initialize() is Ok)
            {
                return(device);
            }

            // If initialization fails, don't actually send the message back. Just return null, we'll have the info in the logs.
            return(null);
        }
        public static async Task <IButtplugDeviceImpl> Create(IButtplugLogManager aLogManager,
                                                              BluetoothLEProtocolConfiguration aConfig,
                                                              BluetoothLEDevice aDevice)
        {
            var device = new UWPBluetoothDeviceInterface(aLogManager, aDevice);
            await device.InitializeDevice(aConfig).ConfigureAwait(false);

            return(device);
        }
        private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher aObj,
                                                   BluetoothLEAdvertisementReceivedEventArgs aEvent)
        {
            if (aEvent?.Advertisement == null)
            {
                BpLogger.Debug("Null BLE advertisement received: skipping");
                return;
            }

            var advertName  = aEvent.Advertisement.LocalName ?? string.Empty;
            var advertGUIDs = new List <Guid>();

            advertGUIDs.AddRange(aEvent.Advertisement.ServiceUuids ?? new Guid[] { });
            var btAddr = aEvent.BluetoothAddress;

            // BpLogger.Trace($"Got BLE Advertisement for device: {aEvent.Advertisement.LocalName} / {aEvent.BluetoothAddress}");
            if (_seenAddresses.Contains(btAddr))
            {
                // BpLogger.Trace($"Ignoring advertisement for already connecting device:
                // {aEvent.Advertisement.LocalName} / {aEvent.BluetoothAddress}");
                return;
            }

            BpLogger.Trace("BLE device found: " + advertName);

            // We always need a name to match against.
            if (advertName == string.Empty)
            {
                return;
            }

            // todo Add advertGUIDs back in. Not sure that ever really gets used though.
            var deviceCriteria = new BluetoothLEProtocolConfiguration(advertName);

            var deviceFactory = DeviceConfigurationManager.Manager.Find(deviceCriteria);

            // If we don't have a protocol to match the device, we can't do anything with it.
            if (deviceFactory == null || !(deviceFactory.Config is BluetoothLEProtocolConfiguration bleConfig))
            {
                BpLogger.Debug($"No usable device factory available for {advertName}.");
                // If we've got an actual name this time around, and we don't have any factories
                // available that match the info we have, add to our seen list so we won't keep
                // rechecking. If a device does have a factory, but doesn't connect, we still want to
                // try again.
                _seenAddresses.Add(btAddr);
                return;
            }

            var fromBluetoothAddressAsync = BluetoothLEDevice.FromBluetoothAddressAsync(btAddr);

            // Can return null if the device no longer exists, for instance if it turned off between
            // advertising and us getting here. Since we didn't get a chance to try to connect,
            // remove it from seen devices, since the user may turn it back on during this scanning period.
            if (fromBluetoothAddressAsync == null)
            {
                return;
            }

            var dev = await fromBluetoothAddressAsync;

            // If a device is turned on after scanning has started, windows seems to lose the device
            // handle the first couple of times it tries to deal with the advertisement. Just log the
            // error and hope it reconnects on a later retry.
            IButtplugDeviceImpl bleDevice = null;
            IButtplugDevice     btDevice  = null;

            try
            {
                bleDevice = await UWPBluetoothDeviceInterface.Create(LogManager, bleConfig, dev).ConfigureAwait(false);

                btDevice = await deviceFactory.CreateDevice(LogManager, bleDevice).ConfigureAwait(false);

                InvokeDeviceAdded(new DeviceAddedEventArgs(btDevice));
            }
            catch (Exception ex)
            {
                if (btDevice != null)
                {
                    btDevice.Disconnect();
                }
                else
                {
                    bleDevice?.Disconnect();
                }

                BpLogger.Error(
                    $"Cannot connect to device {advertName} {btAddr}: {ex.Message}");
            }
        }