1、需要使用到的动态库
Bluetooth
Microsoft.Windows.SDK.Contracts
2、需要使用到的命名控件
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;
3、创建蓝牙设备对象
public BluetoothTools()
{
if (deviceWatcher == null)
{
deviceWatcher = new BluetoothLEAdvertisementWatcher();
deviceWatcher.ScanningMode = BluetoothLEScanningMode.Active;//扫描模式
deviceWatcher.SignalStrengthFilter.InRangeThresholdInDBm = -80;
deviceWatcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -90;
deviceWatcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
deviceWatcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);
deviceWatcher.Received += DeviceWatcher_Received;
deviceWatcher.Stopped += DeviceWatcher_Stopped;
}
}
/// <summary>
/// 蓝牙搜索停止时触发事件
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void DeviceWatcher_Stopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args)
{
//搜索停止
this.DeviceSearchComplete?.Invoke(this.BluetoothList);
}
/// <summary>
/// 扫描到蓝牙设备时处理方法
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void DeviceWatcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress).Completed = async (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
if (asyncInfo.GetResults() != null)
{
BluetoothLEDevice currentDevice = asyncInfo.GetResults();
if (currentDevice.Name.ToUpper().StartsWith("FS"))
{
bool state = BluetoothList.Where(x => x.BluetoothDeviceId == currentDevice.DeviceId).ToList().Count > 0;
if (!state)
{
BluetoothInfo info = new BluetoothInfo()
{
BluetoothName = currentDevice.Name,
BluetoothDeviceId = currentDevice.DeviceId,
BluetoothMac = currentDevice.DeviceId.Split('-')[1]
};
BluetoothList.Add(info); //添加设备到蓝牙列表
DeviceWatcherChanged(info);
}
}
currentDevice.Dispose();//释放掉蓝牙设备
}
}
};
}
4、开启蓝牙搜索,并在一定时间后停止蓝牙搜索操作
/// <summary>
/// 搜索蓝牙设备
/// </summary>
public void Searching()
{
if (SearchingState)
{
return;
}
this.BluetoothList.Clear();
try
{
deviceWatcher.Start();
SearchingState = true;
this.ReceivedMessage(MessageType.Info, "蓝牙搜索中...");
}
catch (Exception ex)
{
this.ReceivedMessage(MessageType.Error, "蓝牙搜索异常:"+ex.Message);
return;
}
long time = Environment.TickCount +1000*5;
Task.Factory.StartNew(() =>
{
while (SearchingState)
{
if (Environment.TickCount > time)
{
if (SearchingState)
{
StopSearching();
}
}
else
{
Thread.Sleep(50);
}
}
});
}
/// <summary>
/// 停止搜索
/// </summary>
public void StopSearching(bool isPassive=false)
{
SearchingState = false;
this.ReceivedMessage(MessageType.Info, isPassive? "停止蓝牙搜索..." : "主动停止蓝牙搜索...");
deviceWatcher.Stop();
}
5、连接指定蓝牙 指定读写特征
/// <summary>
/// 连接蓝牙
/// </summary>
/// <param name="bluetoothAddress"></param>
public async Task ConnectAsync(string mac)
{
if (SearchingState)
{
StopSearching(true);//搜索中停止搜索...
}
if (IsConnect && mac == CurrentDeviceMAC)
{
this.ReceivedMessage(MessageType.Warning, $"已连接蓝牙:{CurrentDeviceMAC},无需重连!");
return;
}
if (IsConnect)
{
this.ReceivedMessage(MessageType.Info, $"连接新的蓝牙:{mac},主动断开已连接蓝牙:{CurrentDeviceMAC}");
CloseConnect();//断开当前的蓝牙连接
Thread.Sleep(500);
}
BluetoothAdapter bluetoothAdapter = await BluetoothAdapter.GetDefaultAsync();
if (bluetoothAdapter == null)
{
this.ReceivedMessage(MessageType.Error, "当前机器没有蓝牙模块");
return;//没有蓝牙设备
}
//var itemList = BluetoothList.Where(x => x.BluetoothMac == mac).ToList();
//if (itemList.Count < 1)
//{
// this.ReceivedMessage(MessageType.Warning, "蓝牙列表中不存在当前蓝牙-请执行搜索蓝牙");
// return;//
//}
//CurrentDevice = await BluetoothLEDevice.FromIdAsync(itemList[0].BluetoothDeviceId);
// 修改:不用搜索也可以连接
byte[] _Bytes1 = BitConverter.GetBytes(bluetoothAdapter.BluetoothAddress);//ulong转换为byte数组
Array.Reverse(_Bytes1);
string macAddress = BitConverter.ToString(_Bytes1, 2, 6).Replace('-', ':').ToLower();
string Id = "BluetoothLE#BluetoothLE" + macAddress + "-" + mac;
CurrentDevice = await BluetoothLEDevice.FromIdAsync(Id);
if (CurrentDevice != null)
{
CurrentDeviceMAC = mac;
CurrentDevice.ConnectionStatusChanged += CurrentDevice_ConnectionStatusChanged;//蓝牙状态
}
else
{
this.ReceivedMessage(MessageType.Warning, "通过MAC未查询到蓝牙");
return;//查询不到蓝牙
}
CurrentDevice.GetGattServicesAsync().Completed = async (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
var services = asyncInfo.GetResults().Services;
foreach (GattDeviceService ser in services)
{
string uid = ser.Uuid.ToString();
if (ser.Uuid.ToString().StartsWith("6e400001"))
{
CurrentService = ser;
FindCharacteristic();
}
else
{
// ser.Dispose();
}
}
if (CurrentService == null)
{
this.ReceivedMessage(MessageType.Error, "未获取蓝牙服务-链接失败");
return;
}
}
};
}
/// <summary>
/// 查找读写特征
/// </summary>
public void FindCharacteristic()
{
CurrentService.GetCharacteristicsAsync().Completed = async (asyncInfo, asyncStatus) =>
{
if (asyncStatus == AsyncStatus.Completed)
{
var characteristics = asyncInfo.GetResults().Characteristics;
foreach (GattCharacteristic characteristic in characteristics)
{
string uid = characteristic.Uuid.ToString();
System.Console.WriteLine(uid);
if (characteristic.Uuid.ToString().StartsWith("6e400003"))
{
CurrentNotifyCharacteristic = characteristic;//读取
CurrentNotifyCharacteristic.ProtectionLevel = GattProtectionLevel.Plain;
CurrentNotifyCharacteristic.ValueChanged += CurrentNotifyCharacteristic_ValueChanged;
try
{
await CurrentNotifyCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
}
catch (Exception ex)
{
this.ReceivedMessage(MessageType.Error, "设置蓝牙读取特征Notify异常:" + ex.Message);
return;
}
}
else if (characteristic.Uuid.ToString().StartsWith("6e400002"))
{
CurrentWriteCharacteristic = characteristic;//写入
}
}
if (CurrentNotifyCharacteristic == null || CurrentWriteCharacteristic == null)
{
this.ReceivedMessage(MessageType.Warning, "未查询到读或写特征码-断开蓝牙");
this.CloseConnect();
}
}
};
}
/// <summary>
/// 蓝牙状态改变触发事件
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void CurrentDevice_ConnectionStatusChanged(BluetoothLEDevice sender, object args)
{
if (sender.ConnectionStatus == BluetoothConnectionStatus.Disconnected)
{
this.IsConnect = false;
if (CurrentDevice != null)
{
CurrentDevice.ConnectionStatusChanged -= CurrentDevice_ConnectionStatusChanged;
this.CloseConnect();
CurrentDevice = null;
}
this.DeviceConnect(2, $"蓝牙:{CurrentDeviceMAC}已断开");
CurrentDeviceMAC = null;
}
else
{
this.IsConnect = true;
this.DeviceConnect(1, $"蓝牙:{CurrentDeviceMAC}已连接");
//保存蓝牙配置
foreach (BluetoothInfo item in BluetoothList)
{
if (item.BluetoothMac == CurrentDeviceMAC)
{
Globals.systemConfig.bluetooth = new BluetoothInfo()
{
BluetoothMac =item.BluetoothMac,
BluetoothDeviceId=item.BluetoothDeviceId,
BluetoothName=item.BluetoothName
};
Globals.SaveConfig();
break;
}
}
}
}
/// <summary>
/// 读特征接收蓝牙数据事件
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void CurrentNotifyCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
byte[] data;
CryptographicBuffer.CopyToByteArray(args.CharacteristicValue, out data);
string str = BitConverter.ToString(data);
OnRev?.Invoke(this, new BleEventArgs(data));
}
5、关闭蓝牙连接
/// <summary>
/// 关闭蓝牙连接
/// </summary>
public void CloseConnect()
{
//ReceivedMessage(MsgType.WarningMsg, $"正在断开蓝牙:{CurrentDeviceMAC}...");
CurrentService?.Dispose();
CurrentDevice?.Dispose();
if (CurrentNotifyCharacteristic != null)
{
CurrentNotifyCharacteristic.ValueChanged -= CurrentNotifyCharacteristic_ValueChanged;
}
CurrentService = null;
CurrentWriteCharacteristic = null;
CurrentNotifyCharacteristic = null;
//if (CurrentDevice != null)
//{
// CurrentDevice.ConnectionStatusChanged -= CurrentDevice_ConnectionStatusChanged;
//}
// CurrentDevice = null;
}
6、通过写特征向蓝牙发送数据
/// <summary>
/// 发送数据接口
/// </summary>
/// <param name="characteristic"></param>
/// <param name="data"></param>
/// <returns></returns>
public async Task<bool> Write(byte[] data)
{
if (CurrentWriteCharacteristic == null) { return false; }
int count = 50;
int len = count;
try
{
for (int i = 0; i < data.Length; i += count)
{
if (i + count > data.Length)
{
len = data.Length - i;
}
byte[] b1 = new byte[len];
Array.Copy(data, i, b1, 0, len);
GattCommunicationStatus status = await CurrentWriteCharacteristic.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(b1), GattWriteOption.WriteWithoutResponse);
if (status != GattCommunicationStatus.Success) { return false; }
else
{
Thread.Sleep(1);
}
}
return true;
}
catch (Exception ex)
{
this.ReceivedMessage(MessageType.Error,$"发送异常:{ex.Message}");
return false;
}
}