简体   繁体   中英

Xamarin.Forms Bluetooth Low Energy Inconsistent

Im building a bluetooth low energy app from: https://github.com/xabre/xamarin-bluetooth-le

The idea is to have an app that will connect to a peripheral device and set some properties. (UserData). If there is some exceptions on the peripheral device i would like some logging via central app also.

So i been successful with connecting to my peripheral and on button click for this device i get notify on my center device(client) if i previously pressed "Start updates" button on client device.

I also been able to write to Firstname characteristic after successfully connected.

The problem is about inconsistent. I disabled Wifi on both devices. Im using Nexus 6P(Peripheral) and OnePlus One(Center). Xamarin.Forms.

Sometimes(often) i get doublets of the services after i connect.

Problem when disconnect(never return from await), often i need to restart devices.

Connection get lost often..

This is my BleServer class:(messy)

public class BleServer 
{
    public class OfflineListener : Java.Lang.Object, IOnClickListener
    {
        private List<string> objects = new List<string>() { "Itaque his sapiens semper", "Sed tamen est aliquid", "Apparet statim", "habes enim a rhetoribus", "Non quam nostram", "Luxuriam non reprehendit" };


        public void OnClick(View v)
        {
            QueueMessages.QueueMessageHandler.Instance.Enqueue(objects.OrderBy(a => Guid.NewGuid()).First());
        }


    }
    public class MyListener : Java.Lang.Object, IOnClickListener
    {
        private BluetoothGattCharacteristic _characteristic;
        private BluetoothGattServer _bluetoothServer;
        private BluetoothDevice _device;

        private List<string> objects = new List<string>() { "Itaque his sapiens semper", "Sed tamen est aliquid", "Apparet statim", "habes enim a rhetoribus", "Non quam nostram", "Luxuriam non reprehendit" };


        public MyListener(BluetoothGattCharacteristic characteristic, BluetoothGattServer bluetoothServer, BluetoothDevice device)
        {
            _characteristic = characteristic;
            _bluetoothServer = bluetoothServer;
            _device = device;
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public void OnClick(View v)
        {
            try
            {
                if (!QueueMessages.QueueMessageHandler.Instance.IsEmpty())
                {
                    while (!QueueMessages.QueueMessageHandler.Instance.IsEmpty())
                    {
                        var message = QueueMessages.QueueMessageHandler.Instance.Dequeue();
                        _characteristic.SetValue(message);
                        _bluetoothServer.NotifyCharacteristicChanged(_device, _characteristic, false);
                    }
                }

                _characteristic.SetValue(objects.OrderBy(a => Guid.NewGuid()).First());
                var ara = _bluetoothServer.NotifyCharacteristicChanged(_device, _characteristic, false);
            }
            catch(Exception ex)
            {
                Console.WriteLine("OnClick: {0}", ex.Message);
            }
        }
    }

    private readonly BluetoothManager _bluetoothManager;
    private BluetoothAdapter _bluetoothAdapter;
    private BleGattServerCallback _bluettothServerCallback;
    private BluetoothGattServer _bluetoothServer;
    private BluetoothGattCharacteristic _characteristic;
    private Button _button;


    private static UUID Notification_Service_UUID = UUID.FromString("00001811-0000-1000-8000-00805f9b34fb");
    private static UUID Notification_NewAlert_UUID = UUID.FromString("00002A46-0000-1000-8000-00805f9b34fb");
    //private static UUID Notification_SupportedNewAlert_UUID = UUID.FromString("00002A47-0000-1000-8000-00805f9b34fb");
    //private static UUID Notification_SupportedUnreadAlertCategory_UUID = UUID.FromString("00002A48-0000-1000-8000-00805f9b34fb");
    //private static UUID Notification_UnreadAlertStatus_UUID = UUID.FromString("00002A45-0000-1000-8000-00805f9b34fb");
    //private static UUID Notification_AlertControlPoint_UUID = UUID.FromString("00002A44-0000-1000-8000-00805f9b34fb");

    private static UUID UserData_Service_UUID = UUID.FromString("0000181c-0000-1000-8000-00805f9b34fb");
    private static UUID UserData_Fname_Level_UUID = UUID.FromString("00002a8a-0000-1000-8000-00805f9b34fb");
    private static UUID UserData_Lname_Level_UUID = UUID.FromString("00002A90-0000-1000-8000-00805f9b34fb");
    private static UUID UserData_Email_Level_UUID = UUID.FromString("00002A87-0000-1000-8000-00805f9b34fb");
    private static UUID UserData_Language_Level_UUID = UUID.FromString("00002AA2-0000-1000-8000-00805f9b34fb");


    public BleServer(Activity activity)
    {
        _button = activity.FindViewById<Button>(Resource.Id.MyButton);


        _button.SetOnClickListener(new OfflineListener());


        _bluetoothManager = (BluetoothManager)activity.ApplicationContext.GetSystemService(Context.BluetoothService);
        _bluetoothAdapter = _bluetoothManager.Adapter;

        _bluettothServerCallback = new BleGattServerCallback();
        _bluetoothServer = _bluetoothManager.OpenGattServer(activity.ApplicationContext, _bluettothServerCallback);

        var service = new BluetoothGattService(Notification_Service_UUID, GattServiceType.Primary);
        _characteristic = new BluetoothGattCharacteristic(Notification_NewAlert_UUID, GattProperty.Notify | GattProperty.Write | GattProperty.Read, GattPermission.Read | GattPermission.Write);

        service.AddCharacteristic(_characteristic);

        _bluetoothServer.AddService(service);




        //test UserData
        var userDataServie = new BluetoothGattService(UserData_Service_UUID, GattServiceType.Primary);
        ///
        var firstName = new BluetoothGattCharacteristic(UserData_Fname_Level_UUID, GattProperty.Read | GattProperty.Write, GattPermission.Read | GattPermission.Write);
        userDataServie.AddCharacteristic(firstName);

        _bluetoothServer.AddService(userDataServie);
        //


        var batteryService = new BluetoothGattService(UUID.FromString("0000180F-0000-1000-8000-00805f9b34fb"), GattServiceType.Primary);
        var batteryLevel = new BluetoothGattCharacteristic(UUID.FromString("00002A19-0000-1000-8000-00805f9b34fb"), GattProperty.Read | GattProperty.Notify, GattPermission.Read);
        batteryService.AddCharacteristic(batteryLevel);
        _bluetoothServer.AddService(batteryService);


        _bluettothServerCallback.CharacteristicReadRequest += _bluettothServerCallback_CharacteristicReadRequest;
        _bluettothServerCallback.CharacteristicWriteRequest += _bluettothServerCallback_CharacteristicWriteRequest;
        _bluettothServerCallback.NotificationSent += _bluettothServerCallback_NotificationSent;
        _bluettothServerCallback.ConnectionStateChange += _bluettothServerCallback_ConnectionStateChange;

        Console.WriteLine("Server created!");

        BluetoothLeAdvertiser myBluetoothLeAdvertiser = _bluetoothAdapter.BluetoothLeAdvertiser;

        var builder = new AdvertiseSettings.Builder();
        builder.SetAdvertiseMode(AdvertiseMode.LowLatency);
        builder.SetConnectable(true);
        builder.SetTimeout(0);
        builder.SetTxPowerLevel(AdvertiseTx.PowerHigh);

        AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
        dataBuilder.SetIncludeDeviceName(true);
        dataBuilder.SetIncludeTxPowerLevel(true);


        myBluetoothLeAdvertiser.StartAdvertising(builder.Build(), dataBuilder.Build(), new BleAdvertiseCallback());
    }


    void _bluettothServerCallback_NotificationSent(object sender, BleEventArgs e)
    {
        Debug.WriteLine("NotificationSent to: " + e.Device);
    }


    void _bluettothServerCallback_CharacteristicReadRequest(object sender, BleEventArgs e)
    {
        _bluetoothServer.SendResponse(e.Device, e.RequestId, GattStatus.Success, e.Offset, e.Characteristic.GetValue());
        return;
    }

    void _bluettothServerCallback_CharacteristicWriteRequest(object sender, BleEventArgs e)
    {
        e.Characteristic.SetValue(e.Value);
        _bluetoothServer.SendResponse(e.Device, e.RequestId, e.GattStatus, e.Offset, e.Characteristic.GetValue());
        return;
    }

    void _bluettothServerCallback_ConnectionStateChange(object sender, BleEventArgs e)
    {
        if(e.ProfileNewState == ProfileState.Connected || e.ProfileNewState == ProfileState.Connecting)
        {
            _button.SetOnClickListener(new MyListener(_characteristic, _bluetoothServer, e.Device));
        }
        else
        {
            _button.SetOnClickListener(new OfflineListener());
        }
    }

}

public class BleAdvertiseCallback : AdvertiseCallback
{
    public override void OnStartFailure(AdvertiseFailure errorCode)
    {
        Console.WriteLine("Adevertise start failure {0}", errorCode);
        base.OnStartFailure(errorCode);
    }

    public override void OnStartSuccess(AdvertiseSettings settingsInEffect)
    {
        Console.WriteLine("Adevertise start success {0}", settingsInEffect.Mode);
        base.OnStartSuccess(settingsInEffect);
    }
}

AndroidManifest on android project(central)

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
          android:versionCode="1" 
          android:versionName="1.0" 
          package="prop.Mobile.Explorer.Droid" 
          android:installLocation="auto">
    <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="23" />
    <application android:label="Microprop" android:icon="@drawable/icon" android:theme="@style/MyTheme"></application>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
</manifest>

I done some reading and BLE is often referred as a pain in the ass.

Summary

Goal

A Xamarin.Form application thats run on different smartphones. This app will connect to different instances of Peripheral. When the person with the central app connect to one Peripheral his firstname(userdata settings) should be written to the peripheral device.

If there is something wrong ie exceptions this should be queued and logged to the central app and then later on to the cloud.

Questions

  • Is this the right way forward?
  • When writing username data, should i use the characteristics named UserData and Firstname? (1)?attributeXmlFile=org.bluetooth.service.user_data.xml
  • For the logging functionality, im going with Alert Notification Service, this is correct? (1)?attributeXmlFile=org.bluetooth.service.alert_notification.xml
  • I've seen beacons in some articles, should i investigate it?
  • Why am i having this problems? (Please give examples of code you wish to see)

(1)bluetooth.com/specifications/gatt/viewer

Concerning the frequent connection losses:

Try to vary the connection parameters, especially the connection supervision timeout. The timeout defines how long a slave may not answer the master until the master interprets this as a loss of connection. If this value is too low, connection losses will occur frequently if the slave needs to much time to answer.

See here for more infos about connection parameters:

https://devzone.nordicsemi.com/question/60/what-is-connection-parameters/

Concerning the doublets of services, this is typically due to one of two causes: Either the registration of services on the peripheral is faulty, or the discovery method has a problem.

Currently I don't see a fault in your registration method, and if there was one, you would always see service doublets. So I would assume that your discovery method has a problem. Maybe you accidentally query a handle region (and, thereby, a service) twice? It is difficult to say without seeing the corresponding methods (sending discovery requests and receiving discovery responses).

A good way to find out would be to log all discovery requests and responses and check which handle intervals have been requested and which results are returned. Do we have duplicate handle intervals? Or do we have a service registered in two different handle regions?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM