Работа с BLE

Понадобилась мне программа на windows, которая поддерживает работу с BLE. Конечно же бесплатная. Работа с BLE должна быть следующей:

  • Поиск BLE устройств;
  • Подключение к выбранному устройству;
  • Чтение/запись характеристик устройства;

Написать решил свою программу на языке C# с использованием библиотеки Windows. Сразу оговорюсь, программу писал под свои цели, она не является универсальной. В статье расскажу и покажу, какие методы и свойства использовал для программирование BLE.

Работа с BLE: поиск устройств BLE

Для программирования BLE использую библиотеку Windows. Devices.Bluetooth. Для корректной работы необходимо в using подключить библиотеку следующим образом:

using Windows.Devices.Bluetooth
using Windows.Devices.Bluetooth.Advertisement

Теперь мы можем приступить к написанию кода для поиска BLE устройств. Предварительно установим несколько ограничений для поиска.

private void btnSearchBLE_Click(object sender, EventArgs e)
        {
            listDevice.Items.Clear();
            AdressBLE.Clear();
            _devices.Clear();
// Переменная _watcher объявлена глобальной типа BluetoothLEAdvertisementWather 
            if (_watcher == null)
                _watcher = new BluetoothLEAdvertisementWatcher();     
            _watcher.Stop();
// отсеиваем устройства по качеству сигнала
            _watcher.SignalStrengthFilter.InRangeThresholdInDBm = -110;
            _watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -110;
// Устанавливаем активный режим поиска
            _watcher.ScanningMode = BluetoothLEScanningMode.Active;
// переопределяем свойство Resived (Что происходит когда устройство обнаружено)
            _watcher.Received += Wather_Recived;
            _watcher.Start();
        }

private async void Wather_Recived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
        {
            dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
            if (dev != null)
            {
               if (!_devices.ContainsKey(args.BluetoothAddress))
                {                   
                   _devices.Add(args.BluetoothAddress, dev);
                   listDevice.Invoke(new Action(() =>
                        {
                            String Name = "";
                            String Addrr = dev.BluetoothAddress.ToString();
                            AdressBLE.Add(Addrr);
                            if (dev.Name == null)
                                Name = "None";
                            else
                                Name = dev.Name;
                            int item = listDevice.Items.IndexOf(Addrr + " " + Name);
                            if (item == -1)
                                listDevice.Items.Add(dev.BluetoothAddress + " " + Name);
                        }));
                }
            }           
        }

Собственно. здесь все просто, запускаем поиск устройств BLE в активном режиме и добавляем найденное устройство в Dictionary с ключём в виде мак адреса устройства.

Демонстрация поиска BLE устройств

Подключение, чтение служб и характеристик BLE

После того как мы нашли нужное нам устройство, необходимо подключиться и прочитать какие у него есть службы. А так же какие характеристики содержат эти службы.

private async void btnConnectBLE_Click(object sender, EventArgs e)
        { 
            trView.Nodes.Clear();
            dev =  await BluetoothLEDevice.FromBluetoothAddressAsync(Convert.ToUInt64(AdressBLE.ElementAt(IndexBLENow)));
            if (dev != null)
            {
                var servisesResult = await dev.GetGattServicesAsync();
                if (servisesResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
                {
                    var services = servisesResult.Services;
                    for (int j = 0; j < services.Count;j++)
                    {
                        var service = services[j];
                        trView.Nodes.Add($"Служба - {service.Uuid}");
                        var characteristicsResult = await service.GetCharacteristicsAsync();
                        if (characteristicsResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
                        {
                            var characteristics = characteristicsResult.Characteristics;
                            var characteristic = characteristics[0];
                            for (int i = 0; i < characteristics.Count; i++)
                            {
                                 characteristic = characteristics[i];
                                 trView.Nodes[trView.Nodes.Count - 1].Nodes.Add($"Характеристика - {characteristic.Uuid}");                              
                            }
                            characteristic.Service.Dispose();
                        }
                        service.Session.Dispose();
                    }                 
                }
            }else MessageBox.Show("Не могу подключить устройство!"); 
        }

Демонстрация кода на рисунке ниже.

Чтение служб и характеристик BLE устройства

Из работы программы мы видим, что наше устройство имеет 3 службы. Меня интересовала третья служба с 4 характеристиками. Последняя характеристика была сделана на чтение и запись, остальные только на чтение.

Чтение-запись характеристики

На по следок рассмотрим как читать и записывать характеристики в устройстве BLE.

private async void btnSendtxt_Click(object sender, EventArgs e)
        {
            if (value != "")
            {
                String guu = value;
                if (guu.Contains("Характеристика"))
                {

                    guu = guu.Replace("Характеристика - ", "");
                    String GuuiServis = "000000ff-0000-1000-8000-00805f9b34fb";
                    if (dev != null)
                        dev.Dispose();


                    dev = await BluetoothLEDevice.FromBluetoothAddressAsync(Convert.ToUInt64(AdressBLE.ElementAt(IndexBLENow)));
                    if (dev != null)
                    {
                        var servisesResult = await dev.GetGattServicesForUuidAsync(Guid.Parse(GuuiServis));
                        if (servisesResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
                        {
                            var services = servisesResult.Services;
                            var service = services[0];
                            try
                            {
                                var characteristicsResult = await service.GetCharacteristicsForUuidAsync(Guid.Parse(guu));
                                if (characteristicsResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
                                {
                                    var characteristics = characteristicsResult.Characteristics;
                                    for (int i = 0; i < characteristics.Count; i++)
                                    {
                                        var characteristic = characteristics[i];
                                        if (characteristic.Uuid == Guid.Parse(guu))
                                        {
                                            var property = characteristic.CharacteristicProperties;
                                            String Data = tbSendTxt.Text;
                                            byte[] input = new byte[Data.Length];
                                            input = Encoding.Default.GetBytes(Data);
                                            var writer = new DataWriter();
                                            writer.WriteBytes(input);
                                            var result = await characteristic.WriteValueAsync(writer.DetachBuffer());
                                        }
                                    }
                                }
                                service.Dispose();
                            }
                            catch
                            {
                            }
                        }
                    }
                }
            }
        }

Вышеприведенный код демонстрирует запись в характеристику. Что бы записать значение в характеристику у нее должно быть свойство записи. Иначе ничего не произойдет.

private async void trView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            value = e.Node.Text;           
            if (value != null)
            {
                String guu = value;
                if (guu.Contains("Характеристика"))
                {
                    String rootNode = e.Node.Parent.Text;
                    guu = guu.Replace("Характеристика - ", "");
                    GuuiServis = rootNode.Replace("Служба - ", "");//"000000ff-0000-1000-8000-00805f9b34fb";                    
                    if (dev != null)
                    {
                        var servisesResult = await dev.GetGattServicesForUuidAsync(Guid.Parse(GuuiServis));
                        if (servisesResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
                        {
                            var services = servisesResult.Services;
                            var service = services[0];
                            try
                            {
                                var characteristicsResult = await service.GetCharacteristicsAsync();
                                if (characteristicsResult.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
                                {
                                    var characteristics = characteristicsResult.Characteristics;
                                    for (int i = 0; i < characteristics.Count; i++)
                                    {
                                        var characteristic = characteristics[i];
                                        if (characteristic.Uuid == Guid.Parse(guu))
                                        {
                                            var result = await characteristic.ReadValueAsync(BluetoothCacheMode.Uncached);
                                            if (result.Status == Windows.Devices.Bluetooth.GenericAttributeProfile.GattCommunicationStatus.Success)
                                            {
                                                var val = DataReader.FromBuffer(result.Value);
                                                byte[] input = new byte[val.UnconsumedBufferLength];
                                                val.ReadBytes(input);
                                                label1.Text = "Значение характеристики: " + System.Text.Encoding.ASCII.GetString(input);
                                            }
                                            characteristic.Service.Dispose();
                                        }                                       
                                    }
                                }
                                service.Session.Dispose();
                                characteristicsResult = null;
                                servisesResult = null;
                            }
                            catch
                            {
                            }                           
                        }
                    }
                }
            }
        }

Представленный выше код реализует следующую логику:

Нажав на характеристику мы получаем ее ID и подключаемся к ней. Затем пытаемся считать то что записано в этой этой характеристике.

Работа с BLE: Закрытие соединения с устройством BLE

private void btnDiscon_Click(object sender, EventArgs e)
        {
            if (dev != null)
            {
                dev.Dispose();
                dev = null;
                listDevice.Items.Clear();
                trView.Nodes.Clear();
                AdressBLE.Clear();
                _devices.Clear();
                GC.Collect();
            }
        }

Что бы закрыть соединение BLE необходимо вызвать метод Dispose, а также отдельно запустить сборщик мусора GC.Collect(). Иначе соединение не будет закрыто.

Скачать весь проект можно по ссылке.

Внимание! Проект проверен на windows 10. В других операционных системах работоспособность не гарантируется.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии