如何创建 Android BLE 外围设备?

Posted

技术标签:

【中文标题】如何创建 Android BLE 外围设备?【英文标题】:How can I create an Android BLE peripheral? 【发布时间】:2015-03-24 14:53:16 【问题描述】:

我尝试制作两个蓝牙 BLE 应用:

一个核心角色 一个外围

但我发现了一些问题,我的应用程序崩溃了。

这是我遵循的步骤:

1-客户端设置描述符

BluetoothGattDescriptor descriptor = MeasurementCharacteristic.getDescriptor(
                UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        bluetoothGatt.writeDescriptor(descriptor); 

2 - onDescriptorWriteRequest 中的服务器设置

MeasurementCharacteristic.setValue(test.getBytes());
gattserver.notifyCharacteristicChanged(device, MeasurementCharacteristic, false);

3 - 客户收到此通知,我已经这样做了:

CommandsCharacteristic.setValue(string_value.getBytes());
                write(CommandsCharacteristic);

4 - 服务器在 onCharacteristicWriteRequest 中接收到这个,我已经这样做了:

if(uuid.equals(CostantUUid.Commands))
            
                .....
                engineMeasurementCharacteristic.setValue(test.getBytes());
                ble.getGattServer().notifyCharacteristicChanged(device, MeasurementCharacteristic, false);
            

5- 在客户端将调用 notifyCharacteristicChanged,我们将返回步骤 3

但遗憾的是,在收到几条消息后,通讯会自动关闭。

客户端启用描述符 服务器向客户端发送通知 客户端读取新特性并重新写入服务器 服务器向客户端重新发送通知 客户端读取发送消息给客户端 消息没有到达...

通过日志,我看到 onCharacteristicWrite 的函数在整个应用程序生命周期中只被调用一次。在没有以状态 133 到达的消息之后被调用,但我不明白为什么它没有在其他消息之后被调用。

@Override
                public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,int status)
                

                    super.onCharacteristicWrite(gatt, characteristic, status);

                    if(status==BluetoothGatt.GATT_SUCCESS)
                    
                        Log.i("test","GATT SUCCESS");
                    
                    if(status==BluetoothGatt.GATT_CONNECTION_CONGESTED)
                    
                        Log.i("test","GATT WRITE connection congested");
                    
                    if(status==BluetoothGatt.GATT_WRITE_NOT_PERMITTED)
                    
                        Log.i("test","GATT WRITE not permitted");
                    
                    if(status==BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH)
                    
                        Log.i("test","GATT invalid attribute lenght");
                    
                    if(status==BluetoothGatt.GATT_FAILURE)
                    
                        Log.i("test","GATT WRITE other errors");
                    
                    if(status==BluetoothGatt.GATT_CONNECTION_CONGESTED)
                    
                        Log.i("test","GATT WRITE congested");
                    
                    if(status==BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION)
                    
                        Log.i("test","GATT WRITE authentication");
                    
                    else
                    
                        Log.i("test","GATT WRITE :"+status);
                    
                

中心角色的日志:

    03-30 15:09:22.308: W/BLE(30615): STATE_CONNECTED
*******
*******
03-30 15:09:50.958: D/HeadsetStateMachine(2312): Disconnected process message: 10
03-30 15:09:50.958: D/KeyguardUpdateMonitor(1026): received broadcast android.intent.action.BATTERY_CHANGED
03-30 15:09:50.958: D/KeyguardUpdateMonitor(1026): handleBatteryUpdate
03-30 15:09:50.958: D/BatteryService(795): level:64, scale:100, status:3, health:2, present:true, voltage: 3898, temperature: 283, technology: Li-ion, AC powered:false, USB powered:false, Wireless powered:false, icon:17303543, invalid charger:0, online:1, current avg:-242, charge type:0, power sharing:false
03-30 15:09:50.958: D/BatteryService(795): Sending ACTION_BATTERY_CHANGED.
03-30 15:09:50.958: D/STATUSBAR-PhoneStatusBar(1026):  mBrightnessEnablebySettings = true mBrightnessEnablebyBattery = true mBrightnessEnablebyDisableFlag = true mPmsBrightnessEnablebySettings = true
03-30 15:09:50.958: D/BatteryMeterView(1026): ACTION_BATTERY_CHANGED : level:64 status:3 health:2
03-30 15:09:50.968: D/STATUSBAR-IconMerger(1026): checkOverflow(2112), More:false, Req:false Child:2
03-30 15:09:52.978: D/SensorService(795):   0.0 -0.1 9.9
03-30 15:09:55.158: D/bt_vendor(2312): op for 7
03-30 15:09:55.158: D/bt_upio(2312): proc btwrite assertion
03-30 15:09:55.178: D/s-s-rMv2:SIOP(795): SIOP:: AP = 300, Delta = 0
03-30 15:09:55.188: E/bt-btm(2312): btm_sec_disconnected - Clearing Pending flag
03-30 15:09:55.188: D/IOP_DB_BT(2312): db_query_create: id DisablePwlCtrReq :: key KEY_BDADDR, value 4b:87:e8:45:76:b9
03-30 15:09:55.188: D/IOP_DB_BT(2312): db_query_add_key: key KEY_LMP_MFCT, value 0
03-30 15:09:55.188: D/IOP_DB_BT(2312): db_query_add_key: key KEY_LMP_VER, value 0:0
03-30 15:09:55.188: D/IOP_DB_BT(2312): db_query_add_key: key KEY_DIR_ALL, value *
03-30 15:09:55.188: D/IOP_DB_BT(2312): db_query_execute: result 1
03-30 15:09:55.188: D/BtGatt.btif(2312): btif_gattc_upstreams_evt: Event 4
03-30 15:09:55.188: D/BtGatt.GattService(2312): onWriteCharacteristic() - address=4B:87:E8:45:76:B9, status=133
03-30 15:09:55.188: D/BluetoothGatt(30615): onCharacteristicWrite() - Device=4B:87:E8:45:76:B9 UUID=687bf0f0-d6dc-11e4-b9d6-1681e6b88ec1 Status=133
03-30 15:09:55.188: D/BtGatt.btif(2312): btif_gattc_upstreams_evt: Event 5
03-30 15:09:55.188: D/BtGatt.GattService(2312): onDisconnected() - clientIf=6, connId=6, address=4B:87:E8:45:76:B9
03-30 15:09:55.188: D/BluetoothGatt(30615): onClientConnectionState() - status=0 clientIf=6 device=4B:87:E8:45:76:B9
03-30 15:09:55.188: I/*****(30615): status = 0 newState = 0
03-30 15:09:55.188: W/BLE(30615): STATE_DISCONNECTED

外设日志:

03-30 15:09:24.001: D/MyActivity(10354): onCharacteristicReadRequest requestId=3 offset=00002a24-0000-1000-8000-00805f9b34fb
03-30 15:09:24.003: D/BtGatt.btif(9706): btif_gatts_send_response
03-30 15:09:24.003: D/BtGatt.btif(9706): btgatts_handle_event: Event 2012
03-30 15:09:24.003: D/BtGatt.GattService(9706): onResponseSendCompleted() handle=46
03-30 15:09:24.096: D/BtGatt.btif(9706): btapp_gatts_handle_cback: Event 1
03-30 15:09:24.097: D/BtGatt.GattService(9706): onAttributeRead() UUID=00002a27-0000-1000-8000-00805f9b34fb, serverIf=5, type=2
03-30 15:09:24.097: D/MyActivity(10354): onCharacteristicReadRequest requestId=4 offset=00002a27-0000-1000-8000-00805f9b34fb
03-30 15:09:24.098: D/BtGatt.btif(9706): btif_gatts_send_response
03-30 15:09:24.098: D/BtGatt.btif(9706): btgatts_handle_event: Event 2012
03-30 15:09:24.098: D/BtGatt.GattService(9706): onResponseSendCompleted() handle=48
03-30 15:09:24.243: D/BtGatt.btif(9706): btapp_gatts_handle_cback: Event 2
03-30 15:09:24.243: D/BtGatt.GattService(9706): onAttributeWrite() UUID=00002902-0000-1000-8000-00805f9b34fb, serverIf=5, type=3
03-30 15:09:24.246: D/BtGatt.btif(9706): btif_gatts_send_response
03-30 15:09:24.246: D/BtGatt.btif(9706): btgatts_handle_event: Event 2012
03-30 15:09:24.246: D/BtGatt.GattService(9706): onResponseSendCompleted() handle=52
03-30 15:09:24.249: D/BtGatt.btif(9706): btif_gatts_send_indication
03-30 15:09:24.252: D/BtGatt.btif(9706): btgatts_handle_event: Event 2011
03-30 15:09:24.257: D/BtGatt.btif(9706): btapp_gatts_handle_cback: Event 5
03-30 15:09:24.257: D/BtGatt.GattService(9706): onNotificationSent() connId=5, status=0
03-30 15:09:24.341: D/BtGatt.btif(9706): btapp_gatts_handle_cback: Event 2
03-30 15:09:24.341: D/BtGatt.GattService(9706): onAttributeWrite() UUID=687bf0f0-d6dc-11e4-b9d6-1681e6b88ec1, serverIf=5, type=2
03-30 15:09:24.342: D/MyActivity(10354): onCharacteristicWriteRequest requestId=6 offset=687bf0f0-d6dc-11e4-b9d6-1681e6b88ec1
03-30 15:09:24.343: I/test(10354): Message received ciao 
03-30 15:09:24.344: D/BtGatt.btif(9706): btif_gatts_send_indication
03-30 15:09:24.345: D/BtGatt.btif(9706): btgatts_handle_event: Event 2011
03-30 15:09:24.345: D/BtGatt.btif(9706): btapp_gatts_handle_cback: Event 5
03-30 15:09:24.345: D/BtGatt.GattService(9706): onNotificationSent() connId=5, status=0
03-30 15:09:54.518: W/bt-btif(9706): bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x0013
03-30 15:09:54.518: W/bt-btif(9706): bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x0013
03-30 15:09:54.519: W/bt-btif(9706): bta_gattc_conn_cback() - cif=6 connected=0 conn_id=6 reason=0x0013
03-30 15:09:54.519: E/bt-btm(9706): btm_sec_disconnected - Clearing Pending flag
03-30 15:09:54.519: D/BtGatt.btif(9706): btapp_gatts_handle_cback: Event 15
03-30 15:09:54.519: D/BtGatt.GattService(9706): onConnected() connId=5, address=B8:6C:E8:5A:99:D2, connected=false
03-30 15:09:54.520: E/BluetoothRemoteDevices(9706): aclStateChangeCallback: Device is NULL
03-30 15:09:54.521: D/BluetoothGattServer(10354): onServerConnectionState() - status=0 serverIf=5 device=B8:6C:E8:5A:99:D2
03-30 15:09:54.522: D/MyActivity(10354): onConnectionStateChange status=0->0
03-30 15:09:59.001: E/WifiStateMachine(449): WifiStateMachine CMD_START_SCAN source -2 txSuccessRate=0.69 rxSuccessRate=23.35 targetRoamBSSID=any RSSI=-69
03-30 15:10:02.207: D/HeadsetStateMachine(9706): Disconnected process message: 10, size: 0
03-30 15:10:19.001: E/WifiStateMachine(449): WifiStateMachine CMD_START_SCAN source -2 txSuccessRate=0.78 rxSuccessRate=22.32 targetRoamBSSID=any RSSI=-68
03-30 15:10:38.999: E/WifiStateMachine(449): WifiStateMachine CMD_START_SCAN source -2 txSuccessRate=0.32 rxSuccessRate=34.32 targetRoamBSSID=any RSSI=-67

编辑:我已经清除了先前的消息,并添加了您的所有建议/建议 :)

编辑 2:外围设备仍然存在,但已断开连接。如果我重新连接连接重新启动,并重做上述相同的步骤:(

EDIT3:在我这样设置的外围设备上:

settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED);
    settingsBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
    settingsBuilder.setConnectable(true);

EDIT5:我解决了我的问题。在 peripherall 内部的 OnCharacteristicWriteRequest 内部存在错误。该应用程序仍在运行,但连接崩溃了。 :)

EDIT6:如何检索我的外围设备的真实 MAC 地址?因为在客户端,当我使用“getAddress()”时,每次外围设备重启时 MAC 地址都会改变

【问题讨论】:

您不要在服务器(外设)端调用connect,您将从监视器(其他电话)角色调用connect。服务器角色应该只注册服务,并监听来自 Monitor 的命令。 bluethootgattsrver 的连接,这将在自动连接功能(如接近配置文件)的情况下由外围设备调用。对于您的另一个问题,需要双方的日志才能了解第三次尝试中发生的情况。 你必须用设备(远程设备)调用它,你可以通过它的地址创建一个设备实例。蓝牙服务或c代码可能有错误,不会显示在您的应用日志中,您需要通过adb logcat命令获取日志 远程/其他设备,如果你在客户端写代码那么远程就是服务器,反之亦然,你可以通过BluetoothAdapter.getBlu..Device(address)创建设备实例 在中心角色日志中,writeRequest(见status=133)有错误,导致断线。之后看到另一行是“onDisconnected”。 【参考方案1】:

Bluetooth Low Energy 试用官方示例。我已经使用了这个例子并且它有效。

在此示例中,Android 应用程序是客户端,但您也可以让 Android 应用程序扮演 GATT 服务器的角色。详情请见BluetoothGattServer

【讨论】:

在那个例子中它创建了一个中心角色应用程序或者我错了?我需要外围角色应用程序的示例,其中使用了 bluetoothgattserver :( 我添加了一个带有其他详细信息的答案:) @aeroxr1:如果您在问题本身中添加这些详细信息并删除该“答案”会更好:) 谢谢 :) 我不知道我的代码哪里错了 :( 有一天,我没有找到一个解决方案... :/ @aeroxr1:休息一下,然后更详细地研究这个例子。如果你有任何疑问可以问我。同时,我正在查看您发布的代码:)

以上是关于如何创建 Android BLE 外围设备?的主要内容,如果未能解决你的问题,请参考以下文章

BLE 5 外围设备未在支持 BLE 5 的 Android 手机和 iPhone 上得到扫描

Android-低功耗蓝牙(BLE)-客户端(主机/中心设备)和服务端(从机/外围设备)

Android BLE 外围设备与状态码 BLE_HCI_INSTANT_PASSED(0x28) 断开连接

Android 8.1 连接到调用 connectGatt 的 BLE 外围设备。回调总是说断开连接。从不连接

在 Android 上无需绑定的 BLE 配对

如何通过android应用连接多个BLE设备?