行业知识
C#和低功耗蓝牙BLE通讯
@TOC
前言
以前都是用手机APP和蓝牙设备通信,现在在一个项目中需要更改为用电脑端上位机与蓝牙通讯的需求,在此记录自己走过的坑和积攒的经验。
特别感谢
未曾接触过的东西,首先就是在网上搜索资料,站在巨人的肩膀上好办事。在此特别感谢以下几个博客,就是参考大神们的博客写出来的。
1 C# ble 4.0 低能耗 蓝牙交互 : https://blog.csdn.net/code_long/article/details/105636398
这篇文章给出了完整的示例代码,也有70+的讨论,对一些搜索缓慢的问题做了修复。以及一些dll引用的问题和路径。
2 Win10 平台C#与低功耗蓝牙BLE设备通信案例 https://blog.csdn.net/shengfakun1234/article/details/110928783
第二篇文章对于获取不到蓝牙服务特征列表的问题进行了修复
3 MSDN有关蓝牙的介绍
1 通用 Windows 平台应用中的低能耗蓝牙: https://learn.microsoft.com/zh-cn/windows/uwp/devices-sensors/bluetooth-low-energy-overview
2 DeviceInformation.CreateWatcher 方法: https://learn.microsoft.com/zh-cn/uwp/api/windows.devices.enumeration.deviceinformation.createwatcher?view=winrt-22621
3 Bluetooth 硬件: https://learn.microsoft.com/zh-cn/windows-hardware/design/component-guidelines/bluetooth?redirectedfrom=MSDN
4 蓝牙调试助手 https://github.com/shijianoo/BluetoothLEAssistant/blob/master/%E8%93%9D%E7%89%99%E8%B0%83%E8%AF%95%E5%8A%A9%E6%89%8B/ViewModel/WatcherViewModel.cs
踩过的坑
1 使用的dll
需要注意的是我们使用的低功耗蓝牙BLE,如果使用一些库32feet.NET、InTheHand等,是搜索不到低功耗蓝牙的,只能搜索到经典蓝牙。
我们需要用MSDN自带的库:System.Runtime.WindowsRuntime.dll和 Windows.winmd。路径如下,自己安装在不同磁盘路径可能稍微有点不同:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd
2 上位机运行环境
必须是win10系统, win7系统不支持BLE通信,win8没有尝试过。 笔记本自带蓝牙,台式电脑没有蓝牙,可以买个蓝牙适配器插在电脑上用。
3 如何过滤蓝牙
现象是这样子的:第一次搜索到蓝牙A之后,关闭蓝牙A的电源,再次搜索还能搜索到蓝牙A,这是不科学的。 https://www.icode9.com/content-3-288234.html 同一个问题,它这个答案我这儿也不适用,感兴趣的可以看看。
这种不可学的情况是我在使用DeviceWatcher类搜索蓝牙的时候发现的,无论怎么设置过滤条件,都不起作用。
“System.Devices.Aep.DeviceAddress”,
“System.Devices.Aep.IsConnected”,
“System.Devices.Aep.Bluetooth.Le.IsConnectable” ,
“System.Devices.Aep.SignalStrength”,
“System.Devices.Aep.IsPresent”
最后是换了BluetoothLEAdvertisementWatcher类去搜索蓝牙,就解决了上述问题。参考这篇博文Win10 平台C#与低功耗蓝牙BLE设备通信案例的蓝牙搜索部分即可。
4 搜索不到蓝牙的服务和特征值
这一种方法在我电脑上是搜索不到服务的。
/// /// 获取蓝牙服务/// public async void FindService(){ var GattServices = this.CurrentDevice.GattServices; foreach (GattDeviceService ser in GattServices) { this.GattDeviceServiceAdded(ser); }} 改成下面的这种写法才能获取服务,特征值也是一样的道理。
/// /// 获取蓝牙服务 /// public async void FindService() { this.CurrentDevice.GetGattServicesAsync().Completed = async (asyncInfo, asyncStatu) => { if(asyncStatu == AsyncStatus.Completed) { var sevices = asyncInfo.GetResults().Services; foreach(GattDeviceService ser in sevices) { this.GattDeviceServiceAdded(ser); } } }; } 5 如何收发蓝牙数据
如果还是刚刚接触到蓝牙,什么都不懂的,可以先看看蓝牙通讯协议,可参考该博文:经典蓝牙与低功耗蓝牙BLE开发基础知识:服务、特征、属性、UUIDhttps://blog.csdn.net/weixin_51484460/article/details/124906595
简单来说就是,Service是服务,Characteristic则是特征值。一般来说,蓝牙里面有多个Service,一个Service里面包括多个Characteristic。
一个蓝牙协议里面包含的Service和Characteristic是比较多的 ,那么这么多的同名属性用什么来区分呢?
就是UUID,每个Service或者Characteristic都有一个 128 bit 的UUID来标识。
Service可以理解为一个功能集合,而Characteristic比较重要,蓝牙设备正是通过Characteristic来进行设备间的交互的,这些Characteristic又包含一些属性Property,如读、写、订阅等操作。
我们得按照自己的需求更改SetOpteron(GattCharacteristic gattCharacteristic)这个函数,而不能照搬这个函数。
蓝牙包含哪些服务,服务下有含有哪些特征值,这个特征值的属性是可读,可写还是可订阅,这些可以通过蓝牙厂商获取,或如果是自己公司开发的话,那问相关的开发人员会更清楚。
效果图
蓝牙类的代码
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Windows.Devices.Bluetooth;using Windows.Devices.Bluetooth.Advertisement;using Windows.Devices.Bluetooth.GenericAttributeProfile;using Windows.Devices.Enumeration;using Windows.Foundation;using Windows.Security.Cryptography;namespace Bluetoolth{ public enum MsgType { NotifyTxt, BleDevice, BleSendData, BleRecData, } public class BleCore { private bool asyncLock = false; /// /// 搜索蓝牙设备对象 /// private DeviceWatcher deviceWatcher; /// /// 当前连接的服务 /// public GattDeviceService CurrentService { get; set; } /// /// 当前连接的蓝牙设备 /// public BluetoothLEDevice CurrentDevice { get; set; } /// /// 写特征对象 /// public GattCharacteristic CurrentWriteCharacteristic { get; set; } /// /// 写名称特征对象 /// public GattCharacteristic CurrentNameCharacteristic { get; set; } /// /// 通知特征对象 /// public GattCharacteristic CurrentNotifyCharacteristic { get; set; } /// /// 特性通知类型通知启用 /// private const GattClientCharacteristicConfigurationDescriptorValue CHARACTERSITIC_NOTIFICATION_TYPE = GattClientCharacteristicConfigurationDescriptorValue.Notify; /// /// 存储检测到的设备 /// private List DevicesList = new List(); /// /// 定义搜索蓝牙设备委托 /// /// /// public delegate void DevicewatcherChangedEvent(MsgType type, BluetoothLEDevice bluetoothLEDevice); /// /// 搜索蓝牙事件 /// public event DevicewatcherChangedEvent DevicewatcherChanged; /// /// 获取服务委托 /// /// public delegate void GattDeviceServiceAddedEvent(GattDeviceService gattDeviceService); /// /// 获取服务事件 /// public event GattDeviceServiceAddedEvent GattDeviceServiceAdded; /// /// 获取特征委托 /// /// public delegate void CharacteristicAddedEvent(GattCharacteristic gattCharacteristic); /// /// 获取特征事件 /// public event CharacteristicAddedEvent CharacteristicAdded; /// /// 提示信息委托 /// /// /// /// public delegate void MessageChangedEvent(MsgType type, string message, byte[] data = null); /// /// 提示信息事件 /// public event MessageChangedEvent MessageChanged; /// /// 当前连接蓝牙的Mac /// private string CurrentDeviceMAC { get; set; } public BleCore() { } /// /// 搜索蓝牙设备 方法1 /// public void StartBleDevicewatcher_1() { string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected", "System.Devices.Aep.Bluetooth.Le.IsConnectable" , "System.Devices.Aep.SignalStrength", "System.Devices.Aep.IsPresent" }; string aqsAllBluetoothLEDevices = "(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")"; string Selector = "System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\""; string selector = "(" + Selector + ")" + " AND (System.Devices.Aep.CanPair:=System.StructuredQueryType.Boolean#True OR System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#True)"; this.deviceWatcher = DeviceInformation.CreateWatcher( // aqsAllBluetoothLEDevices, // BluetoothLEDevice.GetDeviceSelectorFromPairingState(false), selector, requestedProperties, DeviceInformationKind.AssociationEndpoint); //在监控之前注册事件 this.deviceWatcher.Added += DeviceWatcher_Added; this.deviceWatcher.Stopped += DeviceWatcher_Stopped; this.deviceWatcher.Updated += DeviceWatcher_Updated; ; this.deviceWatcher.Start(); string msg = "自动发现设备中.."; this.MessageChanged(MsgType.NotifyTxt, msg); } BluetoothLEAdvertisementWatcher watcher; /// /// 搜索蓝牙设备 方法2 /// public void StartBleDevicewatcher() { watcher = new BluetoothLEAdvertisementWatcher(); watcher.ScanningMode = BluetoothLEScanningMode.Active; // only activate the watcher when we're recieving values >= -80 watcher.SignalStrengthFilter.InRangeThresholdInDBm = -80; // stop watching if the value drops below -90 (user walked away) watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90; // register callback for when we see an advertisements watcher.Received += OnAdvertisementReceived; watcher.Stopped += Watcher_Stopped; // wait 5 seconds to make sure the device is really out of range watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000); watcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000); // starting watching for advertisements watcher.Start(); string msg = "自动发现设备中.."; this.MessageChanged(MsgType.NotifyTxt, msg); } private void Watcher_Stopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args) { DevicesList.Clear(); string msg = "自动发现设备停止"; this.MessageChanged(MsgType.NotifyTxt, msg); } private void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs) { BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress).Completed = async (asyncInfo, asyncStatus) => { if (asyncStatus == AsyncStatus.Completed) { if (asyncInfo.GetResults() == null) { //this.MessAgeChanged(MsgType.NotifyTxt, "没有得到结果集"); } else { BluetoothLEDevice currentDevice = asyncInfo.GetResults(); if (currentDevice.Name.StartsWith("Bluetooth")) { return; } Boolean contain = false; foreach (BluetoothLEDevice device in DevicesList)//过滤重复的设备 { if (device.DeviceId == currentDevice.DeviceId) { contain = true; } } if (!contain) { byte[] _Bytes1 = BitConverter.GetBytes(currentDevice.BluetoothAddress); Array.Reverse(_Bytes1); this.DevicesList.Add(currentDevice); this.MessageChanged(MsgType.NotifyTxt, "发现设备:" + currentDevice.Name + " address:" + BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower()); this.DevicewatcherChanged(MsgType.BleDevice, currentDevice); } } } }; } /// /// 停止搜索 /// public void StopBleDeviceWatcher() { if(deviceWatcher != null) this.deviceWatcher.Stop(); if (watcher != null && watcher.Status == BluetoothLEAdvertisementWatcherStatus.Started) watcher.Stop(); } /// /// 获取发现的蓝牙设备 /// /// /// private void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args) { this.MessageChanged(MsgType.NotifyTxt, "发现设备:" + args.Id); this.Matching(args.Id, args); } private void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate args) { } /// /// 停止搜索蓝牙设备 /// /// /// private void DeviceWatcher_Stopped(DeviceWatcher sender, object args) { string msg = "自动发现设备停止"; this.MessageChanged(MsgType.NotifyTxt, msg); } /// /// 匹配 /// /// public void StartMatching(BluetoothLEDevice device) { this.CurrentDevice = device; } /// /// 获取蓝牙服务 /// public async void FindService() { /*var gattServices = this.CurrentDevice.GattServices; foreach(GattDeviceService ser in gattServices) { this.GattDeviceServiceAdded(ser); }*/ this.CurrentDevice.GetGattServicesAsync().Completed = async (asyncInfo, asyncStatu) => { if(asyncStatu == AsyncStatus.Completed) { var sevices = asyncInfo.GetResults().Services; foreach(GattDeviceService ser in sevices) { this.GattDeviceServiceAdded(ser); // FindCharacteristic(ser); } } }; } public async void FindCharacteristic(GattDeviceService gattDeviceService) { /* this.CurrentService = gattDeviceService; foreach(var c in gattDeviceService.GetAllCharacteristics()) { this.CharacteristicAdded(c); }*/ gattDeviceService.GetCharacteristicsAsync().Completed = async (asyncInfo, asyncStatu) => { if (asyncStatu == AsyncStatus.Completed) { var chara = asyncInfo.GetResults().Characteristics; foreach (GattCharacteristic c in chara) { this.CharacteristicAdded(c); } } }; } /// /// 获取操作 /// /// /// public async Task SetOpteron(GattCharacteristic gattCharacteristic) { if(gattCharacteristic.CharacteristicProperties == GattCharacteristicProperties.WriteWithoutResponse) { this.CurrentWriteCharacteristic = gattCharacteristic; } if (gattCharacteristic.CharacteristicProperties == GattCharacteristicProperties.Notify) { this.CurrentNotifyCharacteristic = gattCharacteristic; this.CurrentNotifyCharacteristic.ProtectionLevel = GattProtectionLevel.Plain; this.CurrentNotifyCharacteristic.ValueChanged += Characteristic_ValueChanged; await this.EnableNotifications(CurrentNotifyCharacteristic); } if (gattCharacteristic.CharacteristicProperties == ( GattCharacteristicProperties.Read | GattCharacteristicProperties.Write)) { this.CurrentNameCharacteristic = gattCharacteristic; } this.Connect(); } private async Task Connect() { byte[] _Bytes1 = BitConverter.GetBytes(this.CurrentDevice.BluetoothAddress); Array.Reverse(_Bytes1); this.CurrentDeviceMAC = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower(); string msg = "正在连接设备 .."; this.MessageChanged(MsgType.NotifyTxt, msg); this.CurrentDevice.ConnectionStatusChanged += CurrentDevice_ConnectionStatusChanged; } private void CurrentDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args) { if(sender.ConnectionStatus == BluetoothConnectionStatus.Disconnected && CurrentDeviceMAC != null) { string msg = "设备已断开,自动重连"; MessageChanged(MsgType.NotifyTxt, msg); if(!asyncLock) { asyncLock = true; this.CurrentDevice.Dispose(); this.CurrentDevice = null; this.CurrentNotifyCharacteristic = null; this.CurrentWriteCharacteristic = null; SelectDeviceFromIdAsync(CurrentDeviceMAC); } }else { string msg = "设备已连接"; MessageChanged(MsgType.NotifyTxt, msg); } } /// /// 搜索到的蓝牙设备 /// /// /// private async Task Matching(string id, DeviceInformation args = null) { try { BluetoothLEDevice.FromIdAsync(id).Completed = async (asyncInfo, asyncStatus) => { if (asyncStatus == AsyncStatus.Completed) { BluetoothLEDevice bleDevice = asyncInfo.GetResults(); if (bleDevice.Name.StartsWith("Bluetooth")) { return; } BluetoothLEDevice tmp = this.DevicesList.Where(p => p.Name == bleDevice.Name).FirstOrDefault(); if(tmp == null) {//没有添加过 // bool state = IsConnectable(bleDevice.DeviceInformation); this.DevicesList.Add(bleDevice); this.DevicewatcherChanged(MsgType.BleDevice, bleDevice); } } }; } catch(Exception e) { string msg = "没有发现设备" + e.ToString(); this.MessageChanged(MsgType.NotifyTxt, msg); this.StopBleDeviceWatcher(); } } /// /// 主动断开连接 /// public void Dispose() { CurrentDeviceMAC = null; CurrentService?.Dispose(); CurrentDevice?.Dispose(); CurrentDevice = null; CurrentService = null; CurrentWriteCharacteristic = null; CurrentNotifyCharacteristic = null; this.MessageChanged(MsgType.NotifyTxt, "主动断开连接"); } /// /// 按MAC地址直接组装设备ID查找设备 /// /// /// public async Task SelectDeviceFromIdAsync(string MAC) { CurrentDeviceMAC = MAC; CurrentDevice = null; BluetoothAdapter.GetDefaultAsync().Completed = async (asyncInfo, asyncStatus) => { if (asyncStatus == AsyncStatus.Completed) { BluetoothAdapter bluetoothAdapter = asyncInfo.GetResults(); // ulong 转为byte数组 byte[] _Bytes1 = BitConverter.GetBytes(bluetoothAdapter.BluetoothAddress); Array.Reverse(_Bytes1); string macAddress = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower(); string Id = "BluetoothLe#BluetoothLe" + macAddress + "-" + MAC; await Matching(Id); } }; } /// /// 设置特征对象为接收通知对象 /// /// /// public async Task EnableNotifications(GattCharacteristic characteristic) { string msg = "收通知对象=" + CurrentDevice.ConnectionStatus; this.MessageChanged(MsgType.NotifyTxt, msg); characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(CHARACTERSITIC_NOTIFICATION_TYPE).Completed = async (asyncInfo, asyncStatus) => { if (asyncStatus == AsyncStatus.Completed) { GattCommunicationStatus status = asyncInfo.GetResults(); if (status == GattCommunicationStatus.Unreachable) { msg = "设备不可用"; this.MessageChanged(MsgType.NotifyTxt, msg); if (CurrentNotifyCharacteristic != null && !asyncLock) { await this.EnableNotifications(CurrentNotifyCharacteristic); } } asyncLock = false; msg = "设备连接状态" + status; this.MessageChanged(MsgType.NotifyTxt, msg); } }; } /// /// 接受到蓝牙数据 /// private void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args) { byte[] data; CryptographicBuffer.CopyToByteArray(args.CharacteristicValue, out data); string str = BitConverter.ToString(data); this.MessageChanged(MsgType.BleRecData, str, data); } /// /// 发送数据接口 /// /// public async Task Write(byte[] data) { if (CurrentWriteCharacteristic != null) { CurrentWriteCharacteristic.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(data), GattWriteOption.WriteWithResponse); string str = "发送数据:" + BitConverter.ToString(data); this.MessageChanged(MsgType.BleSendData, str, data); } } /// /// 发送数据接口 /// /// public async Task WriteName(byte[] data) { if (CurrentNameCharacteristic != null) { CurrentNameCharacteristic.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(data), GattWriteOption.WriteWithResponse); string str = "发送数据:" + BitConverter.ToString(data); this.MessageChanged(MsgType.BleSendData, str, data); } } }} 调用类
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using Windows.Devices.Bluetooth;using Windows.Devices.Bluetooth.Advertisement;using Windows.Devices.Bluetooth.GenericAttributeProfile;using Windows.Devices.Enumeration;using Windows.Foundation;using System.Net.NetworkInformation;namespace HPBluetoolth{ public partial class BlueForm : Form { BleCore bleCore = new BleCore(); /// /// 存储检测到的设备 /// List DeviceList = new List(); /// /// 当前蓝牙服务列表 /// List GattDeviceServices = new List(); /// /// 当前蓝牙服务特征列表 /// List GattCharacteristics = new List(); public BlueForm() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false; this.bleCore.MessageChanged += BleCore_MessAgeChanged; this.bleCore.DevicewatcherChanged += BleCore_DeviceWatcherChanged; this.bleCore.GattDeviceServiceAdded += BleCore_GattDeviceServiceAdded; this.bleCore.CharacteristicAdded += BleCore_CharacteristicAdded; this.Init(); } private void Init() { this.Load += BlueForm_Load; //开始 btnStart.Click += BtnStart_Click; //搜索蓝牙 this.btnSearch.Click += btnSearch_Click; this.btnConnect.Click += BtnConnect_Click; //获取服务 this.btnServes.Click += BtnServes_Click; //获取特征 this.btnFeatures.Click += BtnFeatures_Click; //获取操作 this.btnOpt.Click += BtnOpt_Click; //读取 this.btnRead.Click += BtnRead_Click; //发送 this.btnWrite.Click += BtnWrite_Click; this.FormClosing += BlueForm_FormClosing; } private void BlueForm_Load(object sender, EventArgs e) { } private void BtnStart_Click(object sender, EventArgs e) { string str = tbCode.Text; byte[] buffer = Encoding.UTF8.GetBytes(str); this.bleCore.WriteName(buffer); } bool Closing = false; private void BlueForm_FormClosing(object sender, FormClosingEventArgs e) { Closing = true; bleCore.Dispose(); } // 异步线程 public static void RunAsync(Action action) { ((Action)(delegate () { action.Invoke(); })).BeginInvoke(null, null); } /// /// 搜索蓝牙 /// /// /// private void btnSearch_Click(object sender, EventArgs e) { try { if (this.btnSearch.Text == "查找") { this.listboxMessage.Items.Clear(); this.listboxBleDevice.Items.Clear(); this.bleCore.StartBleDevicewatcher(); this.btnSearch.Text = "停止"; } else { this.bleCore.StopBleDeviceWatcher(); this.btnSearch.Text = "查找"; } }catch(Exception ex) { MessageBox.Show(ex.Message); } } /// /// 提示消息 /// private void BleCore_MessAgeChanged(MsgType type, string message, byte[] data) { if (Closing) return; RunAsync(() => { this.listboxMessage.Items.Add(message); }); } /// /// 搜索蓝牙设备列表 /// private void BleCore_DeviceWatcherChanged(MsgType type, Windows.Devices.Bluetooth.BluetoothLEDevice bluetoothLEDevice) { if (Closing) return; RunAsync(() => { this.listboxBleDevice.Items.Add(bluetoothLEDevice.Name); this.DeviceList.Add(bluetoothLEDevice); }); } /// /// 连接蓝牙 /// /// /// private void BtnConnect_Click(object sender, EventArgs e) { if(this.listboxBleDevice.SelectedItem == null) { MessageBox.Show("请选择连接的蓝牙"); return; } string deviceName = this.listboxBleDevice.SelectedItem.ToString(); Windows.Devices.Bluetooth.BluetoothLEDevice bluetoothLEDevice = this.DeviceList.Where(u => u.Name == deviceName).FirstOrDefault(); if(bluetoothLEDevice == null) { MessageBox.Show("没有发现此蓝牙,请重新搜索"); return; } //两个蓝牙进行匹配 bleCore.StartMatching(bluetoothLEDevice); } /// /// 获取服务 /// /// /// private void BtnServes_Click(object sender, EventArgs e) { this.cmbServer.Items.Clear(); this.bleCore.FindService(); } /// /// 获取服务列表 /// /// private void BleCore_GattDeviceServiceAdded(GattDeviceService gattDeviceService) { // RunAsync(() => // { this.cmbServer.Items.Add(gattDeviceService.Uuid.ToString()); this.GattDeviceServices.Add(gattDeviceService); this.btnFeatures.Enabled = true; // }); } /// /// 获取特征 /// /// /// private void BtnFeatures_Click(object sender, EventArgs e) { this.cmbFeatures.Items.Clear(); if(this.cmbServer.SelectedItem == null) { MessageBox.Show("选择蓝牙服务"); return; }else { var item = this.GattDeviceServices.Where(u => u.Uuid == new Guid(this.cmbServer.SelectedItem.ToString())).FirstOrDefault(); //获取蓝牙特征 this.bleCore.FindCharacteristic(item); } } /// /// 获取特征列表 /// /// private void BleCore_CharacteristicAdded(GattCharacteristic gattCharacteristic) { // RunAsync(() => // { this.cmbFeatures.Items.Add(gattCharacteristic.Uuid); this.GattCharacteristics.Add(gattCharacteristic); this.btnOpt.Enabled = true; // }); } /// /// 获取操作 /// /// /// private void BtnOpt_Click(object sender, EventArgs e) { if(this.cmbFeatures.SelectedItem == null) { MessageBox.Show("请选择蓝牙服务"); return; } var item = this.GattCharacteristics.Where(u => u.Uuid == new Guid(this.cmbFeatures.SelectedItem.ToString())).FirstOrDefault(); //获取操作 this.bleCore.SetOpteron(item); if(item.CharacteristicProperties == (GattCharacteristicProperties.Read | GattCharacteristicProperties.Write)) { this.btnRead.Enabled = true; this.btnWrite.Enabled = true; } } /// /// 读取 /// /// /// private void BtnRead_Click(object sender, EventArgs e) { string str = tbReadWriteInfo.Text; string[] arr = str.Split(' '); byte[] buffer = new byte[7]; for(int i=0; i buffer[i] = Convert.ToByte(arr[i], 16); } //CRC校验 ushort crc = CRC(buffer, 5); buffer[5] = (byte)((crc & 0xFF00) > 8); buffer[6] = (byte)((crc & 0x00FF)); this.bleCore.Write(buffer); } /// /// 写入 /// /// /// private void BtnWrite_Click(object sender, EventArgs e) { string str = tbReadWriteInfo.Text; string[] arr = str.Split(' '); byte[] buffer = new byte[9]; for (int i = 0; i > 8); buffer[8] = (byte)((crc & 0x00FF)); this.bleCore.Write(buffer); } /// /// CRC校验 /// /// /// /// public static ushort CRC(byte[] data, int length) { ushort tempCrcResult = 0xffff; for (int i = 0; i > 1) ^ 0xa001); else tempCrcResult = (ushort)(tempCrcResult >> 1); } } return (tempCrcResult = (ushort)(((tempCrcResult & 0xff) > 8))); } }} 结尾
至此,低功耗蓝牙的搜索和通讯就完成了,感谢大神们贴的博文。
如何正常的关闭(断开)蓝牙连接
因工作上的进一步需要,我也遇到了这个问题,今天调试了一个上午,终于可以正常断开了。特此记录一下,
想直接在评论区写的,奈何写的比较啰嗦,给的字数不够用,就加在后文了。
也是根据这篇“The BLE Device Disconnection not working on UWP C#” 问答的思路写的,总的来说就是将一切引用到当前BluetoothLEDevice对象都要释放掉,否则是不能正常断开蓝牙的。
我因为BluetoothLEDevice对象在三个地方都存着有,一个是BluetoothLEDevice对象列表(List),还有两个类(BleCore,BlueForm)之中也有引用这个对象,所以找起来还是有点费劲的。GATT通道也务必要关闭哈。
BLE蓝牙正常断开的方法,请执行以下步骤,不分先后:
1 关闭GATT服务通道:
//关闭该蓝牙的所有服务 foreach(var sev in GattDeviceServices) { sev.Dispose(); } 2 移除事件监听器:(非必要,不移除也行,但可能会有内存泄漏啥的)
if(CurrentDevice != null) CurrentDevice.ConnectionStatusChanged -= CurrentDevice_ConnectionStatusChanged;
3 释放BluetoothLEDevice对象:(包括存储在 List DeviceList中的,或者指向当前BluetoothLEDevice对象的,都要释放)。
//找到在蓝牙列表里面执行当前蓝牙的对象 string deviceName = this.listboxBleDevice.SelectedItem.ToString(); Windows.Devices.Bluetooth.BluetoothLEDevice bluetoothLEDevice = this.DeviceList.Where(u => u.Name == deviceName).FirstOrDefault(); if (bluetoothLEDevice != null) {//从列表中移除 this.DeviceList.Remove(bluetoothLEDevice); } if (bluetoothLEDevice != null) {//关闭列表中的蓝牙 bluetoothLEDevice.Dispose(); } bluetoothLEDevice = null; //蓝牙类的关闭 this.bleCore.DisConnect(); 完整断开蓝牙连接代码,如下:
//断开 private void BtnDisConent_Click(object sender, EventArgs e) { //找到在蓝牙列表里面执行当前蓝牙的对象 string deviceName = this.listboxBleDevice.SelectedItem.ToString(); Windows.Devices.Bluetooth.BluetoothLEDevice bluetoothLEDevice = this.DeviceList.Where(u => u.Name == deviceName).FirstOrDefault(); if (bluetoothLEDevice != null) {//从列表中移除 this.DeviceList.Remove(bluetoothLEDevice); } //关闭该蓝牙的所有服务 foreach(var sev in GattDeviceServices) { sev.Dispose(); } //并清空 GattDeviceServices.Clear(); GattCharacteristics.Clear(); if (bluetoothLEDevice != null) {//关闭列表中的蓝牙 bluetoothLEDevice.Dispose(); } bluetoothLEDevice = null; //蓝牙类的关闭 this.bleCore.DisConnect(); //释放内存 GC.Collect(); } bleCore.DisConnect方法:
/// /// 主动断开连接 /// public void Dispose() { IsConnect = false; CurrentDeviceMAC = null; //使用到的服务 (我这里仅仅使用了一个服务) CurrentService?.Dispose(); //蓝牙 if(CurrentDevice != null) CurrentDevice.ConnectionStatusChanged -= CurrentDevice_ConnectionStatusChanged; //关闭 CurrentDevice?.Dispose(); CurrentDevice = null; CurrentService = null; //特征值 CurrentNameCharacteristic = null; CurrentWriteCharacteristic = null; CurrentNotifyCharacteristic = null; }
上一篇:怎么架服务器开私服?