为什么BluetoothLEDevice.GattServices为空

时间:2016-03-11 10:20:27

标签: c# windows-runtime windows-10-universal bluetooth-lowenergy gatt

我正在尝试与外围设备进行通信而不将其与Windows配对,我正在使用BluetoothLEAdvertisementWatcher扫描范围内的设备。这是我的WatcherOnReceived方法:

 async private void WatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
    {
        BluetoothLEDevice device = null;
        BluetoothDevice basicDevice = null;
        GattDeviceService services = null;

        if (args.Advertisement.LocalName != "Nexus 6")
            return;

        _watcher.Stop();

        device = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
        device.GattServicesChanged += Device_GattServicesChanged;
        //basicDevice = await BluetoothDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
        //services = await GattDeviceService.FromIdAsync(device.DeviceId);

        lock (m_syncObj)
        {
            Debug.WriteLine("");
            Debug.WriteLine("----------- DEVICE --------------");

            Debug.WriteLine(args.ToString());

            Debug.WriteLine(args.Advertisement.DataSections.Count);

            foreach (var item in args.Advertisement.DataSections)
            {
                var data = new byte[item.Data.Length];
                using (var reader = DataReader.FromBuffer(item.Data))
                {
                    reader.ReadBytes(data);
                }

                Debug.WriteLine("Manufacturer data: " + BitConverter.ToString(data));

                //Debug.WriteLine("Data : " + item.Data.ToString());
                //Debug.WriteLine("Data capacity: " + item.Data.Capacity);
                Debug.WriteLine("Data Type: " + item.DataType);
            }

            foreach (var md in args.Advertisement.ManufacturerData)
            {
                var data = new byte[md.Data.Length];
                using (var reader = DataReader.FromBuffer(md.Data))
                {
                    reader.ReadBytes(data);
                }
                Debug.WriteLine("Manufacturer data: " + BitConverter.ToString(data));
            }

            foreach (Guid id in args.Advertisement.ServiceUuids)
            {
                Debug.WriteLine("UUIDs: " + id.ToString() + " Count: " + args.Advertisement.ServiceUuids.Count);
                //services = device.GetGattService(id);
            }

            Debug.WriteLine("Receive event...");
            Debug.WriteLine("BluetoothAddress: " + args.BluetoothAddress.ToString("X"));
            Debug.WriteLine("Advertisement.LocalName: " + args.Advertisement.LocalName);
            Debug.WriteLine("AdvertisementType: " + args.AdvertisementType);
            Debug.WriteLine("RawSignalStrengthInDBm: " + args.RawSignalStrengthInDBm);

            if (device != null)
            {
                Debug.WriteLine("Bluetooth Device: " + device.Name);
                Debug.WriteLine("Bluetooth Device conn status: " + device.ConnectionStatus);
                Debug.WriteLine("Bluetooth DeviceId: " + device.DeviceId);
                Debug.WriteLine("Bluetooth GettServices Count: " + device.GattServices.Count);
            }
        }   
    }

当收到设备时,我从args.BlutoothAddress成功创建了BluetoothLEDevice,但是device.GattServices总是为空,因此我无法使用它们与设备通信。是设备或Windows API中的问题,还有什么可以尝试?

1 个答案:

答案 0 :(得分:4)

更新04/17 - 创建者更新 微软刚刚更新了他们的蓝牙API。我们现在有未配对的BLE设备通讯!

目前他们的文档很少,但这是一个非常简化的新结构:

BleWatcher = new BluetoothLEAdvertisementWatcher 
{ 
    ScanningMode = BluetoothLEScanningMode.Active
};
BleWatcher.Start();

BleWatcher.Received += async (w, btAdv) => {
    var device = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
Debug.WriteLine($"BLEWATCHER Found: {device.name}");

    // SERVICES!!
    var gatt = await device.GetGattServicesAsync();
    Debug.WriteLine($"{device.Name} Services: {gatt.Services.Count}, {gatt.Status}, {gatt.ProtocolError}");

    // CHARACTERISTICS!!
    var characs = await gatt.Services.Single(s => s.Uuid == SAMPLESERVICEUUID).GetCharacteristicsAsync();
    var charac = characs.Single(c => c.Uuid == SAMPLECHARACUUID);
    await charac.WriteValueAsync(SOMEDATA);
};

现在好多了。正如我所说,目前没有文档,我有一个奇怪的问题,我的ValueChanged回调在30秒左右后停止被调用,尽管这似乎是一个单独的范围问题。

更新2 - 一些不确定性

在更多关于新创作者更新的内容之后,在构建BLE应用时还需要考虑更多的事情。

  • 您不再需要在UI线程上运行蓝牙功能。对于没有配对的BLE,似乎没有任何权限窗口,因此不再需要在UI线程上运行。 您可能会发现应用程序在一段时间后停止从设备接收更新。这是一个范围问题,在这个问题中,对象被处理掉了。在上面的代码中,如果你在charac上听ValueChanged,你可能会遇到这个问题。这是因为GattCharacteristic在它应该被处理之前被处理掉,将特征设置为全局而不是依赖于它被复制。 断开连接似乎有点破碎。退出应用程序不会终止连接。因此,请确保使用App.xml.cs OnSuspended回调来终止连接。否则你会进入一个奇怪的状态,Windows似乎维护(并继续阅读!!)BLE连接。 它有它的怪癖,但它的确有效!

  • 这仍然是Windows Universal应用程序的一个问题,最初的问题是设备必须配对(不绑定)才能发现GattServices。但是,还需要使用Windows设备而不是BLE API来发现它们。微软已经意识到并且正在开发一种新的BLE API,它不需要配对,但坦率地说,在准备就绪之前,他们的BLE支持是无用的。

  • 尝试在控制面板中手动配对设备,然后再次列出服务。出于某些原因,在Windows Universal Apps中,您只能列出配对设备的Gatt服务,尽管BLE的一个优点是您在使用其服务之前无需与设备配对。

您可以以编程方式配对设备,但是根据运行应用程序的平台,这需要UI提示。因此,在后台询问BLE服务是不可行的。这需要修复,因为它真的阻碍了UWP中的BLE支持。

它奇怪但是有效!

OLD ANSWER

以下是一些带有工作BLE设备连接的示例代码:

    private void StartWatcher()
    {
        ConnectedDevices = new List<string>();

        Watcher = new BluetoothLEAdvertisementWatcher { ScanningMode = BluetoothLEScanningMode.Active };
        Watcher.Received += DeviceFound;

        DeviceWatcher = DeviceInformation.CreateWatcher();
        DeviceWatcher.Added += DeviceAdded;
        DeviceWatcher.Updated += DeviceUpdated;

        StartScanning();
    }

    private void StartScanning()
    {
        Watcher.Start();
        DeviceWatcher.Start();
    }

    private async void DeviceFound(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs btAdv)
    {
        if (!ConnectedDevices.Contains(btAdv.Advertisement.LocalName) && _devices.Contains(btAdv.Advertisement.LocalName))
        {
            await Dispatcher.RunAsync(CoreDispatcherPriority.Low, async () =>
            {
                var device = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
                if (device.GattServices.Any())
                {
                    ConnectedDevices.Add(device.Name);
                    device.ConnectionStatusChanged += (sender, args) =>
                    {
                        ConnectedDevices.Remove(sender.Name);
                    };
                    SetupWaxStream(device);
                } else if (device.DeviceInformation.Pairing.CanPair && !device.DeviceInformation.Pairing.IsPaired)
                {
                    await device.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.None);
                }
            });
        }
    }

    private async void DeviceAdded(DeviceWatcher watcher, DeviceInformation device)
    {
        if (_devices.Contains(device.Name))
        {
            try
            {
                var service = await GattDeviceService.FromIdAsync(device.Id);
                var characteristics = service.GetAllCharacteristics();
            }
            catch
            {
                Debug.WriteLine("Failed to open service.");
            }
        }
    }

    private async void DeviceUpdated(DeviceWatcher watcher, DeviceInformationUpdate update)
    {
        var device = await DeviceInformation.CreateFromIdAsync(update.Id);
        if (_devices.Contains(device.Name))
        {
            try
            {
                var service = await GattDeviceService.FromIdAsync(device.Id);
                var characteristics = service.GetAllCharacteristics();
            }
            catch
            {
                Debug.WriteLine("Failed to open service.");
            }
        }
    }