简体   繁体   English

UWP蓝牙低功耗应用尽早断开连接

[英]UWP Bluetooth Low Energy Application Disconnects Early

So I am designing an application for windows laptops to connect to a custom designed pressure sensor. 因此,我正在为Windows笔记本电脑设计一个应用程序,以连接到定制设计的压力传感器。 The application pairs to the device and then receives notifications from the device every 10 ms. 应用程序与设备配对,然后每10毫秒从设备接收一次通知。 Then for some reason the communication stops. 然后由于某种原因通信停止。 I know it is a problem with my application and not with the device, because when I connect to my phone, I do not have this problem. 我知道这是我的应用程序而不是设备的问题,因为当我连接到手机时,我没有此问题。

Here is the main page where I create the devicewatcher and discover the device: 这是我创建devicewatcher并发现设备的主页:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.Devices.Bluetooth;
using Windows.Devices.Enumeration;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace BLEInterfaceTest
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private DeviceWatcher deviceWatcher;
        private ObservableCollection<DeviceInformation> deviceList = new ObservableCollection<DeviceInformation>();

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

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        this.DataContext = deviceList;
        deviceListView.ItemsSource = deviceList;
        deviceWatcher = DeviceInformation.CreateWatcher(
            "System.ItemNameDisplay:~~\"Button\"",
            new string[] {
                "System.Devices.Aep.DeviceAddress",
                "System.Devices.Aep.IsConnected" },
            DeviceInformationKind.AssociationEndpoint);
        deviceWatcher.Added += DeviceWatcher_Added;
        deviceWatcher.Removed += DeviceWatcher_Removed;
        deviceWatcher.Start();
        base.OnNavigatedTo(e);
        SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
            AppViewBackButtonVisibility.Collapsed;
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        deviceWatcher.Stop();
        base.OnNavigatedFrom(e);
    }

    private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
    {
        var toRemove = (from a in deviceList where a.Id == args.Id select a).FirstOrDefault();

        if (toRemove != null)
        {
            await this.Dispatcher.RunAsync(
                Windows.UI.Core.CoreDispatcherPriority.Normal,
                () => { deviceList.Remove(toRemove); });
        }
    }

    private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
    {
        await this.Dispatcher.RunAsync(
            Windows.UI.Core.CoreDispatcherPriority.Normal,
            () => { deviceList.Add(args); });
    }

    private void deviceListView_ItemClick(object sender, ItemClickEventArgs e)
    {
        this.Frame.Navigate(typeof(DevicePage), e.ClickedItem);
    }
  }
}'

This next code is the page where the pressure sensor is connected to and where data is read from the device. 下一个代码是压力传感器连接到的页面以及从设备读取数据的页面。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Popups;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Bluetooth;
using Windows.Devices.Enumeration;
using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.Storage.Streams;
using System.Threading.Tasks;
using Windows.ApplicationModel.Background;


// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238

namespace BLEInterfaceTest
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class DevicePage : Page
    {
        private DeviceInformation device { get; set; }
        private PressureSensor pSensor { get; set; }
        public static DateTime startTime { get; set; }
        public ObservableCollection<DataPoint> PressureData = new ObservableCollection<DataPoint>();
        public static ObservableCollection<DataPoint> inbetween;
        private static TextBox txtP;
        private BluetoothLEDevice leDevice;
        private DispatcherTimer timer = new DispatcherTimer();
        private int packetNum = 0;

        public DevicePage()
        {
            this.InitializeComponent();
            SystemNavigationManager.GetForCurrentView().BackRequested += DevicePage_BackRequested;
            txtP = txtValue1;
            inbetween = PressureData;
        }

        public static void ChangeText(string text)
        {
            txtP.Text = text;
        }

        private async void InitializePressureSensor(GattDeviceService service)
        {
            pSensor = new PressureSensor(service, SensorUUIDs.PressureSensorUuid);
            await pSensor.EnableNotifications();
            btnStart.IsEnabled = true;
        }

        private async void StartRecievingData()
        {
            try
            {
                leDevice = await BluetoothLEDevice.FromIdAsync(device.Id);
                string selector = "(System.DeviceInterface.Bluetooth.DeviceAddress:=\"" +
                    leDevice.BluetoothAddress.ToString("X") + "\")";
                var services = await leDevice.GetGattServicesAsync(BluetoothCacheMode.Uncached);

                foreach (var service in services.Services)
                {
                    if (service.Uuid.ToString() == SensorUUIDs.ButtonSensorServiceUuid)
                    {
                        InitializePressureSensor(service);
                    }
                }

                timer.Interval = new TimeSpan(0, 0, 0, 0, 1);
                timer.Tick += Timer_Tick1;
                startTime = DateTime.Now;
                timer.Start();
            }

            catch (Exception ex)
            {
                var messageDialog = new MessageDialog("An error has occured Please try again. \n" + ex.Message, "Error!");
            }
        }

        public async void UpdateAllData()
        {
            while (pSensor != null && pSensor.MorePacketsAvailable)
            {
                int[] values = await pSensor.GetPressure();

                int packetNumber = values[0];

                if (packetNumber > packetNum)
                {
                    packetNum = packetNumber;

                    txtValue1.Text = Convert.ToString(values[1]);
                    txtValue2.Text = Convert.ToString(values[5]);

                    for (int i = 1; i < 5; i++)
                    {
                        PressureData.Add(new DataPoint(DateTime.Now - startTime, packetNumber, ((i-1)*2.5 + 10*packetNumber), values[i], values[i + 4]));
                    }
                }
            }
        }

        private void Timer_Tick1(object sender, object e)
        {

            UpdateAllData();
        }

        private async void PairToDevice()
        {
            if (device.Pairing.CanPair)
            {
                var customPairing = device.Pairing.Custom;

                customPairing.PairingRequested += CustomPairing_PairingRequested;

                var result = await customPairing.PairAsync(DevicePairingKinds.ConfirmOnly);

                customPairing.PairingRequested -= CustomPairing_PairingRequested;

                if ((result.Status == DevicePairingResultStatus.Paired) || (result.Status == DevicePairingResultStatus.AlreadyPaired))
                {
                    /*while (device.Pairing.IsPaired == false)
                    {
                        device = await DeviceInformation.CreateFromIdAsync(device.Id);
                    }*/

                    StartRecievingData();
                }


            }

            else if (device.Pairing.IsPaired)
            {
                StartRecievingData();
            }
        }

        private void CustomPairing_PairingRequested(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args)
        {
            args.Accept();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            btnSave.Content = "Save";
            btnStop.IsEnabled = false;
            btnStart.IsEnabled = false;
            this.DataContext = PressureData;
            device = (DeviceInformation)e.Parameter;
            PairToDevice();
            //StartRecievingData();

            base.OnNavigatedTo(e);

            Frame rootFrame = Window.Current.Content as Frame;

            if (rootFrame.CanGoBack)
            {
                SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
                    AppViewBackButtonVisibility.Visible;
            }
        }

        private void DevicePage_BackRequested(object sender, BackRequestedEventArgs eventArgs)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            if (rootFrame == null)
            {
                return;
            }

            // Navigate back if possible, and if the event has already been handled
            if (rootFrame.CanGoBack && eventArgs.Handled ==false)
            {
                eventArgs.Handled = true;
                rootFrame.GoBack();
            }
        }

        private async void btnSave_Click(object sender, RoutedEventArgs e)
        {
            timer.Stop();
            var picker = new FileSavePicker();
            picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
            picker.FileTypeChoices.Add("CSV", new List<string>() { ".csv" });

            StorageFile file = await picker.PickSaveFileAsync();

            if (file != null)
            {
                var stream = await file.OpenAsync(FileAccessMode.ReadWrite);

                using (IOutputStream outputStream = stream.GetOutputStreamAt(0))
                {
                    using (var writer = new DataWriter(outputStream))
                    {
                        foreach (DataPoint p in PressureData)
                        {
                            string text = p.TimeStamp.ToString() + "," + p.PacketNumber.ToString() + "," + p.InternalTimestamp.ToString() + "," + p.PressureValue1.ToString() + "," + p.PressureValue2.ToString() +  "\n";
                            writer.WriteString(text);
                        }

                        await writer.StoreAsync();
                        await writer.FlushAsync();
                    }
                }

                stream.Dispose();
            }
        }

        private async void btnStart_Click(object sender, RoutedEventArgs e)
        {
            if (pSensor != null)
            {
                btnStop.IsEnabled = true;
                btnStart.IsEnabled = false;

                startTime = DateTime.Now;

                if (pSensor != null)
                {
                    await pSensor.BeginCollecting();
                }
            }
        }

        private async void btnStop_Click(object sender, RoutedEventArgs e)
        {
            btnStart.IsEnabled = true;
            btnStop.IsEnabled = false;

            if (pSensor != null)
            {
                await pSensor.StopCollecting();
            }
        }
    }
}

Here is where I define my SensorBase and PressureSensor class that handles the device connection: 在这里定义用于处理设备连接的SensorBase和PressureSensor类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Storage.Streams;
using Windows.Devices.Enumeration;

namespace BLEInterfaceTest
{
    public static class SensorUUIDs
    {
        private static readonly string _packetUuid =           "0000a043-0000-1000-8000-00805f9b34fb";
        private static readonly string _buttonSensorServiceUuid = "0000a042-0000-1000-8000-00805f9b34fb";
        private static readonly string _sensorStateUuid =         "0000a044-0000-1000-8000-00805f9b34fb";

        public static string PressureSensorUuid
        {
            get { return _packetUuid; }
        }

        public static string ButtonSensorServiceUuid
        {
            get { return _buttonSensorServiceUuid; }
        }

        public static string SensorStateUuid
        {
            get { return _sensorStateUuid; }
        }
    }

    public class SensorBase : IDisposable
    {
        protected GattDeviceService deviceService;
        protected string sensorDataUuid;
        protected Queue<byte[]> fifoBuffer;
        protected bool isNotificationSupported = false;
        public bool newData = false;
        private GattCharacteristic dataCharacteristic;

        public SensorBase(GattDeviceService dataService, string sensorDataUuid)
        {
            this.deviceService = dataService;
            this.sensorDataUuid = sensorDataUuid;
            fifoBuffer = new Queue<byte[]>(20);
        }

        public bool MorePacketsAvailable
        {
            get
            {
                if (fifoBuffer.Count > 0)
                {
                    return true;
                }

                else
                {
                    return false;
                }
            }
        }

        public virtual async Task EnableNotifications()
        {
            GattCharacteristicsResult result = await deviceService.GetCharacteristicsAsync();

            foreach (var test in result.Characteristics)
            {
                string t = test.Uuid.ToString();
            }


            isNotificationSupported = true;
            dataCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
                new Guid(sensorDataUuid))).Characteristics[0];
            dataCharacteristic.ValueChanged += dataCharacteristic_ValueChanged;
            GattCommunicationStatus status = await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
                GattClientCharacteristicConfigurationDescriptorValue.Notify);

            var currentDescriptorValue = await dataCharacteristic.ReadClientCharacteristicConfigurationDescriptorAsync();

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

        public virtual async Task DisableNotifications()
        {
            newData = false;
            isNotificationSupported = false;
            dataCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
                new Guid(sensorDataUuid))).Characteristics[0];
            dataCharacteristic.ValueChanged -= dataCharacteristic_ValueChanged;
            GattCommunicationStatus status = await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.None);
        }

        protected async Task<byte[]> ReadValue()
        {
            if (!isNotificationSupported)
            {
                if (dataCharacteristic == null)
                {
                    dataCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
                        new Guid(sensorDataUuid))).Characteristics[0];
                }

                GattReadResult readResult = await dataCharacteristic.ReadValueAsync();
                byte[] data = new byte[readResult.Value.Length];
                DataReader.FromBuffer(readResult.Value).ReadBytes(data);

                fifoBuffer.Enqueue(data);
            }

            return fifoBuffer.Dequeue();
        }

        protected async Task WriteByteArray(string characteristicUuid, byte[] value)
        {
            GattCharacteristic writeCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
                        new Guid(characteristicUuid))).Characteristics[0];

            var writer = new DataWriter();
            writer.WriteBytes(value);
            var res = await writeCharacteristic.WriteValueAsync(writer.DetachBuffer(), GattWriteOption.WriteWithoutResponse);
        }

        private void dataCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
        {
            byte[] data = new byte[args.CharacteristicValue.Length];
            DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);
            fifoBuffer.Enqueue(data);
            newData = true;
        }

        public async void Dispose()
        {
            await DisableNotifications();
        }
    }

    public class PressureSensor: SensorBase
    {
        public PressureSensor(GattDeviceService dataService, string sensorDataUuid)
            : base(dataService, sensorDataUuid)
        {

        }

        public async Task BeginCollecting()
        {
            await WriteByteArray(SensorUUIDs.SensorStateUuid, new byte[] { 0x01 });
        }

        public async Task<int[]> GetPressure()
        {
            byte[] data = await ReadValue();

            if (data != null)
            {
                int[] values = new int[9];

                values[0] = (int)BitConverter.ToInt32(data, 0);

                for (int i = 1; i < values.Length; i++)
                {
                    values[i] = (int)BitConverter.ToInt16(data, 2 * i + 2);
                }

                return values;
            }

            else
            {
                return new int[] { 0 };
            }
        }

        public async Task StopCollecting()
        {
            await WriteByteArray(SensorUUIDs.SensorStateUuid, new byte[] { 0x00 });
        }
    }
}

Here is the DataPoint Class that I use to organize the data received from the pressure sensor: 这是我用来组织从压力传感器接收的数据的DataPoint类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace BLEInterfaceTest
{
    public class DataPoint : INotifyPropertyChanged
    {
        private TimeSpan _timestamp;
        private int _packetNumber;
        private double _internalTimestamp;
        private int _pressure1;
        private int _pressure2;

        public event PropertyChangedEventHandler PropertyChanged;

        public TimeSpan TimeStamp
        {
            get { return _timestamp; }
            set
            {
                _timestamp = value;
                this.NotifyPropertyChanged();
            }
        }

        public int PacketNumber
        {
            get { return _packetNumber; }
            set
            {
                _packetNumber = value;
                this.NotifyPropertyChanged();
            }
        }
        public double InternalTimestamp
        {
            get { return _internalTimestamp; }
            set
            {
                _internalTimestamp = value;
                this.NotifyPropertyChanged();
            }
        }

        public int PressureValue1
        {
            get { return _pressure1; }
            set
            {
                _pressure1 = value;
                this.NotifyPropertyChanged();
            }
        }

        public int PressureValue2
        {
            get { return _pressure2; }
            set
            {
                _pressure2 = value;
                this.NotifyPropertyChanged();
            }
        }

        public DataPoint(TimeSpan time,int packetNumber, double internalTimestamp, int pressure1, int pressure2)
        {
            _timestamp = time;
            _packetNumber = packetNumber;
            _internalTimestamp = internalTimestamp;
            _pressure1 = pressure1;
            _pressure2 = pressure2;
        }

        private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (!string.IsNullOrEmpty(propertyName))
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

I have researched this extensively, and all I could find was help on how to initiate a disconnection. 我对此进行了广泛的研究,而我所能找到的只是如何断开连接的帮助。 I have the opposite problem. 我有相反的问题。 One page I found stated that the problem might be caused by the device not properly storing the bonding state, but I have checked that and I did initialize the device to save the bonding state. 我发现一页显示该问题可能是由于设备未正确存储绑定状态引起的,但是我已经检查了这一点,并且确实对设备进行了初始化以保存绑定状态。

Interestingly if I do not pair the device to the computer before trying to read information from it then I do not have the problem. 有趣的是,如果我在尝试从设备读取信息之前未将设备与计算机配对,那么我就没有问题了。 The connection never randomly stops. 连接永远不会随机停止。 But when I do this, the computer does not receive every packet of data sent from the sensor device. 但是,当我这样做时,计算机不会接收到传感器设备发送的每个数据包。 It will receive one or two packets and then skip five or six packets. 它将接收一两个数据包,然后跳过五个或六个数据包。 If I pair the device then I will receive every packet but the connection will randomly cut off. 如果我配对设备,则我将收到每个数据包,但连接将随机断开。

So my question is two fold, I guess. 我想我的问题有两个。 How do I stop the connection from cutting off when the device is paired? 设备配对后如何停止断开连接? Or alternatively, is there a way to allow the application to receive every packet of data when it is not paired? 或者,是否有一种方法可以让应用程序在未配对时接收每个数据包?

UPDATE UPDATE

I realized I should include more information on my sensor peripheral in case the error is in that code. 我意识到我应该在传感器外围设备上包含更多信息,以防该代码中出现错误。 I am currently designing a rapid prototyping of this sensor before I move on to designing the embedded version. 在继续设计嵌入式版本之前,我目前正在设计此传感器的快速原型。 To do this, I am using the BLE Nano 1 from RedBearLabs as a user friendly prototype. 为此,我将RedBearLabs的BLE Nano 1用作用户友好的原型。 I am programing this device with the online MBED compiler. 我正在使用在线MBED编译器对该设备进行编程。 I have included the nRF51822 and BLE_API libraries to handle the bluetooth low energy communication. 我已经包括了nRF51822和BLE_API库来处理蓝牙低能耗通信。

UPDATE 2 So after more research into what is causing the problem, I have found that the disconnection occurs when a connection interval and a generation 2 garbage collection occur at the same time. 更新2因此,在对引起问题的原因进行了更多研究之后,我发现当连接间隔和第2代垃圾回收同时发生时,就会发生断开连接。 In UWP the garbage collector can pause the UI Thread for generation 2 collections. 在UWP中,垃圾收集器可以暂停第2代收集的UI线程。 (see here ) (请参阅此处

My thought is that if the thread is paused at the beginning of a connection interval, then the central is not able to initiate the connection with the peripheral and the peripheral therefore thinks the client is no longer listening (see more about how BLE connections work ). 我的想法是,如果线程在连接间隔开始时暂停,那么中心将无法启动与外围设备的连接,因此外围设备认为客户端不再侦听(请参阅有关BLE连接的更多信息) 。

I discovered this by finding out exactly what is necessary to get the connection back once it has randomly stopped. 我通过找出随机中断后恢复连接的确切条件来发现这一点。 I started with the entire connection process and reduced it down to this: 我从整个连接过程开始,并将其简化为:

public async Task ReconnectDevice()
{
   GattCommunicationStatus status = await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
      GattClientCharacteristicConfigurationDescriptorValue.Notify);

   await WriteByteArray(SensorUUIDs.SensorStateUuid, new byte[] { 0x01 });
}

Because my BluetoothLEDevice, GattService, and GattCharacteristic objects are not disposed, all I need to do is resubscribe to notifications and write a 1 to the device so that it begins collecting data again. 因为未处理我的BluetoothLEDevice,GattService和GattCharacteristic对象,所以我要做的就是重新订阅通知,并将1写入设备,以便它再次开始收集数据。

I have reduced my memory allocations in my application significantly since discovering this, and the time for a gen2 collection has decreased to an average of 5 ms. 自发现这一点以来,我已大大减少了我的应用程序中的内存分配,并且gen2收集的时间平均减少了5毫秒。 Also, the amount of time before the connection disconnects has increased to around 4-5 sec. 同样,连接断开之前的时间已增加到大约4-5秒。

UWP has a GattCharacteristicNotificationTrigger for receiving notifications in a BackgroundTask, but I have never had much success at incorporating background tasks in UWP. UWP具有用于在BackgroundTask中接收通知的GattCharacteristicNotificationTrigger,但是我在将UWP中的后台任务并入方面从未取得过成功。

I think I will try next to incorporate the windows.devices into a WPF application where I think I will have a better chance at getting it working. 我想我接下来将尝试将windows.devices集成到WPF应用程序中,在该应用程序中,我认为我会有更多的机会使其运行。

So, after a while of trying different ideas I have finally stumbled across a solution to my problem. 因此,经过一段时间尝试不同的想法,我终于偶然发现了解决我的问题的方法。 I had to make 2 changes: 我必须进行2个更改:

  1. Used the unpaired connection instead of the paired connection. 使用未配对的连接,而不是配对的连接。 This solved the problem of the connection dropping suddenly. 这样解决了连接突然掉线的问题。

  2. Increased the connection interval to 40 ms. 将连接间隔增加到40 ms。 For some reason when I did this, I received all of the data and no longer had any problems. 由于某些原因,我收到了所有数据,不再遇到任何问题。 Anything below 40 ms causes information to be lost when communicating to a Windows device (I had to make this change on the C code running on my sensors.) 与Windows设备通信时,任何低于40毫秒的时间都会导致信息丢失(我必须在运行于传感器上的C代码上进行此更改。)

I have used the devices for about 2 months now after making this change and have had no problems at all. 进行此更改后,我已经使用了大约2个月的设备,并且完全没有问题。

I seems to me that these problems are related to the BluetoothCacheMode Enum. 在我看来,这些问题与BluetoothCacheMode枚举有关。 This indicates whether certain Bluetooth API methods should operate on values cached in the system or retrieve those values from the Bluetooth device. 这表明某些蓝牙API方法是应该对系统中缓存的值进行操作还是从蓝牙设备中检索这些值。 Using BluetoothCacheMode.Uncached attribute allows the service to update the attributes when needed. 使用BluetoothCacheMode.Uncached属性允许服务在需要时更新属性。 If the device is paired then the BluetoothCacheMode is not needed(I think BluetoothCacheMode.Cached is default). 如果设备已配对,则不需要BluetoothCacheMode(我认为BluetoothCacheMode.Cached是默认设置)。 In your code the line: 在您的代码行中:

var services = await leDevice.GetGattServicesAsync(BluetoothCacheMode.Uncached);

Can be the cause of the connection lost if paired. 如果配对,可能会导致连接丢失。

GetGattServicesAsync(), GetCharacteristicsAsync() and ReadValueAsync() must have the attribute BluetoothCacheMode.Uncached when not paired, when paired default or BluetoothCacheMode.Cached. GetGattServicesAsync(),GetCharacteristicsAsync()和ReadValueAsync()必须具有属性BluetoothCacheMode.Uncache(未配对),默认配对或BluetoothCacheMode.Cached(未配对)。 See https://msdn.microsoft.com/en-us/library/windows/apps/dn263758.aspx . 请参阅https://msdn.microsoft.com/en-us/library/windows/apps/dn263758.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM