为什么Gatt Characteristic设置Value Changed时值不在预期范围内

Why value does not fall within the expected range when setting Value Changed for Gatt Characteristic

我想继续阅读 characteristic/set 我的 BLE 4.0 设备特性的值更改事件处理程序,方法是在 Visual Studio 2017 中使用 Universal Windows Platform C# 中的 ValueChanged 回调.

我遵循了这些站点的一些教程:Damian Blog's Windows Universal with BLE, Bluetooth Gatt's Git Hub, Bluetooth Generic Attribute Profile - Heart Rate Service and Dr. Jukka's mobile Blog on BLE。他们都在使用 ValueChanged,我也尝试按照他们所做的去做。

不幸的是,我没有触发 ValueChanged,而是在使用 ValueChanged 回调时收到以下错误。

System.ArgumentException: 'Value does not fall within the expected range.'

这行代码产生错误:

characteristic.ValueChanged += Oncharacteristic_ValueChanged;

这里是我的源代码的更多细节:

注意:我正在为我的加密狗使用 COM 7,我的程序可以发现 BLE 的设备名称,并且可以发现服务和特征的 Uuid。

    public List<string> serviceList = new List<string>();
    public List<string> characteristicList = new List<string>();
    public BluetoothLEDevice myDevice { get; set; }

    public MainPage()
    {
        this.InitializeComponent();
    }

        private async void Page_Loaded(object sender, RoutedEventArgs e)
    {
        // Find the com port
        string selector = SerialDevice.GetDeviceSelector("COM7");
        DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(selector);
        if (devices.Count > 0)
        {
            var dialog = new MessageDialog("Com Device found");
            await dialog.ShowAsync();

            DeviceInformation deviceInfo = devices[0];
            SerialDevice serialDevice = await SerialDevice.FromIdAsync(deviceInfo.Id);
            serialDevice.BaudRate = 9600;
            serialDevice.DataBits = 8;
            serialDevice.StopBits = SerialStopBitCount.One;
            serialDevice.Parity = SerialParity.None;
        }
        else
        {
            MessageDialog popup = new MessageDialog("Sorry, no device found.");
            await popup.ShowAsync();
        }

        // After com port is found, search for device
        foreach (DeviceInformation di in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelector()))
        {
            BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromIdAsync(di.Id);

            // Display BLE device name
            var dialogBleDeviceName = new MessageDialog("BLE Device Name " + bleDevice.Name);
            await dialogBleDeviceName.ShowAsync();

            myDevice = bleDevice;
        }

        // Check device connection
        myDevice.ConnectionStatusChanged += OnConnectionStatusChanged;

        foreach (var service in myDevice.GattServices)
        {
            serviceList.Add(service.Uuid.ToString());

            // Verify if service is discovered by displaying a popup
            MessageDialog serviceUuidPopUp = new MessageDialog("Adding Service Uuid to list " + service.Uuid.ToString() );
            await serviceUuidPopUp.ShowAsync();

            foreach (var characteristic in service.GetAllCharacteristics())
            {
                var characteristicUuid = characteristic.Uuid.ToString().ToLowerInvariant();
                characteristicList.Add(characteristicUuid);

                // Verify if characteristic is discovered by displaying a popup 
                MessageDialog charUuidPopUp = new MessageDialog("Adding characteristic Uuid to list " + characteristicUuid);
                await charUuidPopUp.ShowAsync();

                // set value changed event handlers for characteristics
                characteristic.ValueChanged += Oncharacteristic_ValueChanged;

            }
        }
    }

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

    private void Oncharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
    {
        byte[] data = new byte[args.CharacteristicValue.Length];
        DataReader.FromBuffer(
            args.CharacteristicValue).ReadBytes(data);
        string text = Encoding.UTF8.GetString(data, 0, data.Length);
    }

更新 1 我尝试按照 answer given by rudi belt on SO.

在为我的特征设置值更改事件处理程序之前检查特征属性
if (characteristic.CharacteristicProperties == (GattCharacteristicProperties.Read | GattCharacteristicProperties.Notify))
                {
                    characteristic.ValueChanged += Oncharacteristic_ValueChanged;
                }   

很遗憾,这个 IF 语句没有被执行。

更新 2 我试图删除 ALL Oncharacteristic_ValueChanged 方法中的代码。但它仍然给我同样的错误

System.ArgumentException: 'Value does not fall within the expected range.'

我花了很多时间试图解决这个问题。如果有人可以帮助我,我将非常高兴。谢谢!

阅读您在前一个问题中所做的努力,我可以提供一个工作示例,但首先要进行一些解释。 myDevice.ConnectionStatusChanged 不需要,它仅用于通知连接丢失或已连接。您必须先连接到您的设备并在连接方法中处理事情。

连接成功后,您必须获取包含您要用于读取、写入、通知或指示的特征的服务。

当您选择了服务后,您可以获得该服务的特征。

Select Uuid 的特征,或者在我的例子中 CharacteristicProperties.HasFlag。 在我的例子中这个标志是 Notify。 在代码注释中,您可以找到额外的信息。

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.UI.Popups;
using Windows.UI.Xaml.Controls;

namespace App1
{
public sealed partial class MainPage : Page
{
   GattDeviceServicesResult serviceResult = null;
  private BluetoothLEDevice myDevice;
  private GattCharacteristic selectedCharacteristic;

  public MainPage()
  {
     this.InitializeComponent();
     ConnectDevice();
  }

  private async void ConnectDevice()
  {
     //This works only if your device is already paired!
     foreach (DeviceInformation di in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelector()))
     {
        BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromIdAsync(di.Id);
        // Display BLE device name
        var dialogBleDeviceName = new MessageDialog("BLE Device Name " + bleDevice.Name);
        await dialogBleDeviceName.ShowAsync();
        myDevice = bleDevice;
     }

     if (myDevice != null)
     {
        int servicesCount = 3;//Fill in the amount of services from your device!!!!!
        int tryCount = 0;
        bool connected = false;
        while (!connected)//This is to make sure all services are found.
        {
           tryCount++;
           serviceResult = await myDevice.GetGattServicesAsync();
           if (serviceResult.Status == GattCommunicationStatus.Success && serviceResult.Services.Count >= servicesCount)
           {
              connected = true;
              Debug.WriteLine("Connected in " + tryCount + " tries");
           }
           if (tryCount > 5)//make this larger if faild
           {
              Debug.WriteLine("Failed to connect to device ");
              return;
           }
        }
        if (connected)
        {
           for (int i = 0; i < serviceResult.Services.Count; i++)
           {
              var service = serviceResult.Services[i];
              //This must be the service that contains the Gatt-Characteristic you want to read from or write to !!!!!!!.
              string myServiceUuid = "0000ffe0-0000-1000-8000-00805f9b34fb";
              if (service.Uuid.ToString() == myServiceUuid)
              {
                 Get_Characteriisics(service);
                 break;
              }
           }
        }
     }
  }
  private async void Get_Characteriisics(GattDeviceService myService)
  {
     var CharResult = await myService.GetCharacteristicsAsync();
     if (CharResult.Status == GattCommunicationStatus.Success)
     {
        foreach (GattCharacteristic c in CharResult.Characteristics)
        {
           if (c.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
           {
              selectedCharacteristic = c;
              break;
           }
        }
        try
        {
           // Write the ClientCharacteristicConfigurationDescriptor in order for server to send notifications.               
           var result = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
                                                     GattClientCharacteristicConfigurationDescriptorValue.Notify);
           if (result == GattCommunicationStatus.Success)
           {
              var dialogNotifications = new MessageDialog("Successfully registered for notifications");
              await dialogNotifications.ShowAsync();
              selectedCharacteristic.ValueChanged += SelectedCharacteristic_ValueChanged;
           }
           else
           {
              var dialogNotifications = new MessageDialog($"Error registering for notifications: {result}");
              await dialogNotifications.ShowAsync();
           }
        }
        catch (Exception ex)
        {
           // This usually happens when not all characteristics are found
           // or selected characteristic has no Notify.
           var dialogNotifications = new MessageDialog(ex.Message);
           await dialogNotifications.ShowAsync();
           await Task.Delay(100);
           Get_Characteriisics(myService); //try again
           //!!! Add a max try counter to prevent infinite loop!!!!!!!
        }
     }
     else
     {
        var dialogNotifications = new MessageDialog("Restricted service. Can't read characteristics");
        await dialogNotifications.ShowAsync();
     }
  }

  private void SelectedCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
  {

  }
 }
}

如果您对此代码有任何疑问,请随时在评论中提问。