简体   繁体   English

Xamarin。形成蓝牙低功耗不一致

[英]Xamarin.Forms Bluetooth Low Energy Inconsistent

Im building a bluetooth low energy app from: https://github.com/xabre/xamarin-bluetooth-le 我从以下位置构建蓝牙低能耗应用程序: 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. 成功连接后,我还能够写入Firstname特性。

The problem is about inconsistent. 问题在于不一致。 I disabled Wifi on both devices. 我在两个设备上都禁用了Wifi。 Im using Nexus 6P(Peripheral) and OnePlus One(Center). 我正在使用Nexus 6P(外围设备)和OnePlus One(中心)。 Xamarin.Forms. 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) 这是我的BleServer类:(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) android项目上的AndroidManifest(中央)

<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. 我做了一些阅读,而BLE通常被认为是最痛苦的事情。

Summary 摘要

Goal 目标

A Xamarin.Form application thats run on different smartphones. 在不同智能手机上运行的Xamarin.Form应用程序。 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? 写入用户名数据时,我应该使用名为UserData和Firstname的特征吗? (1)?attributeXmlFile=org.bluetooth.service.user_data.xml (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 (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 (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/ 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? 还是我们在两个不同的句柄区域中注册了一项服务?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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