stackoverflow 上的Android BLE API: GATT Notification not received一点感想

来源:互联网 发布:淘宝电脑直通车怎么找 编辑:程序博客网 时间:2024/06/05 11:27

大家可以先看一下starkoverflow的一个讨论(时间是两年前的):

http://stackoverflow.com/questions/17910322/android-ble-api-gatt-notification-not-received


大致内容就是安卓上的app明显调用了

public boolean setCharacteristicNotification (BluetoothGattCharacteristic characteristic, boolean enable)
的接口,却收不到gatt server发过来的notification。

让我们先看看这个接口的解释:

Enable or disable notifications/indications for a given characteristic.Once notifications are enabled for a characteristic, a onCharacteristicChanged(BluetoothGatt, BluetoothGattCharacteristic) callback will be triggered if the remote device indicates that the given characteristic has changed.Requires BLUETOOTH permission.ParameterscharacteristicThe characteristic for which to enable notificationsenableSet to true to enable notifications/indicationsReturnstrue, if the requested notification status was set successfully

说的很明显啊,当你enable一个characteristic的notification之后,一旦远端相应的characteristic的值改变,则一个callback函数
onCharacteristicChanged
就会在本地被调用, 还是符合一般逻辑的,即client告诉server,你如果某个值有变化的话请通知我。

可是如果只是这样世界就完美了,也就不会有那个提问了。调用完这个函数之后,其实gatt server并没有发生什么,这个函数只是在手机本地设置了一下,竟然没有和远端交互。我们可以来看bluedroid中的代码:

/*********************************************************************************** Function         BTA_GATTC_RegisterForNotifications**** Description      This function is called to register for notification of a service.**** Parameters       client_if - client interface.**                  bda - target GATT server.**                  p_char_id - pointer to GATT characteristic ID.**** Returns          OK if registration succeed, otherwise failed.*********************************************************************************/tBTA_GATT_STATUS BTA_GATTC_RegisterForNotifications (tBTA_GATTC_IF client_if,                                                     BD_ADDR bda,                                                     tBTA_GATTC_CHAR_ID *p_char_id){    tBTA_GATTC_RCB      *p_clreg;    tBTA_GATT_STATUS    status = BTA_GATT_ILLEGAL_PARAMETER;    UINT8               i;    if (!p_char_id)    {        APPL_TRACE_ERROR("deregistration failed, unknow char id");        return status;    }    if ((p_clreg = bta_gattc_cl_get_regcb(client_if)) != NULL)    {        for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++)        {            if ( p_clreg->notif_reg[i].in_use &&                 !memcmp(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN) &&                  bta_gattc_charid_compare(&p_clreg->notif_reg[i].char_id, p_char_id))            {                APPL_TRACE_WARNING("notification already registered");                status = BTA_GATT_OK;                break;            }        }        if (status != BTA_GATT_OK)        {            for (i = 0; i < BTA_GATTC_NOTIF_REG_MAX; i ++)            {                if (!p_clreg->notif_reg[i].in_use)                {                    memset((void *)&p_clreg->notif_reg[i], 0, sizeof(tBTA_GATTC_NOTIF_REG));                    p_clreg->notif_reg[i].in_use = TRUE;                    memcpy(p_clreg->notif_reg[i].remote_bda, bda, BD_ADDR_LEN);                    p_clreg->notif_reg[i].char_id.srvc_id.is_primary = p_char_id->srvc_id.is_primary;                    bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.srvc_id.id, &p_char_id->srvc_id.id);                    bta_gattc_cpygattid(&p_clreg->notif_reg[i].char_id.char_id, &p_char_id->char_id);                    status = BTA_GATT_OK;                    break;                }            }            if (i == BTA_GATTC_NOTIF_REG_MAX)            {                status = BTA_GATT_NO_RESOURCES;                APPL_TRACE_ERROR("Max Notification Reached, registration failed.");            }        }    }    else    {        APPL_TRACE_ERROR("Client_if: %d Not Registered", client_if);    }    return status;}


我们可以看到,这个函数首先判断characteristic是否合法,之后判断是否超过了注册的notification的数量(15个),之后是把所要notify的service以及characteristic记录在本地,然后就没有了然后了。这一次搞得上层的app以为gatt server已经收到了这个注册通知。其实,gatt server啥都没有收到。

还是要看core spec:


然后再看section3.3.3 写道:

A client may write this configuration descriptor to control the configuration ofthis characteristic on the server for the client.

也就是说,client可以用来通过写入一个characteristic的descriptor的值,然后来控制server在这个characteristic变化的时候,是否通知client。

好吧其实一般的思维即是,我调用了前面的接口之后,stack应该办上面设置descriptor的事儿,没有想到完全是两码事……

所以,最终还需要重新写一下这个descriptor,这完全在google的API文档里没有提到嘛,当然在google的例子里面是提到了。可是毕竟会有人没去看这个东西。


对于不熟悉蓝牙的同学来讲是个很大的坑。所以下面这个接口

public boolean writeDescriptor (BluetoothGattDescriptor descriptor)


很重要。



0 0
原创粉丝点击