【问题标题】:Use a BLE keyring as smart button使用 BLE 钥匙圈作为智能按钮
【发布时间】:2017-01-24 13:46:54
【问题描述】:

我有一个BLE keyring,它有一个按钮(显然还有各种传感器)。我希望我的 C# 应用程序对按钮按下作出反应。

我的问题:

  • 我不知道应该订阅哪个特征。
  • 即使订阅所有特征通知,也不会调用 ValueChanged 回调。
  • 过了一会儿,我收到一条异常消息:“设备无法识别命令。(来自 HRESULT 的异常:0x80070016)”。 UPDATE:这似乎是由不可靠的连接引起的。用简单的 try/catch 绕过。

这是 BTHGattDump 的结果:

Microsoft Bluetooth GATT database viewer v1.00 Copyright (c) Microsoft Corp.
Selected device - GABLYS
Device Address - e7be9c955801  (STATIC)
[Service] Handle=0x0001 Type=0x1800(GAP)
    [Characteristic] Handle=0x0002 ValueHandle=0x0003 Type=0x2a00(Device Name) Properties=(Read/Write)
        [Value] GABLYS
    [Characteristic] Handle=0x0004 ValueHandle=0x0005 Type=0x2a01(Appearance) Properties=(Read)
        [Value] [0000]
    [Characteristic] Handle=0x0006 ValueHandle=0x0007 Type=0x2a04(Peripheral Preferred Connection Parameters) Properties=(Read)
        [Value] [1000300000006400]
[Service] Handle=0x0008 Type=0x1801(GATT)
[Service] Handle=0x000c Type=0x180f(Battery)
    [Characteristic] Handle=0x000d ValueHandle=0x000e Type=0x2a19(Battery Level) Properties=(Read/Notify)
        [Value] [64]
        [Descriptor]  Handle=0x000f Type=0x2902(Client Configuration)
            [Value]  No subscription
[Service] Handle=0x0010 Type=0x1803(Link Loss)
    [Characteristic] Handle=0x0011 ValueHandle=0x0012 Type=0x2a06(Alert Level) Properties=(Read/Write)
        [Value] [00]
[Service] Handle=0x0013 Type=0x1802(Immediate Alert)
    [Characteristic] Handle=0x0014 ValueHandle=0x0015 Type=0x2a06(Alert Level) Properties=(WriteWithoutResponse)
[Service] Handle=0x0016 Type=4f172801-1867-a896-28c0-1bfbc156fa45
    [Characteristic] Handle=0x0017 ValueHandle=0x0018 Type=4f172491-1867-a896-28c0-1bfbc156fa45 Properties=(Read/Notify)
        [Value] [01]
        [Descriptor]  Handle=0x0019 Type=0x2902(Client Configuration)
            [Value]  No subscription
    [Characteristic] Handle=0x001a ValueHandle=0x001b Type=4f172492-1867-a896-28c0-1bfbc156fa45 Properties=(Read/Notify)
        [Value] [00]
        [Descriptor]  Handle=0x001c Type=0x2902(Client Configuration)
            [Value]  No subscription
[Service] Handle=0x001d Type=b0ad1523-99b2-7e1d-fc0d-6d399e1edf02
    [Characteristic] Handle=0x001e ValueHandle=0x001f Type=b0ad1524-99b2-7e1d-fc0d-6d399e1edf02 Properties=(Read/Notify)
        [Value] [00]
        [Descriptor]  Handle=0x0020 Type=0x2902(Client Configuration)
            [Value]  No subscription
    [Characteristic] Handle=0x0021 ValueHandle=0x0022 Type=b0ad1525-99b2-7e1d-fc0d-6d399e1edf02 Properties=(Read/Write)
        [Value] [00]
    [Characteristic] Handle=0x0023 ValueHandle=0x0024 Type=b0ad1526-99b2-7e1d-fc0d-6d399e1edf02 Properties=(Read/Write)
        [Value] [00]
[Service] Handle=0x0025 Type=89943300-2d54-b8cb-3af2-212144c5ca13
    [Characteristic] Handle=0x0026 ValueHandle=0x0027 Type=89943301-2d54-b8cb-3af2-212144c5ca13 Properties=(Read/Write)
        [Value] [00]
    [Characteristic] Handle=0x0028 ValueHandle=0x0029 Type=89943302-2d54-b8cb-3af2-212144c5ca13 Properties=(Read/Notify)
        [Value] [00]
        [Descriptor]  Handle=0x002a Type=0x2902(Client Configuration)
            [Value]  No subscription
    [Characteristic] Handle=0x002b ValueHandle=0x002c Type=89943304-2d54-b8cb-3af2-212144c5ca13 Properties=(Read/Write)
        [Value] [00]

我的代码(基于HeartbeatFg from DrJukka):

public async void InitializeServiceAsync(string deviceId)
{
    try
    {
        Deinitialize();
        _service = await GattDeviceService.FromIdAsync(deviceId);

        if (_service != null)
        {
            //we could be already connected, thus lets check that before we start monitoring for changes
            if (DeviceConnectionUpdated != null && (_service.Device.ConnectionStatus == BluetoothConnectionStatus.Connected))
            {
                DeviceConnectionUpdated(true, null);
            }

            _service.Device.ConnectionStatusChanged += OnConnectionStatusChanged;

            Subscribe(0x0016, 0x0017);

            //Let's try those once I can get at least the first one to work
            //Subscribe(0x0016, 0x001a);

            //Subscribe(0x001d, 0x001e);
            //Subscribe(0x0025, 0x0028);
        }
    }
    catch (Exception e)
    {
        System.Diagnostics.Debug.WriteLine("ERROR: Accessing your device failed." + Environment.NewLine + e.Message);

        if (DeviceConnectionUpdated != null)
        {
            DeviceConnectionUpdated(false, "Accessing device failed: " + e.Message);
        }
    }
}

public async void Subscribe(ushort serviceHandle, ushort characteristicHandle)
{
    try
    {
        var service = _service.Device.GattServices.Single(x => x.AttributeHandle == serviceHandle);
        var characteristic = service.GetAllCharacteristics().Single(x => x.AttributeHandle == characteristicHandle);

        if (characteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
        {
            var currentDescriptorValue = await characteristic.ReadClientCharacteristicConfigurationDescriptorAsync();

            if ((currentDescriptorValue.Status != GattCommunicationStatus.Success) || (currentDescriptorValue.ClientCharacteristicConfigurationDescriptor != GattClientCharacteristicConfigurationDescriptorValue.Notify))
            {
                await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
            }

            characteristic.ValueChanged += Oncharacteristic_ValueChanged;
        }
    }
    catch(Exception e)
    {
        Debug.WriteLine(e.Message);
    }
}

private void Oncharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
    System.Diagnostics.Debug.WriteLine($"Oncharacteristic_ValueChanged from : {sender.AttributeHandle}");

    var data = new byte[args.CharacteristicValue.Length];
    DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);

    System.Diagnostics.Debug.WriteLine("Oncharacteristic_ValueChanged : " + data[0]);
}

private void OnConnectionStatusChanged(BluetoothLEDevice sender, object args)
{
    if (sender.ConnectionStatus == BluetoothConnectionStatus.Connected)
    {
        System.Diagnostics.Debug.WriteLine("Connected");
    }
    else
    {
        System.Diagnostics.Debug.WriteLine("Disconnected");
    }

    if (DeviceConnectionUpdated != null)
    {
        DeviceConnectionUpdated(sender.ConnectionStatus == BluetoothConnectionStatus.Connected, null);
    }
}

输出:

FindAllAsync devices.Count : 1
Found : GABLYS, id: \\?\BTHLEDevice#{7b122568-6677-7f8c-f8e9-af0eedb36e3a}_e7be9c955801#9&ce378e&1&0032#{6e3bb679-4372-40c8-9eaa-4509df260cd8}
'HeartbeatFg.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Dev\Perso\BLE\BLETestStuffWindows-master\HeartbeatFg\HeartbeatFg\bin\x64\Debug\AppX\Microsoft.ApplicationInsights.PersistenceChannel.dll'. Cannot find or open the PDB file.
'HeartbeatFg.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Dev\Perso\BLE\BLETestStuffWindows-master\HeartbeatFg\HeartbeatFg\bin\x64\Debug\AppX\System.Threading.dll'. Symbols loaded.
'HeartbeatFg.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Dev\Perso\BLE\BLETestStuffWindows-master\HeartbeatFg\HeartbeatFg\bin\x64\Debug\AppX\System.Diagnostics.Tracing.dll'. Module was built without symbols.
'HeartbeatFg.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Dev\Perso\BLE\BLETestStuffWindows-master\HeartbeatFg\HeartbeatFg\bin\x64\Debug\AppX\System.Linq.dll'. Symbols loaded.
'HeartbeatFg.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Dev\Perso\BLE\BLETestStuffWindows-master\HeartbeatFg\HeartbeatFg\bin\x64\Debug\AppX\System.Globalization.dll'. Module was built without symbols.
'HeartbeatFg.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Dev\Perso\BLE\BLETestStuffWindows-master\HeartbeatFg\HeartbeatFg\bin\x64\Debug\AppX\System.IO.dll'. Symbols loaded.
Device GABLYS selected, now navigating to HeartBeatPage
OnNavigatedTo
'HeartbeatFg.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Dev\Perso\BLE\BLETestStuffWindows-master\HeartbeatFg\HeartbeatFg\bin\x64\Debug\AppX\System.Runtime.Extensions.dll'. Symbols loaded.
'HeartbeatFg.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Dev\Perso\BLE\BLETestStuffWindows-master\HeartbeatFg\HeartbeatFg\bin\x64\Debug\AppX\System.Reflection.dll'. Module was built without symbols.
Connected
'HeartbeatFg.exe' (CoreCLR: CoreCLR_UWP_Domain): Loaded 'C:\Dev\Perso\BLE\BLETestStuffWindows-master\HeartbeatFg\HeartbeatFg\bin\x64\Debug\AppX\System.Reflection.Extensions.dll'. Module was built without symbols.
The thread 0x3d6c has exited with code 0 (0x0).
The thread 0x34a8 has exited with code 0 (0x0).
The thread 0x368c has exited with code 0 (0x0).
The thread 0x12b4 has exited with code 0 (0x0).
Disconnected
Exception thrown: 'System.Exception' in mscorlib.ni.dll
Connected
Exception thrown: 'System.Exception' in mscorlib.ni.dll

【问题讨论】:

  • 服务 4f172801-1867-a896-28c0-1bfbc156fa45、b0ad1523-99b2-7e1d-fc0d-6d399e1edf02 和 89943300-2d54-b8cb-3af2-212144c5ca13 有什么作用?在互联网上搜索这些服务并没有任何结果。
  • 我实际上不知道哪些“非标准”服务做了什么。但是其中之一必须与按钮有关,因此我希望在按下按钮时会收到通知。但这不会发生:-(
  • 如果没有这些信息,几乎不可能推断出要做什么。如果配置通知的每个特征都没有帮助,那么事情似乎更复杂,做正确的事情完全是运气的问题。唯一的想法可能是该特征需要指示而不是通知,但这也只是猜测。

标签: c# uwp bluetooth-lowenergy gatt


【解决方案1】:

我不知道应该订阅哪个特征。

因此,您可以检索设备支持的所有服务和特征并注册 ValueChanged 事件。

我使用以下代码在 TI SensorTag 上进行测试,它适用于我。你可以试一试。 (我假设你的设备支持按键服务。)

    public async void InitializeServiceAsync(string deviceId)
    {
        try
        {
            _service = await GattDeviceService.FromIdAsync(deviceId);

            System.Diagnostics.Debug.WriteLine(_service.Device.Name);
            if (_service == null)
                return;

            var service = _service.Device.GattServices;
            foreach (var item in service)
            {
                var chars = item.GetAllCharacteristics();
                foreach (var cha in chars)
                {
                    _service = item;
                    Subscribe(item.AttributeHandle, cha.AttributeHandle);
                }
            }

        }
        catch (Exception e)
        {
            System.Diagnostics.Debug.WriteLine("ERROR: Accessing your device failed." + Environment.NewLine + e.Message);
        }
    }

    public async void Subscribe(ushort serviceHandle, ushort characteristicHandle)
    {
        try
        {
            var service = _service.Device.GattServices.Single(x => x.AttributeHandle == serviceHandle);
            var characteristic = service.GetAllCharacteristics().Single(x => x.AttributeHandle == characteristicHandle);

            if (characteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
            {
                System.Diagnostics.Debug.WriteLine("serviceHandle=" + serviceHandle);
                System.Diagnostics.Debug.WriteLine("characteristicHandle=" + characteristicHandle);
                await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);

                System.Diagnostics.Debug.WriteLine("register value changed event");
                characteristic.ValueChanged += Oncharacteristic_ValueChanged;
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }

    }

调用 InitializeServiceAsync() 方法:

    var selector = GattDeviceService.GetDeviceSelectorFromUuid(GattServiceUuids.GenericAccess);
    var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(selector);
    InitializeServiceAsync(devices[0].Id); //Use your device id intead of "devices[0].Id"

更新:

我做了两个修改:

  1. 遍历所有服务和特征。
  2. 删除此声明:

if ((currentDescriptorValue.Status != GattCommunicationStatus.Success) || (currentDescriptorValue.ClientCharacteristicConfigurationDescriptor != GattClientCharacteristicConfigurationDescriptorValue.Notify))

【讨论】:

  • 我在这里省略了它,但我对 InitializeServiceAsync() 的调用与您的几乎相同。否则,除了我调用 ReadClientCharacteristicConfigurationDescriptorAsync 而你不知道之外,我看不到你的代码在哪里做与我不同的事情吗?我在订阅方法中添加了一个 try/catch,这样我的问题 n°3 就被规避了(请参阅更新后的帖子)
  • @Vinzz 关于代码的差异请看我的更新。我的代码对你不起作用?你的 BLE 设备是什么类型的?我无法打开您的链接。
猜你喜欢
  • 2019-10-25
  • 1970-01-01
  • 2020-11-28
  • 2011-05-24
  • 2018-08-02
  • 1970-01-01
  • 2014-10-26
  • 2020-10-06
  • 1970-01-01
相关资源
最近更新 更多