none
Why does gattCharacteristic ValueChanged event never fire in winform and console applications??? RRS feed

  • Question

  • Hi all,

    I am using the windows 10 SDK 16299.91 (for the Fall Creator Edition Updates), the console app (NOT UWP) works fine with my BLE sensors except for the notification.

    the system information is as follows

      Edition: Windows 10 Pro,

      Version: 1709,

      OS Build: 16299.194

    Here are what I have done:

    1. enable notification by setting up the property

    var value_result = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
    if (value_result == GattCommunicationStatus.Success)
    {
       AddValueChangedHandler();
    }

    , it returned GattCommunicationStatus.Success which indicates the notification was enabled successfully

    2. subscribe the characteristic with the ValueChanged event

            private void AddValueChangedHandler()
            {
                    registeredCharacteristic = selectedCharacteristic;
                    registeredCharacteristic.ValueChanged += OnCharacteristicValueChanged;
            }

    and in the ValueChanged event, display the received data

            private async void OnCharacteristicValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
            {
                Console.Write($"{args.Timestamp}:\t 0x {HexString(args.CharacteristicValue.ToArray()," ")}\r\n");
            }

    the LED on my sensor indicates that the sensor is streaming data (notification), but the ValueChanged event never fires....

    what did I miss in my code? and again, my application is NOT UWP . Many thanks!!

    the whole class is as follows

    public class MyBLEClass
        {
            public bool STATE_MOVE_ON = false;
            public BluetoothLEAdvertisementWatcher BleWatcher = null;
            public Dictionary<ulong, BluetoothLEDevice> BluetoothLEDeviceCollection; // all connected BLE devices
            public Dictionary<ulong, Dictionary<Guid,Dictionary<Guid, GattCharacteristic>>> BluetoothLEServiceCharacteristicCollection; // all connected BLE devices
            public BluetoothLEDevice last_connected_ble_device, current_operation_ble_device;
            public Dictionary<ulong, BluetoothLEAdvertisementReceivedEventArgs> BluetoothLEAdvertisingCollection
            {
                get;
                private set;
            }
            public ObservableCollection<DeviceInformation> DeviceInformationCollection
            {
                get;
                private set;
            }
            public string sensor_to_connect = "";
            GattCharacteristic selectedCharacteristic, registeredCharacteristic;
    
    
            //----------------Constructor--------------------------//
            public MyBLEClass()
            {
                BluetoothLEDeviceCollection = new Dictionary<ulong, BluetoothLEDevice>();
            }
    
            //----------------Advertisement Watcher-----------------//
            public void InitialiseAdvertisementWatcher()
            {
                BluetoothLEAdvertisingCollection = new Dictionary<ulong, BluetoothLEAdvertisementReceivedEventArgs>();
                BluetoothLEServiceCharacteristicCollection = new Dictionary<ulong, Dictionary<Guid, Dictionary<Guid, GattCharacteristic>>>();
                BleWatcher = new BluetoothLEAdvertisementWatcher
                {
                    ScanningMode = BluetoothLEScanningMode.Active
                };
                BleWatcher.Received += OnAdvertisementReceived;
            }
    
            async public void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher w, BluetoothLEAdvertisementReceivedEventArgs btAdv)
            {
                if (btAdv.Advertisement.LocalName.Trim() != "")
                {
                    ulong address = btAdv.BluetoothAddress;
                    if (BluetoothLEAdvertisingCollection.Keys.Contains(address))
                    {
                        BluetoothLEAdvertisingCollection[address] = btAdv;
                    }
                    else
                    {
                        BluetoothLEAdvertisingCollection.Add(address, btAdv);
                    }
                    Console.Write($"{btAdv.Advertisement.LocalName}({HexAddress(btAdv.BluetoothAddress)})    |{btAdv.RawSignalStrengthInDBm} dBm | {btAdv.Advertisement.ServiceUuids.Count.ToString()} Services\r\n");
    
                    if (btAdv.Advertisement.LocalName == sensor_to_connect)
                    {
                        StopAdvertisementWatcher();
                        STATE_MOVE_ON = true;
                    }
                }
            }
    
            public void StartAdvertisementWatcher()
            {
                BleWatcher.Start();
            }
    
            public void StopAdvertisementWatcher()
            {
                BleWatcher.Stop();
            }
    
            async public Task ConnectDeviceByAddress(ulong address,int retry_time)
            {
                if (retry_time > 0)
                {
                    BleWatcher.Stop();
                    last_connected_ble_device = await BluetoothLEDevice.FromBluetoothAddressAsync(address);
                    if (last_connected_ble_device == null)
                    {
                        --retry_time;
                        Thread.Sleep(1000);
                        await ConnectDeviceByAddress(address, retry_time);
                    }
                    else
                    {
                        last_connected_ble_device.ConnectionStatusChanged += OnConnectionStatusChanged;
                        current_operation_ble_device = last_connected_ble_device;
                        if (BluetoothLEDeviceCollection.ContainsKey(current_operation_ble_device.BluetoothAddress))
                        {
                            BluetoothLEDeviceCollection[current_operation_ble_device.BluetoothAddress] = current_operation_ble_device;
                        }
                        else
                        {
                            BluetoothLEDeviceCollection.Add(current_operation_ble_device.BluetoothAddress, current_operation_ble_device);
                        }
                    }
                }
            }
    
            //----------------- Common Used Functions --------------//
            public string HexAddress(ulong address)
            {
                string strHex = "";
                byte[] byte_address = BitConverter.GetBytes(address);
                foreach (byte b in byte_address)
                {
                    strHex += (b.ToString("X2") + ":");
                }
                if (strHex.Length > 0)
                {
                    strHex = strHex.Substring(0, strHex.Length - 1);
                }
                return strHex;
            }
    
            public string HexString(byte[] value, string split)
            {
                string strHex = "";
                foreach (byte b in value)
                {
                    strHex += b.ToString("X2") + split;
                }
                if (strHex.Length > 0)
                {
                    strHex = strHex.Substring(0, strHex.Length - 1);
                }
                return strHex;
            }
    
            async public Task GetServicesCharacteristicsList(ulong address)
            {
                if (BluetoothLEDeviceCollection.ContainsKey(address))
                {
                    current_operation_ble_device = BluetoothLEDeviceCollection[address];
                    if (current_operation_ble_device != null)
                    {
                        Dictionary<Guid, Dictionary<Guid, GattCharacteristic>> dic_sub = new Dictionary<Guid, Dictionary<Guid, GattCharacteristic>>();
                        GattDeviceServicesResult result = await current_operation_ble_device.GetGattServicesAsync();
                        if (result.Status == GattCommunicationStatus.Success)
                        {
                            var services = result.Services;
                            foreach (GattDeviceService service in services)
                            {
                                Guid uuid = service.Uuid;
                                Console.Write($"service: {uuid.ToString()}\r\n");
                                var char_result = await service.GetCharacteristicsAsync();
                                if (char_result.Status == GattCommunicationStatus.Success)
                                {
                                    Dictionary<Guid, GattCharacteristic> dic_char = new Dictionary<Guid, GattCharacteristic>();
                                    var characteristics = char_result.Characteristics;
                                    foreach (GattCharacteristic characteristic in characteristics)
                                    {
                                        dic_char.Add(characteristic.Uuid, characteristic);
                                        string property = characteristic.CharacteristicProperties.ToString();
                                        Console.Write($"\t|- {characteristic.Uuid.ToString()} | {property}\r\n");
                                    }
                                    dic_sub.Add(service.Uuid, dic_char);
                                }
                            }
                        }
                        BluetoothLEServiceCharacteristicCollection.Add(address, dic_sub);
                    }
                }
                else
                {
                    Console.Write("Device is not connected\r\n");
                }
            }
    
            async public Task<byte[]> ReadValueByUUID(ulong address, Guid uuid)
            {
                if (BluetoothLEDeviceCollection.ContainsKey(address))
                {
                    current_operation_ble_device = BluetoothLEDeviceCollection[address];
                    if (current_operation_ble_device != null)
                    {
                        //GattDeviceServicesResult result = await current_operation_ble_device.GetGattServicesAsync();
                        //if (result.Status == GattCommunicationStatus.Success)
                        //{
                        //    var services = result.Services;
                        //    //Task<byte[]> ReadValueTask = ReadValue(services, uuid);
                        //    foreach (GattDeviceService service in services)
                        //    {
                        //        var characteristic_result = await service.GetCharacteristicsForUuidAsync(uuid);
                        //        if (characteristic_result.Status == GattCommunicationStatus.Success && characteristic_result.Characteristics.Count > 0)
                        //        {
                        //            var value_result = await characteristic_result.Characteristics[0].ReadValueAsync();
                        //            if (value_result.Status == GattCommunicationStatus.Success)
                        //            {
                        //                var value = value_result.Value;
                        //                byte[] byte_array = value.ToArray();
                        //                Console.Write(HexString(byte_array, " "));
                        //                return byte_array;
                        //            }
                        //        }
                        //    }
                        //}
                    }
                }
                return null;
            }
    
            async public Task<byte[]> ReadValue(IReadOnlyList<GattDeviceService> services, Guid uuid)
            {
                foreach (GattDeviceService service in services)
                {
                    //var characteristic_result = await service.GetCharacteristicsForUuidAsync(uuid);
                    //if (characteristic_result.Status == GattCommunicationStatus.Success && characteristic_result.Characteristics.Count > 0)
                    //{
                    //    var value_result = await characteristic_result.Characteristics[0].ReadValueAsync();
                    //    if (value_result.Status == GattCommunicationStatus.Success)
                    //    {
                    //        var value = value_result.Value;
                    //        byte[] byte_array = value.ToArray();
                    //        Console.Write(HexString(byte_array, " "));
                    //        return byte_array;
                    //    }
                    //}
                }
                return null;
            }
    
            async public Task<bool> WriteValueByUUID(ulong address, Guid service_uuid, Guid characteristic_uuid, byte[] value)
            {
                if (BluetoothLEServiceCharacteristicCollection.ContainsKey(address))
                {
                    current_operation_ble_device = BluetoothLEDeviceCollection[address];
                    if (current_operation_ble_device != null)
                    {
                        GattCharacteristic gattCharacteristic = BluetoothLEServiceCharacteristicCollection[address][service_uuid][characteristic_uuid];
                        var value_result = await gattCharacteristic.WriteValueWithResultAsync(value.AsBuffer());
                        if (value_result.Status == GattCommunicationStatus.Success)
                        {
                            Console.Write("write finished\r\n");
                            return true;
                        }
                    }
                }
                return false;
            }
    
            private void AddValueChangedHandler()
            {
                    registeredCharacteristic = selectedCharacteristic;
                    registeredCharacteristic.ValueChanged += OnCharacteristicValueChanged;
            }
    
            async public Task EnableNotification(ulong address, Guid service_uuid, Guid characteristic_uuid)
            {
                if (BluetoothLEDeviceCollection.ContainsKey(address))
                {
                    current_operation_ble_device = BluetoothLEDeviceCollection[address];
                    if (current_operation_ble_device != null)
                    {
                        selectedCharacteristic = BluetoothLEServiceCharacteristicCollection[address][service_uuid][characteristic_uuid];
                        if (selectedCharacteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
                        {
                            try
                            {
                                var value_result = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
                                
                                if (value_result == GattCommunicationStatus.Success)
                                {
                                    AddValueChangedHandler();
                                }
                            }
                            catch(Exception ex)
                            {
    
                            }
                        }
    
                        //GattDeviceServicesResult result = await current_operation_ble_device.GetGattServicesAsync();
                        //if (result.Status == GattCommunicationStatus.Success)
                        //{
                        //    var services = result.Services;
                        //    foreach (GattDeviceService service in services)
                        //    {
                        //        var characteristic_result = await service.GetCharacteristicsForUuidAsync(uuid);
                        //        if (characteristic_result.Status == GattCommunicationStatus.Success && characteristic_result.Characteristics.Count > 0)
                        //        {
                        //            GattCharacteristic gattCharacteristic = characteristic_result.Characteristics[0];
                                    
                        //            //gattCharacteristic.ValueChanged += (sender, args) =>
                        //            //{
                        //            //    Console.Write($"{args.Timestamp}:\t 0x {HexString(args.CharacteristicValue.ToArray(), " ")}\r\n");
                        //            //};
                        //        }
                        //    }
                        //}
                    }
                }
                
            }
    
            async public Task DisableNotification(ulong address, Guid uuid)
            {
                if (BluetoothLEDeviceCollection.ContainsKey(address))
                {
                    current_operation_ble_device = BluetoothLEDeviceCollection[address];
                    if (current_operation_ble_device != null)
                    {
                        //GattDeviceServicesResult result = await current_operation_ble_device.GetGattServicesAsync();
                        //if (result.Status == GattCommunicationStatus.Success)
                        //{
                        //    var services = result.Services;
                        //    foreach (GattDeviceService service in services)
                        //    {
                        //        var characteristic_result = await service.GetCharacteristicsForUuidAsync(uuid);
                        //        if (characteristic_result.Status == GattCommunicationStatus.Success && characteristic_result.Characteristics.Count > 0)
                        //        {
                        //            GattCharacteristic gattCharacteristic = characteristic_result.Characteristics[0];
                        //            gattCharacteristic.ValueChanged -= dataCharacteristic_ValueChanged;
                        //            var value_result = await gattCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.None);
                        //        }
                        //    }
                        //}
                    }
                }
            }
    
            //--------------------- Custom Event -----------------//
            private async void OnCharacteristicValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
            {
                Console.Write($"{args.Timestamp}:\t 0x {HexString(args.CharacteristicValue.ToArray()," ")}\r\n");
            }
    
            private void OnConnectionStatusChanged(BluetoothLEDevice sender, Object status)
            {
                if (sender.ConnectionStatus == BluetoothConnectionStatus.Connected)
                {
                    Console.Write($"{sender.Name}({HexAddress(sender.BluetoothAddress)}) is connected \r\n");
                }
                else
                {
                    Console.Write($"{sender.Name}({HexAddress(sender.BluetoothAddress)}) is disconnected \r\n");
                }
            }
        }


    • Edited by JIERAN-ZHI Sunday, February 11, 2018 9:37 PM
    Friday, February 9, 2018 1:16 AM

Answers

  • Hi Charles, 

    Thanks for your reply and I appreciate your work attitude. Indeed, it needs lots of experiments to get the API working on a console and winform. It turns out to be an issue in our firmware, which was ignored till recently when we decided to use the internal Bluetooth module on the surface instead of the dongle.

    Well, we did not come across with the problem you have,  we use the FromBluetoothAddressAsync in following way

    last_connected_ble_device = await BluetoothLEDevice.FromBluetoothAddressAsync(address);

    and it works well, just wonder if you turned on your Bluetooth on your pc/surface?

    Anyway, it is working now and again thanks for your reply.

    Cheers


    Tuesday, February 13, 2018 11:31 PM

All replies

  • Hello JIERAN-ZHI,

    Some UWP Apis aren't fully available for all packaged apps, some feature areas are not yet fully tested or currently functioning as intended. 

    The detailed info about available UWP APIs.

    https://docs.microsoft.com/en-us/windows/uwp/porting/desktop-to-uwp-supported-api#new

    Best regards,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, February 12, 2018 9:05 AM
    Moderator
  • can you just be straight and say if the BLE notification is working or not for winform applications in an official term.
    Monday, February 12, 2018 10:18 PM
  • Hi Jieran,

    Have you succeeded connecting your sensor by BluetoothLEDevice.FromBluetoothAddressAsync(address)? I also tested this but I got null when I called it.

    What's more, you just use Advertisement to find devices, have you tried to use GATT client to discover your sensor?

    Best Regards,

    Charles He


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.



    Tuesday, February 13, 2018 2:08 PM
  • Hi Charles, 

    Thanks for your reply and I appreciate your work attitude. Indeed, it needs lots of experiments to get the API working on a console and winform. It turns out to be an issue in our firmware, which was ignored till recently when we decided to use the internal Bluetooth module on the surface instead of the dongle.

    Well, we did not come across with the problem you have,  we use the FromBluetoothAddressAsync in following way

    last_connected_ble_device = await BluetoothLEDevice.FromBluetoothAddressAsync(address);

    and it works well, just wonder if you turned on your Bluetooth on your pc/surface?

    Anyway, it is working now and again thanks for your reply.

    Cheers


    Tuesday, February 13, 2018 11:31 PM
  • Hi Jieran,

    I read this document whose last paragraph says that GATT and Beacons(Advertisement) are different, so I was not sure whether we can connect to device in your way. And I also tested your code with two laptops but get null. This may be caused by bluetooth module difference in laptop and your sensor.

    Anyway, thanks for your sharing and glad to know you have your problem solved. I suggest that you mark your last reply as answer, this will benefit community members who have same or similar problems. Thanks a lot!

    Best Regards,

    Charles He


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.



    Thursday, February 15, 2018 1:26 AM