And*_*ler 35 android bluetooth-lowenergy
我的问题是:Android 4.3(客户端)可以与多个BLE设备(服务器)建立活动连接吗?如果是这样,我该如何实现呢?
到目前为止我做了什么
我尝试使用BLE和Android 4.3 BLE API评估您可以实现的吞吐量.此外,我还尝试找出可以同时连接和激活的设备数量.我使用Nexus 7(2013),Android 4.4作为主设备,TI CC2540 Keyfob作为从设备.
我为奴隶编写了一个简单的服务器软件,它通过BLE通知传输10000个20Byte数据包.我将我的Android应用程序基于Bluetooth SIG 的Application Accelerator.
它适用于一个设备,我可以在7.5 ms的连接间隔内实现大约56 kBits的有效载荷吞吐量.为了连接多个奴隶,我遵循了在北欧开发者区撰写的北欧员工的建议:
是的,可以使用单个应用程序处理多个从属服务器.您需要使用一个BluetoothGatt实例处理每个从属设备.对于您连接的每个从站,您还需要特定的BluetoothGattCallback.
所以我尝试了它,部分工作.我可以连接到多个奴隶.我也可以注册多个奴隶的通知.当我开始测试时,问题就开始了.我首先收到来自所有从站的通知,但是经过几次连接间隔后,只有来自一个设备的通知才会通过.大约10秒后,其他从属设备断开连接,因为它们似乎达到连接超时.有时我从测试开始就收到来自一个奴隶的通知.
我也尝试通过读取操作访问该属性,结果相同.在几次读取之后,只有一个设备的答案来了.
我知道在这个论坛上有一些类似的问题:Android 4.3是否支持多个BLE设备连接?,原生Android BLE GATT实现同步性吗?或Ble多重连接.但是,如果有可能以及如何做到这一点,这些答案都没有让我清楚.
我非常感谢你的建议.
Tim*_*mmm 21
我怀疑每个人添加延迟只是让BLE系统在您提交另一个之前完成您所要求的操作.Android的BLE系统没有排队的形式.如果你这样做
BluetoothGatt g;
g.writeDescriptor(a);
g.writeDescriptor(b);
Run Code Online (Sandbox Code Playgroud)
然后第一个写操作将立即被第二个写操作覆盖.是的,它真的很愚蠢,文档应该实际上提到这一点.
如果插入等待,则允许在执行第二个操作之前完成第一个操作.但这是一个巨大的丑陋黑客.更好的解决方案是实现自己的队列(就像Google应该拥有的那样).幸运的是,Nordic已经为我们发布了一个.
编辑:顺便说一下,这是BLE API的通用行为.WebBluetooth的行为方式相同(但Javascript确实使它更容易使用),我相信iOS的BLE API行为也一样.
Rai*_*ain 13
这个概念:在每个引发BluetoothGattCallback的主要动作(例如,连接,服务发现,写入,读取)之后,都需要dealy.PS看一下关于BLE API 19级样本的 Google示例,以了解如何发送广播并获得一些一般性的了解......
首先,扫描(或扫描)BluetoothDevices,使用所需设备填充connectionQueue并调用initConnection().
看看下面的例子.
private Queue<BluetoothDevice> connectionQueue = new LinkedList<BluetoothDevice>();
public void initConnection(){
if(connectionThread == null){
connectionThread = new Thread(new Runnable() {
@Override
public void run() {
connectionLoop();
connectionThread.interrupt();
connectionThread = null;
}
});
connectionThread.start();
}
}
private void connectionLoop(){
while(!connectionQueue.isEmpty()){
connectionQueue.poll().connectGatt(context, false, bleInterface.mGattCallback);
try {
Thread.sleep(250);
} catch (InterruptedException e) {}
}
}
Run Code Online (Sandbox Code Playgroud)
现在如果一切都很好,你已经建立了连接并且已经调用了BluetoothGattCallback.onConnectionStateChange(BluetoothGatt gatt,int status,int newState).
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
switch(status){
case BluetoothGatt.GATT_SUCCESS:
if (newState == BluetoothProfile.STATE_CONNECTED) {
broadcastUpdate(BluetoothConstants.ACTION_GATT_CONNECTED, gatt);
}else if(newState == BluetoothProfile.STATE_DISCONNECTED){
broadcastUpdate(BluetoothConstants.ACTION_GATT_DISCONNECTED, gatt);
}
break;
}
}
protected void broadcastUpdate(String action, BluetoothGatt gatt) {
final Intent intent = new Intent(action);
intent.putExtra(BluetoothConstants.EXTRA_MAC, gatt.getDevice().getAddress());
sendBroadcast(intent);
}
Run Code Online (Sandbox Code Playgroud)
PS sendBroadcast(intent)可能需要像这样完成:
Context context = activity.getBaseContext();
context.sendBroadcast(intent);
Run Code Online (Sandbox Code Playgroud)
广播由BroadcastReceiver.onReceive(...)接收
public BroadcastReceiver myUpdateReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(BluetoothConstants.ACTION_GATT_CONNECTED.equals(action)){
//Connection made, here you can make a decision: do you want to initiate service discovery.
// P.S. If you are working with multiple devices,
// make sure that you start the service discovery
// after all desired connections are made
}
....
}
}
Run Code Online (Sandbox Code Playgroud)
在广播接收器中做任何你想做的事后,我继续这样做:
private Queue<BluetoothGatt> serviceDiscoveryQueue = new LinkedList<BluetoothGatt>();
private void initServiceDiscovery(){
if(serviceDiscoveryThread == null){
serviceDiscoveryThread = new Thread(new Runnable() {
@Override
public void run() {
serviceDiscovery();
serviceDiscoveryThread.interrupt();
serviceDiscoveryThread = null;
}
});
serviceDiscoveryThread.start();
}
}
private void serviceDiscovery(){
while(!serviceDiscoveryQueue.isEmpty()){
serviceDiscoveryQueue.poll().discoverServices();
try {
Thread.sleep(250);
} catch (InterruptedException e){}
}
}
Run Code Online (Sandbox Code Playgroud)
同样,在成功发现服务之后,将调用BluetoothGattCallback.onServicesDiscovered(...).再次,我向BroadcastReceiver发送一个意图(这次使用不同的动作字符串),现在你可以开始阅读,编写和启用通知/指示... PS如果你正在使用多个设备,请确保你开始所有设备报告他们的服务已经被发现之后的阅读,写作等等.
private Queue<BluetoothGattCharacteristic> characteristicReadQueue = new LinkedList<BluetoothGattCharacteristic>();
private void startThread(){
if(initialisationThread == null){
initialisationThread = new Thread(new Runnable() {
@Override
public void run() {
loopQueues();
initialisationThread.interrupt();
initialisationThread = null;
}
});
initialisationThread.start();
}
}
private void loopQueues() {
while(!characteristicReadQueue.isEmpty()){
readCharacteristic(characteristicReadQueue.poll());
try {
Thread.sleep(BluetoothConstants.DELAY);
} catch (InterruptedException e) {}
}
// A loop for starting indications and all other stuff goes here!
}
Run Code Online (Sandbox Code Playgroud)
BluetoothGattCallback将从BLE传感器获取所有传入数据.一个好的做法是将带有数据的广播发送到BroadcastReceiver并在那里处理它.
我正在开发一个具有BLE功能的应用程序.我设法连接到多个设备并打开通知的方式是实现延迟.
所以我创建一个新线程(为了不阻止UI线程)并在新线程中连接并打开通知.
例如,在BluetoothDevice.connectGatt()之后; 调用Thread.sleep();
并为读/写和启用/不可用通知添加相同的延迟.
编辑
使用这样的等待,以便Android不会让ANR感到愤怒
public static boolean waitIdle() {
int i = 300;
i /= 10;
while (--i > 0) {
if (true)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return i > 0;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
58871 次 |
| 最近记录: |