This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CC2340R5:如何处理 blePending (0x16)返回代码

Guru**** 2587365 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/1396486/cc2340r5-how-to-handle-blepending-0x16-return-code

器件型号:CC2340R5

工具与软件:

您好!

我有一个中央应用程序查询外设 GATT 表以获取特定服务和特征。 我已经找到了服务声明、找到了特征声明、现在我正在尝试获取具有通知属性的其中一个特征的 CCC 的句柄。  

我一直在使用 根据简单的中央示例修改的 GATT_eventhandler 函数、并对堆栈发出调用以开始发现过程的下一阶段。 但当我使用 GATT_DiscAllCharDescs()时、我得到一个返回代码0x16、该代码对应于 bcomdef.h 文件中的 blePending。

那么、如何应对可能挂起的操作? 我永远不会收到任何 ATT_FIND_INFO_RSP 事件、即使我已经为这些事件注册、所以我假定请求永远不会被发送出去。

是否存在指示请求完成事件何时出现的事件? 否则、我们如何知道 BLE 栈何时可用于另一个请求?

GATT_eventhandler 状态机中的相关分支如下:

    case ATT_READ_BY_TYPE_RSP:
      {
          attReadByTypeRsp_t *rsp = ( attReadByTypeRsp_t * )&(gattMsg->msg.readByTypeRsp);

          //MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE, 0, "GATT status: ATT_READ_BY_TYPE_RSP");

          for(size_t i = 0; i < rsp->numPairs; i++) {
              uint16_t attributeHandle = BUILD_UINT16( rsp->pDataList[i * rsp->len + 3],
                                                       rsp->pDataList[i * rsp->len + 4]);
              
              if(appCar_checkIfCharHandleBelongs(&carDataSvc, attributeHandle)) {
                  MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE1+carDataSvc.discStage+i, 0, "GATT Status: Found char %s with handle %d, discStage %d",
                                    BLEAppUtil_convertBytes2Str(&rsp->pDataList[i*rsp->len+5],ATT_UUID_SIZE), attributeHandle, carDataSvc.discStage);
                  appCar_storeCharHandles(&carDataSvc, attributeHandle, &rsp->pDataList[i*rsp->len+5]);
              }

              if(carDataSvc.discStage == CAR_DATASVC_NUM_CHARS) {
                  MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE1+carDataSvc.discStage, 0, "GATT Char Discovery Complete");

                  status = appCar_findCharDescs(&carDataSvc);

                  if (status == SUCCESS) {
                      MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE, 0, "GATT Status: start characteristic description discovery");
                  } else {
                      MenuModule_printf(APP_MENU_PROFILE_STATUS_LINE, 0, "GATT Status: characteristic description discovery failed with code %d", status);
                  }
              }
          }

          break;
      }

 appCar_findCharDescs 的函数定义当前只是 GATT_DiscAllCharDescs()的包装器:

bStatus_t  appCar_findCharDescs(carDataServiceGattProfile_t* gattProfile) {

    return GATT_DiscAllCharDescs(gattProfile->connHandle, gattProfile->serviceHandleStart, gattProfile->serviceHandleEnd, BLEAppUtil_getSelfEntity());
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Munan、您好!

    感谢您的咨询。

    根据返回错误的函数、可以通过不同的方式处理错误。 例如、如果为传输通知或 GATT 写入命令分配了存储器、则在返回 blepend 时、应该释放 mem。 在这种情况下、应用程序可以重试。 但是、问题可能与传递给 GATT_DiscAllCharDescs()的参数的正确性有关、您能否提供有关这些参数的更多信息(connHandle、startHandle、endHandle)。

    此外、只有当该过程成功时、堆栈才会返回 ATT_FIND_INFO_RSP。 您能否检查一下是否收到 ATT_ERROR_RSP

    BR、

    David。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 David:

    感谢您的反馈。  

    我在 GATT_DiscAllCharDescs()处放置了一个断点、下面是传递到 API 调用的 gattProfile 的快照:

    就 ATT_ERROR_RSP 而言、我没有在菜单中看到任何表明提供了错误响应的打印输出。

    到目前为止、我一直静态分配 attReadByTypeReq_t 等内容、因此您会说、如果我在请求完成后使用 BLE 堆栈分配器、它将释放内存、并且我可以在应用中生成一个可在空闲后处理操作的事件。

    Munan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Munan、您好!

    我想问您是否已在 GATTHandler 的.EventMask 中添加事件(BLEAPPUTIL_ATT_ERROR_RSP 和 BLEAPPUTIL_ATT_FIND_INFO_RSP)? 您是否修改了 carDataSvc? 我将查看一个开箱即用示例以查看标准 HandleEnd 值。

    您是否还可以尝试使用手机等其他中央设备执行 GATT 发现(使用 SimpleLink Connect 应用程序或 BTool -\tools\ble5stack\btool、其中刷写 host_test_app.hex)? 这样做的目的是确保 GATT 表/外设–服务器正常工作?

    关于存储器分配、这是一个如何处理隐寄的示例、但如果不进行动态分配、则不必释放已分配的存储器。

    BR、

    David。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 David:

    是的、我已经将 BLEAPPUTIL_ATT_ERROR_RSP 和 BLEAPPUTIL_ATT_FINDINFO_RSP 添加到事件掩码中:

    // Events handlers struct, contains the handlers and event masks
    // of the application data module
    BLEAppUtil_EventHandler_t dataGATTHandler =
    {
        .handlerType    = BLEAPPUTIL_GATT_TYPE,
        .pEventHandler  = GATT_EventHandler,
        .eventMask      = BLEAPPUTIL_ATT_FLOW_CTRL_VIOLATED_EVENT |
                          BLEAPPUTIL_ATT_MTU_UPDATED_EVENT |
                          BLEAPPUTIL_ATT_FIND_INFO_RSP |
                          BLEAPPUTIL_ATT_FIND_BY_TYPE_VALUE_RSP |
                          BLEAPPUTIL_ATT_READ_BY_GRP_TYPE_RSP |
                          BLEAPPUTIL_ATT_READ_BY_TYPE_RSP |
                          BLEAPPUTIL_ATT_READ_RSP |
                          BLEAPPUTIL_ATT_WRITE_RSP |
                          BLEAPPUTIL_ATT_EXCHANGE_MTU_RSP|
                          BLEAPPUTIL_ATT_ERROR_RSP |
                          BLEAPPUTIL_ATT_HANDLE_VALUE_NOTI
    };

    我确实使用了 BTOOL 来帮助验证我在这里的方法以发现 CCC 句柄、我发布了具有相同起始句柄和结束句柄的相同命令、它返回的结果与我预期的完全相同。

    对于它的价值, carDataSvc 基本上只是一个黑客版本的 data_stream 服务示例. 那么、我到目前为止所做的就是更改 UUID。

    Munan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Munan、您好!

    我明白、感谢您的更新。

    我们可以尝试使用 GATT_DiscPrimaryServiceByUUID() API 吗? 如果找到服务、则 ATT_FIND_BY_TYPE_VALUE_RSP 事件将发布到应用程序中、我们使用 GATT_DiscAllChars()发现所有特征。 如果希望使用 UUID 发现特征,则 应使用 GATT_DiscCharsByUUUID() API ,其使用方式与前面提到的服务 API 非常相似。

     请告诉我如何发展。

    BR、

    David。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 David:

    我确实使用 GATT_DiscPrimaryServiceByUUID API 来发现服务、然后使用 GATT_DiscAllChars()来查找特征句柄。

    我发现 GATT_DiscAllChars 仅查找主要特征声明:

    我在 BTool 中找到的唯一发现 CCC 的 GATT API 调用是调用 GATT_DiscAllCharDescs()。

    此外、为了仔细检查、我在 ATT_READ_BY_TYPE_RSP 中添加了一个打印件、以打印返回的每个句柄、我没有看到任何其他东西、除了返回的句柄37和40。

    最后、我曾尝试使用 GATT_DiscCharsByUUID 专门搜索 CCCD 的 UUID 0x2920、但该调用未返回任何结果:

    对于可能发生的情况、还有其他建议或想法?

    Munan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Munan、您好!

    您能指出我们的调用 GATT_DiscPrimaryServiceByUUID()的位置吗? 我建议在应用程序接收到 BLEAPPUTIL_LINK_ENVERSED_EVENT 时在 ConnHandler 中执行此操作。

    gapEstLinkReqEvent_t *gapMsg = (gapEstLinkReqEvent_t *) pMsgData,
    switch(event)
    {
        case BLEAPPUTIL_LINK_ESTABLISHED_EVENT:
        
        ...
        
        bStatus_t status = GATT_DiscPrimaryServiceByUUID(gapMsg -> connectionHandle, &pUUID, ATT_BT_UUID_SIZE, BLEAppUtil_getSelfEntity());
        
        ...
    
    }

    BR、

    David。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 David:

    是的、这是我启动主要服务扫描的位置:

            case BLEAPPUTIL_LINK_ESTABLISHED_EVENT:
            {
                gapEstLinkReqEvent_t *gapEstMsg = (gapEstLinkReqEvent_t *)pMsgData;
                bStatus_t gattScanStatus;
                // Add the connection to the connected device list
                Connection_addConnInfo(gapEstMsg->connectionHandle, gapEstMsg->devAddr);
    
                /*! Print the peer address and connection handle number */
                MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Established - "
                                  "Connected to " MENU_MODULE_COLOR_YELLOW "%s " MENU_MODULE_COLOR_RESET
                                  "connectionHandle = " MENU_MODULE_COLOR_YELLOW "%d" MENU_MODULE_COLOR_RESET,
                                  BLEAppUtil_convertBdAddr2Str(gapEstMsg->devAddr), gapEstMsg->connectionHandle);
    
                /*! Print the number of current connections */
                MenuModule_printf(APP_MENU_NUM_CONNS, 0, "Connections number: "
                                  MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET,
                                  linkDB_NumActive());
                gattScanStatus = appCar_scanGATTForDataSvc(gapEstMsg->connectionHandle);
                break;

    bStatus_t appCar_scanGATTForDataSvc(uint16_t connHandle) {
    
        bStatus_t status;
    
        status  = GATT_DiscAllPrimaryServices(connHandle, BLEAppUtil_getSelfEntity());
        MenuModule_printf(APP_MENU_GENERAL_STATUS_LINE, 0, "Call Status: GATT_DiscAllPrimaryServices = "
                              MENU_MODULE_COLOR_BOLD MENU_MODULE_COLOR_RED "%d" MENU_MODULE_COLOR_RESET,
                              status);
    
        return status;
    }

    我在 GATT 事件处理程序中检查发现的服务是否是我所寻找/期望的服务。

    Munan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Munan、您好!

    请确认以下内容以确保我们在同一页面上:

    1. 您使用的是 GATT_DiscAllPrimaryServices ()(不是前面提到的 GATT_DiscPrimaryServiceByUUUUUE())?
    2. 使用 GATT_DiscAllPrimaryServices 时是否接收到成功状态和 ATT_READ_BY_GRP_TYPE_RSP 事件?
    3. 如果 GATT_DiscXXXPrimaryXXXX ()函数运行正常,并且您在执行 GATT_DiscAllCharDescs ()时遇到问题,您是否可以在调用特征发现函数之前尝试添加 ClockP_SLEEP(1)并查看该函数的返回状态? 我们已经看到、如果不引入延迟、发现过程可能会失败、因为堆栈仍在处理信息。

    BR、

    David。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 David:

    感谢您的建议、为了完整起见、我最后还是让它可行、感谢您离线分享外设示例!

    您关于添加 ClockP_SLEEP (1)的建议可以消除返回代码问题。 我基本上在特征发现之前添加了一个休眠状态、然后在  GATT_DiscAllCharDescs () 步骤之前添加了另一个休眠状态、这似乎可以正常运行、代码现在继续查找整个 GATT 表。

    我想我有一个建议是、如果应用程序能够检查堆栈是否已为请求做好准备、这可能会有所帮助、而不是仅仅添加手动等待周期、或者定期重试、直到堆栈准备就绪、这会增加额外的开销。

    Munan