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.

[参考译文] CC2652R7:ZStack 错误导致在没有网络的情况下进行调试时出现竞态条件

Guru**** 2455360 points
Other Parts Discussed in Thread: CC2652R7, Z-STACK

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

https://e2e.ti.com/support/wireless-connectivity/zigbee-thread-group/zigbee-and-thread/f/zigbee-thread-forum/1545659/cc2652r7-zstack-bug-leading-to-race-condition-on-commissioning-with-no-networks

器件型号:CC2652R7
主题中讨论的其他器件: Z-stack

工具/软件:

您好:

我们遇到竞争情况、导致在调试期间应用程序任务挂起。

启动和初始化后:

zstack_bdbStartCommissioningReq_t zstack_bdbStartCommissioningReq;
zstack_bdbStartCommissioningReq.commissioning_mode = BDB_COMMISSIONING_MODE_IDDLE;
Zstackapi_bdbStartCommissioningReq(task_id, &zstack_bdbStartCommissioningReq);

The main APP loop then receives the following events:

1. zstackmsg_CmdIDs_BDB_NOTIFICATION
   - mode: BDB_COMMISSIONING_INITIALIZATION
   - status: NO_NETWORK
   - remainModes: 0

APP calls bdb_StartCommissioning(BDB_COMMISSIONING_MODE_NWK_STEERING);

2. zstackmsg_CmdIDs_BDB_NOTIFICATION
> - mode: NWK_STEERING
> - status: IN_PROGRESS
> - remainModes: 2

APP no action

3. zstackmsg_CmdIDs_DEV_STATE_CHANGE_IND
   - state: zstack_DevState_NWK_DISC

APP no action

4. zstackmsg_CmdIDs_BDB_FILTER_NWK_DESCRIPTOR_IND

APP calls Zstackapi_bdbFilterNwkDescComplete(app_task_id)

5. zstackmsg_CmdIDs_BDB_FILTER_NWK_DESCRIPTOR_IND

APP calls Zstackapi_bdbFilterNwkDescComplete(app_task_id)

*** App task hangs

原因如下:

The call to Zstackapi_bdbFilterNwkDescComplete in event 4 does the following:
[APP] Zstackapi_bdbFilterNwkDescComplete
[APP]   => sendReqDefaultRsp
[APP]      => OsalPort_msgSend
[APP]      => while(!gotRsp)
[APP]         {
[APP]             // Wait for the response message
[APP]             OsalPort_blockOnEvent(Task_self());
[APP]             pCmdStatus = (zstackmsg_genericReq_t*)OsalPort_msgFindDequeue(appServiceTaskId, pMsg->hdr.event);
[APP]             if(pCmdStatus)
[APP]             {
[APP]                 gotRsp = true;
[APP]             }
[APP]         }

The zstack task handles the incoming message like this:
processBdbFilterNwkDescCompleteReq
[ZSTACK] => bdb_tryNwkAssoc(); joinState = BDB_JOIN_STATE_NWK_DISC
[ZSTACK]    => bdb_SendMsg(task: 7, state: 3, status: fail)
[ZSTACK] => sent reponse to APP task

The BDB task takes this message and effectively does this:
bdb_event_loop
[BDB] => OsalPort_msgReceive [BDB_COMMISSIONING_STATE_JOINING]
[BDB]    => bdb_ProcessOSALMsg(msg)
[BDB] 	  => bdb_nwkDiscoveryAttempt(FALSE);
[BDB]          => If secondary channel not tried yet - try
[BDB]          => else
[BDB]             => bdb_reportCommissioningState(BDB_COMMISSIONING_STATE_JOINING, FALSE);
[BDB]                 => ...
[BDB]                 => bdb_setFN();
[BDB]                 => NLME_ResetRequest();
[BDB]                 => ZMacReset
[BDB]                     => MAP_MAC_MlmeResetReq
[BDB]                         => OsalPort_clearTaskQueues

也许您能明白这是怎么回事。 为了响应 APP 事件 4、BDB 任务会尝试辅助通道、这会触发 APP 事件 5。

在应用程序事件 5 上、BDB 任务最终会清除所有任务队列。 根据各种任务的精确时序、记录取消/启用等。这可能会在应用任务接收到发送到 ZStack 任务的消息的响应之前发生。

总结:

1. APP calls OsalPort_msgSend (zstackmsg_CmdIDs_BDB_FILTER_NWK_DESC_COMPLETE_REQ)
2. APP blocks on itself and waits for response from the ZSTACK task
   - OsalPort_blockOnEvent
   - OsalPort_msgFindDequeue
   - loop
3. ZSTACK task sends msg to BDB task
4. ZSTACK task puts response in APP message queue
5. BDB task clears all message queues
6. APP waits forever for a message that will never come

请确认我们的理解是正确的、并且我们没有遗漏任何东西。

此致

环境:

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

    您好 Kenny、

    感谢您对此问题的深入报告。   另一个 E2E 用户报告了 相同的行为以及 TI 自己的内部观察结果。  有一个 15.4-Stack 低级问题正在进行进一步调查、同时您可以:

    • 使用 SimpleLink F2 SDK v7.41、其中未演示该行为
    • 配置看门狗或时钟超时以复位器件
    • 尝试相关 E2E 帖子使用的权变措施(TI 未确认)

    此致、
    Ryan

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

    尊敬的 Kenny:

    应使用以下权变措施:

    void OsalPort_clearTaskQueues( void )
    {
    // uint8_t i;
    // uint8_t *pMsg;
    //
    // for(i = 0; i < taskCnt; i++)
    // {
    // while((pMsg = OsalPort_msgReceive(i)) != NULL)
    // {
    // OsalPort_msgDeallocate(pMsg);
    // }
    // }
    }

    TI 研发部门将在下一个 SimpleLink F2 SDK 版本前实施修复。

    此致、
    Ryan

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

    您好、Ryan、

    感谢您的快速答复。

    未通过该变通办法清除队列是否存在任何问题?

    我们通过在应用程序发送->等待响应周围放置二进制信标来修复它,并像这样清除应用程序队列代码部分,但如果完全删除它没有任何后果,那么我们就只需这样做

    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    // app_main.c
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    
    uint8_t app_task_id = 0xff;
    ...
    void app_initialize()
    {
    ...
        app_task_id = OsalPort_registerTask(Task_self(), h_app_loop_sem, &app_task_events);
    ...
    }
    
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    // osal_task_clear_fix.h
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    
    #ifndef APPLICATION_OSAL_TASK_CLEAR_FIX_H_
    #define APPLICATION_OSAL_TASK_CLEAR_FIX_H_
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #define TASK_CLEAR_FIX
    
    #ifdef TASK_CLEAR_FIX
    
    extern uint8_t app_task_id;
    
    uint8_t OsalPort_getTaskId(void* taskHndl);
    
    void osal_task_clear_fix_init();
    void osal_task_clear_fix_pend();
    void osal_task_clear_fix_post();
    
    #endif // #ifdef TASK_CLEAR_FIX
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif /* APPLICATION_OSAL_TASK_CLEAR_FIX_H_ */
    
    
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    // osal_task_clear_fix.c
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    
    #include "osal_task_clear_fix.h"
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/BIOS.h>
    
    static Semaphore_Struct app_wait_for_rsp_sem;
    static Semaphore_Handle h_app_wait_for_rsp_sem = NULL;
    
    void osal_task_clear_fix_init()
    {
        Semaphore_Params params;
        Semaphore_Params_init(&params);
        params.mode = ti_sysbios_knl_Semaphore_Mode_BINARY;
        Semaphore_construct(&app_wait_for_rsp_sem, 1, &params);
        h_app_wait_for_rsp_sem = Semaphore_handle(&app_wait_for_rsp_sem);
    }
    
    
    void osal_task_clear_fix_pend()
    {
        if (h_app_wait_for_rsp_sem) {
            Semaphore_pend(h_app_wait_for_rsp_sem, BIOS_WAIT_FOREVER);
        }
    }
    
    void osal_task_clear_fix_post()
    {
        if (h_app_wait_for_rsp_sem) {
            Semaphore_post(h_app_wait_for_rsp_sem);
        }
    }
    ```
    
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    // [SDK FILE] osal_port.c
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    
    // ============================= EDIT BEGIN =============================
    #include "osal_task_clear_fix.h"
    // ============================= EDIT END =============================
    
    void OsalPort_clearTaskQueues( void )
    {
        uint8_t  i;
        uint8_t *pMsg;
    
        for(i = 0; i < taskCnt; i++)
        {
            // ============================= EDIT BEGIN =============================
    #ifdef TASK_CLEAR_FIX
            // app_task_id is statically init to 0xff and
            // is set after the semaphore is initalized.
            if (i == app_task_id) {
                osal_task_clear_fix_pend();
            }
    #endif
            // ============================= EDIT END =============================
    
          while((pMsg = OsalPort_msgReceive(i)) != NULL)
          {
              OsalPort_msgDeallocate(pMsg);
          }
          
          // ============================= EDIT BEGIN =============================
    #ifdef TASK_CLEAR_FIX
          // app_task_id is statically init to 0xff and
          // is set after the semaphore is initalized.
          if (i == app_task_id) {
              osal_task_clear_fix_post();
          }
    #endif
          // ============================= EDIT END =============================
    
        }
    }
    
    
    
    // ============================= EDIT BEGIN =============================
    uint8_t OsalPort_getTaskId(void* taskHndl)
    {
        for(uint8_t taskIdx = 0; taskIdx < taskCnt; taskIdx++)
        {
            if (taskTbl[taskIdx].taskHndl == taskHndl) {
                return taskIdx;
            }
        }
        return 0xff;
    }
    // ============================= EDIT END =============================
    
    
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    // [SDK FILE] zstackapi.c
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    
    // ============================= EDIT BEGIN =============================
    #include "osal_task_clear_fix.h"
    // ============================= EDIT END =============================
    static zstack_ZStatusValues sendReqDefaultRsp(uint8_t appServiceTaskId,
                                                  zstack_CmdIDs cmdID, void *pReq,
                                                  int msgSize)
    {
        zstack_ZStatusValues status = zstack_ZStatusValues_ZMemError;
        uint8_t msgStatus;
    
        //Make sure allocate space enought for the msg, even
        //if the message does not have payload
        if(msgSize < sizeof(zstackmsg_genericReq_t))
        {
          msgSize = sizeof(zstackmsg_genericReq_t);
        }
    
        zstackmsg_genericReq_t *pMsg =
            (zstackmsg_genericReq_t *)OsalPort_msgAllocate(msgSize);
    
        // Make sure the allocation was successful
        if(pMsg != NULL)
        {
            // Fill in the message header
            pMsg->hdr.event = cmdID;
            pMsg->hdr.status = 0;
            pMsg->hdr.srcServiceTask = appServiceTaskId;
    
            // Update the messges's request field
            pMsg->pReq = pReq;
    
            // ============================= EDIT BEGIN =============================
    #ifdef TASK_CLEAR_FIX
            // Do any other tasks call this fn?
            bool is_app_task = OsalPort_getTaskId(Task_self()) == app_task_id;
            if (is_app_task) {
                osal_task_clear_fix_pend();
            }
    #endif
            // ============================= EDIT END =============================
    
            // Send the message
            msgStatus = OsalPort_msgSend( stackServiceTaskId, (uint8_t*) pMsg );
    
            // Was the message sent successfully
            if(msgStatus == OsalPort_SUCCESS)
            {
                bool gotRsp = false;
    
                // Return status
                zstackmsg_genericReq_t *pCmdStatus = NULL;
    
                while(!gotRsp)
                {
                    // Wait for the response message
                    OsalPort_blockOnEvent(Task_self());
    
                    pCmdStatus = (zstackmsg_genericReq_t*)OsalPort_msgFindDequeue(appServiceTaskId, pMsg->hdr.event);
    
                    if(pCmdStatus)
                    {
                      gotRsp = true;
                    }
                }
                // ============================= EDIT BEGIN =============================
    #ifdef TASK_CLEAR_FIX
                if (is_app_task) {
                    osal_task_clear_fix_post();
                }
    #endif
                // ============================= EDIT END =============================
    
                 // setup return of
                status = (zstack_ZStatusValues)pCmdStatus->hdr.status;
            }
    
            // pCmdStatus is the same as pMsg
            OsalPort_msgDeallocate( (uint8_t*)pMsg);
        }
    
        // function status
        return(status);
    }

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

    建议的解决方案不会产生任何后果、 OsalPort_clearTaskQueues API 只能用于不适用 Z-Stack 解决方案的 15.4 堆栈协处理器项目。

    此致、
    Ryan