通信例程之GenericApp

zigbee學習筆記3-通信例程之GenericApp
剛入手的朋友,對 Z-Stack 非常迷糊的時期,如果能夠跑通幾個例子、看幾個演示,那麼可以大大提高學習興趣;另外如果知道某個例子的大致功能及實現,那麼在去看具體實現過程目的性就非常明確。 
首先來看看 TI 究竟有哪些例子: 可以看出其例子是非常豐富的。 
       GenericApp(設備互相綁定傳送信息-hellow world),Location(定位),SampleApp(設備發送和接收LED燈信息),SimpleApp(溫度和燈開關,和智能家居結合使用的,have Profile),HomeAutomation(智能家居的應用,have Profile),SerialApp(串行傳輸的應用),Transmit(發送應用), ZLOAD(協議文件夾中只有Source)。這樣看來還是不少的。其中 SampleApp 例子已經在前面的學習中有所涉及,可以說前面的所有學習都是基於這個例子的,所以這裏就不測試它了。 Location 是定位的測試例子,這裏我的硬件是不夠的,所以也不做測試。其他我都做點測試,能成功的就成功,不能成功的就失敗,這個我也沒辦法。

       1、GenericApp 
      這個實驗是兩個模塊相互綁定後可以對傳數據,模塊綁定之後,兩個模塊之間相互傳輸字符串”Hello World”。

       實驗說明:首先啓動一個網絡協調器,協調器如果建立網絡成功後,會在 LCD 上顯示該節點爲協調者同時顯示網絡 ID號。然後打開一個終端節點或路由器的電源,此時節點會自動加入網絡。加入網絡成功後,節點會顯示自己的節點類型、網絡地址和父節點的網絡地址。

節點加入網絡成功後,首先把主機模塊的搖桿往右拔一下,然後把要綁定模塊的 RIGHT按一下,如果兩邊的 LED4 都熄滅或是點亮後馬上熄滅,表示綁定成功。綁定成功後,兩個節點就開始相互定時發送數據,並在對方的LCD屏上顯示出來,發送的數據爲”Hello World”。此時如果把相互綁定模塊中的 left 按一下,可以發送 Match Description Request命令,對方則顯示 Match Description Request信息。(以上無線龍手冊提供)

2 關鍵函數分析:

我開始沒搞清楚,功能是個啥 大約瀏覽了下,這個例子似乎還與設備的 所以還決定看看程序來判斷這個例子的功能。 綁定有關係,在key control   描述中發現

//***************** Key control**************************//

SW2: initiates end device binding           //–初始化中斷設備綁定
       SW4: initiates a match description request //–初始化一個匹配描述請求

2.1 按建處理程序中發現: 
if ( keys & HAL_KEY_SW_2 ) 
    { 
      HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );

      // Initiate an End Device Bind Request for the mandatory endpoi
nt 
      dstAddr.addrMode = Addr16Bit; 
      dstAddr.addr.shortAddr = 0x0000; // Coordinator 
      ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(), 
                            GenericApp_epDesc.endPoint, 
                            GENERICAPP_PROFID, 
                            GENERICAPP_MAX_CLUSTERS, (cId_t *)Generic
App_ClusterList, 
                            GENERICAPP_MAX_CLUSTERS, (cId_t *)Generic
App_ClusterList, 
                            FALSE ); 

很明顯這裏按鍵 2(右鍵)是發送綁定請求的命令。 
if ( keys & HAL_KEY_SW_4 ) 
    { 
      HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );

      // Initiate a Match Deion Request (Service Discovery) 
      dstAddr.addrMode = AddrBroadcast; 
      dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR; 
      ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR, 
                        GENERICAPP_PROFID, 
                        GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_
ClusterList, 
                        GENERICAPP_MAX_CLUSTERS, (cId_t *)GenericApp_
ClusterList, 
                        FALSE ); 
    } 
顯然按鍵 4(左)是初始化一個匹配描述符請求,也就是發現服務,或者叫自動尋求匹配設備。 
2.2 在發送數據發現:
void GenericApp_SendTheMessage( void ) 

char theMessageData[] = “Hello World”;

if ( AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc, 
                       GENERICAPP_CLUSTERID, 
                       (byte)osal_strlen( theMessageData ) + 1, 
                       (byte *)&theMessageData, 
                       &GenericApp_TransID, 
                       AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatu
s_SUCCESS ) 

    // Successfully requested to be sent. 

else 

    // Error occurred in request to send. 

}
      這裏發送了”Hello World”字符串。如果更改這裏,是可以在接收端看到變化的。 這裏調用了 AF_DataRequest 函數,該函數爲 AF層請求發送數據函數。 
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP, 
                                              uint16 cID, uint16 len, uint8 *buf, uint8 *transID, 
                                              uint8 options, uint8 radius ) 
我想最關心的就是幾個參數: 

1、目標地址:&GenericApp_DstAddr

typedef struct
{
union
{
    uint16 shortAddr;
} addr;
afAddrMode_t addrMode;
byte endPoint;
} afAddrType_t;//–裏面定義了目標地址模式、地址、EP三個參數

2、端點描述符:&GenericApp_epDesc 
typedef struct 

byte endPoint; 
byte *task_id; // Pointer to location of the Application task ID. 
SimpleDescriptionFormat_t *simpleDesc; 
afNetworkLatencyReq_t latencyReq; 
} endPointDesc_t; 
3、串 ID 

#define GENERICAPP_CLUSTERID          1 
4、發送數據 
數據長度:(byte)osal_strlen( theMessageData ) + 1, 
數據載荷: (byte *)&theMessageData, 
5、發送 ID:&GenericApp_TransID

6、選項:AF_DISCV_ROUTE 

#define AF_DISCV_ROUTE                     0x20 
7、發送半徑:AF_DEFAULT_RADIUS 
#define AF_DEFAULT_RADIUS                  DEF_NWK_RADIUS 
網絡路由深度,初始化爲: #define DEF_NWK_RADIUS    10

2.3 接收處理函數發現 :

void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) ///接收處理函數
{
switch ( pkt->clusterId )
{
    case GENERICAPP_CLUSTERID:
      // “the” message

#if defined( LCD_SUPPORTED )
     // HalLcdWriteScreen( (char*)pkt->cmd.Data, “rcvd” );
      Print8(HAL_LCD_LINE_2,10,”                “, 1);
      Print8(HAL_LCD_LINE_3,10,”                “, 1);
      Print8(HAL_LCD_LINE_2,10,(INT8U*)pkt->cmd.Data, 1);
      Print8(HAL_LCD_LINE_3,16, “WXL Welcome”, 1);
      break;
#endif

}
}
       接收數據處理函數里居然要通過液晶顯示,本人這裏的液晶暫時沒有移植過來,因爲暫時還不具備那個實力,怪不得看不到發送數據的狀況!這裏本人就自作聰明的把以前 SampleApp 例子裏面的一句話加過來了: 
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) //–修改的哦

switch ( pkt->clusterId ) 

    case GENERICAPP_CLUSTERID: 
      // “the” message 
HalLedBlink( HAL_LED_4, 4, 50, (500) );

#if defined( LCD_SUPPORTED ) 
      HalLcdWriteScreen( (char*)pkt->cmd.Data, “rcvd” ); 
#elif defined( WIN32 ) 
      WPRINTSTR( pkt->cmd.Data ); 
#endif 
      break; 


      麼想到啊,這麼一加居然就有反應了!其實這裏很簡單的了,就是接收到數據後閃爍 4 下燈,間隔 0.5S。因爲從:GenericApp_ProcessEvent中有週期性發送函數

2.4 週期性發送函數

if ( events & GENERICAPP_SEND_MSG_EVT ) 

    // Send “the” message 
    GenericApp_SendTheMessage(); //–發送信息
    // Setup to send message again 
    osal_start_timerEx( GenericApp_TaskID, 
                        GENERICAPP_SEND_MSG_EVT, 
                        GENERICAPP_SEND_MSG_TIMEOUT ); 
    // return unprocessed events 
    return (events ^ GENERICAPP_SEND_MSG_EVT); 

        這裏可以看出,這個例子很明顯僅僅是個發送週期信息的例子。所以 LED4 就週期性的閃爍 4 下,當然是協調器發送,路由器閃爍,路由器發送,協調器閃爍。 該事件是一個用戶事件,不在系統事件內。可以看到調用了發送函數 GenericApp_SendTheMessage();,之後又調用了osal_start_timerEx函數觸發定時發送數據,所以是一個週期發送。 發送了,不一定對方一定能收到,這裏只有匹配描述符的才能接收這個信息。

2.5 再來看看ZDO 響應函數:

void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )
{
switch ( inMsg->clusterID )
{
    case End_Device_Bind_rsp: //–綁定
      if ( ZDO_ParseBindRsp( inMsg ) == ZSuccess )
      {
        // Light LED
        HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
      }

#if defined(BLINK_LEDS)
      else
      {
        // Flash LED to show failure
        HalLedSet ( HAL_LED_4, HAL_LED_MODE_FLASH );
      }
#endif
      break;

    case Match_Desc_rsp: //–描述符匹配
      {
        ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );
        if ( pRsp )
        {
          if ( pRsp->status == ZSuccess && pRsp->cnt )
          {
            GenericApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
            GenericApp_DstAddr.addr.shortAddr = pRsp->nwkAddr;
            // Take the first endpoint, Can be changed to search through endpoints
            GenericApp_DstAddr.endPoint = pRsp->epList[0];

            // Light LED
            HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
          }
          osal_mem_free( pRsp );
        }
      }
      break;
}
}

        這裏兩類事件,主要是針對兩種按鍵操作的響應處理:綁定響應和描述符匹配響應。 可以看到,當綁定成功 G燈點亮,失敗 G燈閃爍。 描述符匹配成功 G燈點亮。此時液晶上也會有顯示。

3. 事件處理函數:

UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
afIncomingMSGPacket_t *MSGpkt;
afDataConfirm_t *afDataConfirm;

// Data Confirmation message fields
byte sentEP;
ZStatus_t sentStatus;
byte sentTransID;       // This should match the value sent

if ( events & SYS_EVENT_MSG )
{
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        case ZDO_CB_MSG:
          GenericApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
          break;

        case KEY_CHANGE:
          GenericApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          break;

        case AF_DATA_CONFIRM_CMD:
          // This message is received as a confirmation of a data packet sent.
          // The status is of ZStatus_t type [defined in ZComDef.h]
          // The message fields are defined in AF.h
          afDataConfirm = (afDataConfirm_t *)MSGpkt;
          sentEP = afDataConfirm->endpoint;
          sentStatus = afDataConfirm->hdr.status;
          sentTransID = afDataConfirm->transID;
          (void)sentEP;
          (void)sentTransID;

          // Action taken when confirmation is received.
          if ( sentStatus != ZSuccess )
          {
            // The data wasn’t delivered – Do something
          }
          break;

        case AF_INCOMING_MSG_CMD:
          GenericApp_MessageMSGCB( MSGpkt );
          break;

        case ZDO_STATE_CHANGE:
          GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
          if ( (GenericApp_NwkState == DEV_ZB_COORD)
              || (GenericApp_NwkState == DEV_ROUTER)
              || (GenericApp_NwkState == DEV_END_DEVICE) )
          {
            // Start sending “the” message in a regular interval.
            osal_start_timerEx( GenericApp_TaskID,
                                GENERICAPP_SEND_MSG_EVT,
                                GENERICAPP_SEND_MSG_TIMEOUT );
          }
          break;

        default:
          break;
      }

      // Release the memory
      osal_msg_deallocate( (uint8 *)MSGpkt );

      // Next
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
    }

    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
}

// Send a message out - This event is generated by a timer
// (setup in GenericApp_Init()).
if ( events & GENERICAPP_SEND_MSG_EVT )
{
    // Send “the” message
    GenericApp_SendTheMessage();

    // Setup to send message again
    osal_start_timerEx( GenericApp_TaskID,
                        GENERICAPP_SEND_MSG_EVT,
                        GENERICAPP_SEND_MSG_TIMEOUT );

    // return unprocessed events
    return (events ^ GENERICAPP_SEND_MSG_EVT);
}

// Discard unknown events
return 0;
}

3.1 網絡狀態改變

        case ZDO_STATE_CHANGE:
          GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
          if ( (GenericApp_NwkState == DEV_ZB_COORD)
              || (GenericApp_NwkState == DEV_ROUTER)
              || (GenericApp_NwkState == DEV_END_DEVICE) )
          {
            // Start sending “the” message in a regular interval.
            osal_start_timerEx( GenericApp_TaskID,
                                GENERICAPP_SEND_MSG_EVT,
                                GENERICAPP_SEND_MSG_TIMEOUT );
          }
          break;

           一旦網絡設備類型確定,就表示加入網絡成功。那麼就調用了 osal_start_timerEx 函數定期(GENERICAPP_SEND_MSG_TIMEOUT)觸發發送事件,這裏也是週期發送(GENERICAPP_SEND_MSG_EVT)

3.2 ZDO 響應事件 
case ZDO_CB_MSG: 
          GenericApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt ); 
          break; 
     
    這裏主要是對鍵盤事件操作後的一個 ZDO層的響應。
3.3 接收信息處理

case AF_INCOMING_MSG_CMD: 
          GenericApp_MessageMSGCB( MSGpkt );
          break; 
      
   調用了 GenericApp_MessageMSGCB函數。

       總的來說:例子很明顯僅僅是個發送週期信息的例子。所以 LED4 就週期性的閃爍 4 下,當然是協調器發送,路由器閃爍,路由器發送,協調器閃爍(這個是在我改過後的情況)。 這例子裏體現了綁定的概念,應該說是從基本功能上很齊全的一個例子,而且在 ZSTACK 上實現無線網絡數傳,沒有任何多餘的功能。所以該例子是一個典型的 ZSTACK 模板,也就是爲用戶提供了一個通用模板可以通過這個建立自己的應用。關於如何在這個例子上建立、修改成自己的工程和應用項目詳細見文檔: Create New Application For The CC2430DB_F8W-2005-0033_.pdf

    我們來看看沒有修改的函數演示現象




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章