WinForm低功耗蓝牙通信BlueToothLE C#

工作中用到低功耗蓝牙,在网上找了一圈自己总结了一下

最终效果
image

开发环境:Visual Studio2019 Win10

image
image

参考文章
https://www.cnblogs.com/webtojs/p/9675956.html
https://blog.csdn.net/weixin_32673065/article/details/113578844?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0.pc_relevant_aa&spm=1001.2101.3001.4242.1&utm_relevant_index=3

自己实现的库

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.Security.Cryptography;

public class LanBle
{
    string Mac { get; set; }
    string ServiceID { get; set; }
    string WriteID { get; set; }
    string ReadID { get; set; }
    public BluetoothLEDevice Device { get; set; }
    //存储检测到的主服务。
    public GattDeviceService Service { get; set; }
    //存储检测到的写特征对象。
    public GattCharacteristic WriteCharacteristic { get; set; }
    //存储检测到的通知特征对象。
    public GattCharacteristic NotifyCharacteristic { get; set; }
    public event BleRev OnRev;
    public event BleScanResult OnScanResult;
    List<ScanResult> ScanResults = new List<ScanResult>();
    bool flag = false;
    public LanBle()
    {

    }
    public bool DisConnect()
    {
        NotifyCharacteristic = null;
        WriteCharacteristic = null;
        Service?.Dispose();
        Service = null;
        Device?.Dispose();
        Device = null;
        return true;
    }
    public void Stop()
    {
        flag = false;
    }
    private bool Find(string id)
    {
        var x = from a in ScanResults where a.ID == id select a;
        if (x == null) { return false; }
        return x.Count() == 1;
    }
    public void Scan(int timeOut = 10)
    {
        string[] requestedProperties = { "System.Devices.Aep.IsConnected","System.Devices.Aep.DeviceAddress", "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}\")";


        DeviceWatcher deviceWatcher =
                DeviceInformation.CreateWatcher(
                    aqsAllBluetoothLEDevices,
                    requestedProperties,
                    DeviceInformationKind.AssociationEndpoint);

        deviceWatcher.Added += DeviceWatcher_Added;
        deviceWatcher.Updated += DeviceWatcher_Updated;
        deviceWatcher.Stopped += DeviceWatcher_Stopped;
        flag = true;
        long l1 = Environment.TickCount + 1 * timeOut * 1000;
        Task.Factory.StartNew(() =>
        {
            while (flag)
            {
                if (Environment.TickCount > l1)
                {
                    deviceWatcher.Stop();
                    return;
                }
                else
                {
                    Thread.Sleep(50);
                }

            }

        });
        ScanResults.Clear();
        deviceWatcher.Start();
    }
    private void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
    {
        if (string.IsNullOrEmpty(args.Name)) { return; }

        var rssi = args.Properties.Single(d => d.Key == "System.Devices.Aep.SignalStrength").Value;
        if (rssi == null) { return; }
        int x1 = int.Parse(rssi.ToString());

        if (x1 < -80) { return; }

        string s1 = $"[{x1}] { (args.Name).PadLeft(30, ' ')} {args.Id}";

        Console.WriteLine(s1);
        if (!Find(args.Id))
        {
            var x = args.Properties;

            ScanResults.Add(new ScanResult(args.Name, args.Id));
        }
    }

    private void DeviceWatcher_Stopped(DeviceWatcher sender, object args)
    {
        OnScanResult?.Invoke(sender, new BleScanResultEventArgs(ScanResults));
    }

    private void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate args)
    {

    }
    public async Task<int> Connect(string mac, string serviceId, string writeId, string readId)
    {
        Mac = mac.ToLower();
        ServiceID = serviceId.ToLower();
        WriteID = writeId.ToLower();
        ReadID = readId.ToLower();
        try
        {
            BluetoothAdapter bluetoothAdapter = await BluetoothAdapter.GetDefaultAsync();
            if (bluetoothAdapter == null) { return -1; }

            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;
            Device = await BluetoothLEDevice.FromIdAsync(Id);
            if (Device == null) { return -2; }

            GattDeviceServicesResult result = await Device.GetGattServicesForUuidAsync(new Guid(ServiceID));
            IEnumerable<GattDeviceService> lists = result.Services;
            if (lists == null || lists.Count() == 0) { return -3; }

            Service = result.Services[0];
            GattCharacteristicsResult w1 = await Service.GetCharacteristicsForUuidAsync(new Guid(WriteID));
            IEnumerable<GattCharacteristic> list2 = w1.Characteristics;
            if (list2 == null || list2.Count() == 0) { return -4; }

            WriteCharacteristic = w1.Characteristics[0];
            GattCharacteristicsResult r1 = await Service.GetCharacteristicsForUuidAsync(new Guid(ReadID));
            IEnumerable<GattCharacteristic> list3 = r1.Characteristics;
            if (list3 == null || list3.Count() == 0) { return -5; }

            NotifyCharacteristic = r1.Characteristics[0];
            NotifyCharacteristic.ProtectionLevel = GattProtectionLevel.Plain;
            NotifyCharacteristic.ValueChanged += Characteristic_ValueChanged;
            await NotifyCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
            return 0;
        }
        catch
        {
            return -6;
        }
    }

    /// <summary>
    /// 发送数据接口
    /// </summary>
    /// <param name="characteristic"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    public async Task<bool> Write(byte[] data)
    {
        if (WriteCharacteristic == null) { return false; }


        int count = 20;
        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);
                Console.WriteLine($"发送 : " + ByteToHex(b1));
                GattCommunicationStatus status = await WriteCharacteristic.WriteValueAsync(CryptographicBuffer.CreateFromByteArray(b1), GattWriteOption.WriteWithoutResponse);
                if (status != GattCommunicationStatus.Success) { return false; }
                else
                {
                    Thread.Sleep(5);
                }
            }
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message.ToString());
            return false;
        }

    }

    private void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
    {
        byte[] data;
        CryptographicBuffer.CopyToByteArray(args.CharacteristicValue, out data);
        string str = BitConverter.ToString(data);
        OnRev?.Invoke(this, new BleEventArgs(data));
    }
    private string ByteToHex(byte[] b, bool space = true)
    {
        if (b == null) { return ""; }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < b.Length; i++)
        {
            sb.Append(b[i].ToString("X2") + (space ? " " : ""));
        }
        return sb.ToString();
    }
}
public delegate void BleRev(object sender, BleEventArgs e);
public delegate void BleScanResult(object sender, BleScanResultEventArgs e);
public class BleScanResultEventArgs : EventArgs
{
    public List<ScanResult> ScanResults;
    public BleScanResultEventArgs(List<ScanResult> scanResults)
    {
        this.ScanResults = scanResults;
    }
}
public class ScanResult
{
    public string Name { get; set; }
    public string Mac { get; set; }
    public string ID { get; set; }
    public ScanResult(string name, string id)
    {
        this.Name = name;

        if (string.IsNullOrEmpty(Name))
        {
            Name = "未知";
        }
        this.ID = id;

        string[] s1 = id.Split('-');
        if (s1.Length == 2)
        {
            this.Mac = s1[1];
        }
        else
        {
            this.Mac = "";
        }
    }
    public override string ToString()
    {
        //return $"{Name}\t{Mac}\t{ID}";
        return $"{Name}\t{Mac}";
    }
}
public class BleEventArgs : EventArgs
{
    public byte[] Data { get; set; }
    public BleEventArgs(byte[] data)
    {
        this.Data = data;
    }

}

调用方式

扫描:

lb = new LanBle();
lb.OnScanResult += Lb_OnScanResult;
lb.Scan();

private void Lb_OnScanResult(object sender, BleScanResultEventArgs e)
{
foreach (var item in e.ScanResults)
{
AppendText(item.ToString(), false);
}

    }

连接:

LanBle lb = new LanBle();
lb.OnRev += Lb_OnRev;
int iRev = await lb.Connect(mac, _serviceGuid, _writeCharacteristicGuid, _notifyCharacteristicGuid);
bool flag = iRev == 0;

发送数据:

private async Task Write(byte[] bSend)
{
bool flag = false;
string sSend = Fun.ByteToHex(bSend);
if (lb != null && lb.Service != null)
{
lTime = Environment.TickCount;
flag = await lb.Write(bSend);
AppendText($"Send : {sSend}");
Console.WriteLine(flag);
sRev = "";
}
Console.WriteLine($"发送【{(flag ? "成功" : "失败")}】:{sSend }");
return flag;
}

收到数据:
private void Lb_OnRev(object sender, BleEventArgs e)
{
byte[] data = e.Data;
}

posted @ 2022-02-28 15:33  mycls  阅读(5808)  评论(5编辑  收藏  举报