Judson Abraham
Judson Abraham

Reputation: 412

The write operation doesn't update the characteristic value for iOS in xamarin forms

I'm creating a BLE application using xamarin forms. Everything is working fine in Android I'm able to read and write GATT characteristics. In iOS I'm able to read successfully but the write operation doesn't update the characteristics value. There is no error in the write operation as well it is executing but the characteristics value is not changing. I tried iOS native application called light blue there its working fine the characteristic value is updated I'm facing issue only in Xamarin forms app. This is my code

 private async Task<string> ProcessDeviceInformationService(IService deviceInfoService)
        {
            try
            {
               await adapter.ConnectToDeviceAsync(device);
                var sb = new StringBuilder("Getting information from Device Information service: \n");
                 var characteristics =  deviceInfoService.GetCharacteristicsAsync();
                var characteristic = await deviceInfoService.GetCharacteristicAsync(Guid.Parse("00002a2b-0000-1000-8000-00805F9B34FB"));
                
                try
                {
                    
                    if (characteristic != null)
                    {
                        var sbnew = new StringBuilder("BLE Characteristics\n");
                        byte[] senddata = Encoding.UTF8.GetBytes(string.IsNullOrEmpty(SendMessageLabel.Text) ? "12" : SendMessageLabel.Text);

 

                       
                    
                                                    
                                                 
                        
                        characteristic.ValueUpdated += (o, args) =>
                          {
                        
                         var bytes = characteristic.Value;
                                                 };
                                               await characteristic.WriteAsync(senddata);

 

                                                                                                     
                      

 

                        string str = Encoding.UTF8.GetString(senddata);

 

                  

 

                        sbnew.AppendLine($"Characteristics found on this device: {string.Join(", ", str.ToString())}");
                            CharactericsLabel.Text = sbnew.ToString();
                        

 


                    }
                }
                catch (Exception ex)
                {
                    //return ex.Message;
                    DisplayAlert("Notice", ex.Message.ToString(), "OK");

 

                }

I tried delay and I also tried to get write without response from peripheral but it doesn't work. This is my peripheral code

 // Current Time characteristic
BluetoothGattCharacteristic currentTime = new BluetoothGattCharacteristic(CURRENT_TIME,
        //Read-only characteristic, supports notifications
        BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
        BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PROPERTY_WRITE);
BluetoothGattDescriptor configDescriptor = new BluetoothGattDescriptor(CLIENT_CONFIG,
        //Read/write descriptor
        BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE);
currentTime.addDescriptor(configDescriptor);
// Local Time Information characteristic
BluetoothGattCharacteristic localTime = new BluetoothGattCharacteristic(LOCAL_TIME_INFO,
        //Read-only characteristic
        BluetoothGattCharacteristic.PROPERTY_READ,
        BluetoothGattCharacteristic.PERMISSION_READ);
BluetoothGattCharacteristic sampleText = new BluetoothGattCharacteristic sampleText = new BluetoothGattCharacteristic(SAMPLE_TEXT,
        //Read-only characteristic
        BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE | BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
        BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ);

I have no clue how to fix this any suggestions.I tried even Semaphore but it didn't help as you can see in my code

private static async Task<string> WriteAndWaitForResponseAsync(
    ICharacteristic characteristic,
    byte[] senddata)
        {
            var semaphore = new SemaphoreSlim(0, 1);
            string result = null;

            characteristic.ValueUpdated += (o, args) =>
            {
                var bytes = characteristic.Value;

                result = Encoding.UTF8.GetString(bytes);  // Note I don't know if this is your intended behaviour with the values you get back, you can decide what to actually do with the response.
                                                          // Notify a value has been received.
                semaphore.Release();
            };

            await characteristic.WriteAsync(senddata,new CancellationToken(true)).ConfigureAwait(false);

            // Wait until we receive a notification.
            await semaphore.WaitAsync(); // I strongly suggest you look in to CancellationTokens but I am not going in to that now.
           
            return result;
        }

Upvotes: 0

Views: 970

Answers (1)

Bijington
Bijington

Reputation: 3751

I suspect that threading is part of the problem here and that you subscribe for the event, call WriteAsync but then you ultimately leave the method before the data/event has been received. I suggest you need to try blocking the method from leaving before you receive your data.

Try something like:

private static async Task<string> WriteAndWaitForResponseAsync(
    ICharacteristic characteristic,
    byte[] senddata)
{
    var semaphore = new SemaphoreSlim(0, 1);
    string result = null;

    characteristic.ValueUpdated += (o, args) =>
    {
        // Make sure you read from the new value in event not the existing characteristic.
        var bytes = args.Characteristic.Value;

        result = Encoding.UTF8.GetString(bytes);  // Note I don't know if this is your intended behaviour with the values you get back, you can decide what to actually do with the response.
        // Notify a value has been received.
        semaphore.Release();
    };
    
    await characteristic.WriteAsync(senddata);

    // Wait until we receive a notification.
    await semaphore.WaitAsync(); // I strongly suggest you look in to CancellationTokens but I am not going in to that now.

    return result;
}

Then you can call this method from within your current one like:

string str = await WriteAndWaitForResponseAsync(characteristic, senddata);

Upvotes: 1

Related Questions