Zigbee协议栈学习之串口透明传输

   1 第一个功能:协调器的组网,终端设备和路由设备发现网络以及加入网络
   2 //第一步:Z-Stack 由 main()函数开始执行,main()函数共做了 2 件事:
   3 //一是系统初始化,另外一件是开始执行轮转查询式操作系统
   4 int main( void )
   5 {
   6   .......
   7     // Initialize the operating system
   8   osal_init_system(); //第二步,操作系统初始化
   9   ......
  10   osal_start_system(); //初始化完系统任务事件后,正式开始执行操作系统
  11   ......
  12 }
  13
  14 //第二步,进入 osal_init_system()函数,执行操作系统初始化
  15 uint8 osal_init_system( void ) //初始化操作系统,其中最重要的是,初始化操作系统的任务
  16 {
  17   // Initialize the Memory Allocation System
  18   osal_mem_init();
  19   // Initialize the message queue
  20   osal_qHead = NULL;
  21   // Initialize the timers
  22   osalTimerInit();
  23   // Initialize the Power Management System
  24   osal_pwrmgr_init();
  25   // Initialize the system tasks.
  26   osalInitTasks(); //第三步,执行操作系统任务初始化函数
  27   // Setup efficient search for the first free block of heap.
  28   osal_mem_kick();
  29   return ( SUCCESS );
  30 }
  31
  32 //第三步,进入osalInitTasks()函数,执行操作系统任务初始化
  33 void osalInitTasks( void ) //第三步,初始化操作系统任务
  34 {
  35   uint8 taskID = 0;
  36   tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
  37   osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
  38   //任务优先级由高向低依次排列,高优先级对应 taskID 的值反而小
  39   macTaskInit( taskID++ ); //不需要用户考虑
  40   nwk_init( taskID++ ); //不需要用户考虑
  41   Hal_Init( taskID++ ); //硬件抽象层初始化,需要我们考虑
  42 #if defined( MT_TASK )
  43   MT_TaskInit( taskID++ );
  44 #endif
  45   APS_Init( taskID++ ); //不需要用户考虑
  46 #if defined ( ZIGBEE_FRAGMENTATION )
  47   APSF_Init( taskID++ );
  48 #endif
  49   ZDApp_Init( taskID++ ); //第四步,ZDApp层,初始化 ,执行ZDApp_init函数后,
  50                           //如果是协调器将建立网络,如果是终端设备将加入网络。
  51 #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
  52   ZDNwkMgr_Init( taskID++ );
  53 #endif
  54   SerialApp_Init( taskID ); //应用层SerialApp层初始化,需要用户考虑 在此处设置了一个按键触发事件,
  55                             //当有按键按下的时候,产生一个系统消息
  56 }
  57
  58 //第四步,进入ZDApp_init()函数,执行ZDApp层初始化 //The first step
  59 void ZDApp_Init( uint8 task_id ) //The first step,ZDApp层初始化。
  60 {
  61   // Save the task ID
  62   ZDAppTaskID = task_id;
  63   // Initialize the ZDO global device short address storage
  64   ZDAppNwkAddr.addrMode = Addr16Bit;
  65   ZDAppNwkAddr.addr.shortAddr = INVALID_NODE_ADDR;
  66   (void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.
  67   // Check for manual "Hold Auto Start"
  68   ZDAppCheckForHoldKey();
  69   // Initialize ZDO items and setup the device - type of device to create.
  70   ZDO_Init();
  71   // Register the endpoint description with the AF
  72   // This task doesn‘t have a Simple description, but we still need
  73   // to register the endpoint.
  74   afRegister( (endPointDesc_t *)&ZDApp_epDesc );
  75 #if defined( ZDO_USERDESC_RESPONSE )
  76   ZDApp_InitUserDesc();
  77 #endif // ZDO_USERDESC_RESPONSE
  78   // Start the device?
  79   if ( devState != DEV_HOLD ) //devState 初值为DEV_INIT , 所以在初始化ZDA层时,就执行该条件语句
  80   {
  81     ZDOInitDevice( 0 ); //The second step, 接着转到ZDOInitDevice()函数,执行The third step;
  82   }
  83   else
  84   {
  85     // Blink LED to indicate HOLD_START
  86     HalLedBlink ( HAL_LED_4, 0, 50, 500 );
  87   }
  88   ZDApp_RegisterCBs();
  89 } /* ZDApp_Init() */
  90
  91 //The third step,执行ZDOInitDevice()函数,执行设备初始化
  92 uint8 ZDOInitDevice( uint16 startDelay ) //The third step, ZDO层初始化设备,
  93 {
  94   .......
  95   // Trigger the network start
  96   ZDApp_NetworkInit( extendedDelay ); //网络初始化,跳到相应的函数里头,执行The fourth step .......
  97 }
  98
  99 //The fouth step,执行 ZDApp_NetWorkInit()函数
 100 void ZDApp_NetworkInit( uint16 delay ) //The fourth step,网络初始化
 101 {
 102   if ( delay )
 103   {
 104     // Wait awhile before starting the device
 105     osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );
 106     //发 送ZDO_NETWORK_INIT(网络初始化)消息到 ZDApp层,转到
 107     //ZDApp层,执行The fifth step , ZDApp_event_loop() 函数
 108   }
 109   else
 110   {
 111     osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );
 112   }
 113 }
 114
 115 //The fifth step,转到ZDApp_event_loop()函数
 116 UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
 117 {
 118   if ( events & ZDO_NETWORK_INIT ) //The fivth step,网络初始化事件处理
 119   {
 120     // Initialize apps and start the network
 121     devState = DEV_INIT;
 122     //设备逻辑类型,启动模式,信标时间,超帧长度,接着转到The sixth step,
 123     //去启动设备,接着执行The sixth step,转到ZDO_StartDevice()
 124     ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,
 125                     DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );
 126     // Return unprocessed events
 127     return (events ^ ZDO_NETWORK_INIT);
 128   }
 129 }
 130
 131 //The sixth step,执行ZDO_StartDevice()函数,启动设备
 132 void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte superframeOrder )
 133 {
 134   ......
 135   if ( ZG_BUILD_COORDINATOR_TYPE && logicalType == NODETYPE_COORDINATOR ) //当设备作为协调器时,执行这个条件语句。
 136   {
 137     if ( startMode == MODE_HARD )
 138     {
 139       devState = DEV_COORD_STARTING;
 140       //向网络层发送网络形成请求。当网络层执行 NLME_NetworkFormationRequest()建立网络后,将给予 ZDO层反馈信息。
 141       // 接着转到The seventh step,去执行ZDApp层的 ZDO_NetworkFormationConfirmCB()函数
 142       ret = NLME_NetworkFormationRequest( zgConfigPANID, zgApsUseExtendedPANID, zgDefaultChannelList,
 143                                          zgDefaultStartingScanDuration, beaconOrder,
 144                                          superframeOrder, false
 145     );
 146   }
 147   if ( ZG_BUILD_JOINING_TYPE && (logicalType == NODETYPE_ROUTER || logicalType == NODETYPE_DEVICE) )
 148           //当为终端设备或路由时
 149   {
 150     if ( (startMode == MODE_JOIN) || (startMode == MODE_REJOIN) )
 151     {
 152       devState = DEV_NWK_DISC;
 153       // zgDefaultChannelList与协调器形成网络的通道号匹配。 网络发现请求。
 154       // 继而转到ZDO_NetworkDiscoveryConfirmCB()函数
 155       ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration );
 156     }
 157   }
 158   ......
 159 }
 160
 161 //The seventh step,分两种情况,1.协调器 2.路由器或终端设备 1)协调器
 162 void ZDO_NetworkFormationConfirmCB( ZStatus_t Status ) //The seventh step,给予ZDO层网络形成反馈信息(协调器)
 163 {
 164   osal_set_event( ZDAppTaskID, ZDO_NETWORK_START ); //发送网络启动事件到ZDApp层,接着转到ZDApp_event_loop()函数
 165   ......
 166 }
 167
 168 UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
 169 {
 170   ......
 171   if ( events & ZDO_NETWORK_START ) // 网络启动事件
 172   {
 173     ZDApp_NetworkStartEvt(); //网络启动事件,接着跳转到The ninth step, 执行ZDApp_NetworkStartEvt()函数
 174     ......
 175   }
 176 }
 177
 178 void ZDApp_NetworkStartEvt( void ) //处理网络启动事件
 179 {
 180   ......
 181   osal_pwrmgr_device( PWRMGR_ALWAYS_ON ); //电源总是上电
 182   osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT ); //设置网络状态改变事件,发送到ZDApp层,转到The tenth step,去
 183   ......                                               //ZDApp_event_loop()函数,找到相对应的网络改变事件。
 184 }
 185
 186 2)路由器或终端设备 //The seventh step(终端设备), 当发现有网络存在时,网络层将给予 ZDO 层发现网络反馈信息
 187 ZStatus_t ZDO_NetworkDiscoveryConfirmCB( uint8 ResultCount, networkDesc_t *NetworkList )
 188 {
 189   .......
 190   //把网络发现这个反馈消息,发送到ZDA层,转到 ZDApp_ProcessOSALMsg(),执行
 191   ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_DISC_CNF, sizeof(ZDO_NetworkDiscoveryCfm_t), (uint8 *)&msg );
 192 }
 193
 194 void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
 195 {
 196   ...... case ZDO_NWK_DISC_CNF: // (终端设备),网络发现响应。
 197   ......
 198   //当发现有网络存在时,网络层将给予 ZDO 层发现网络反馈信息。然后由网络层发起加入网络请求,
 199   //如加入网络成功,则网络层将给予 ZDO 层加入网络反馈,执行NLME_JoinRequest()函数。然后转到
 200   //The ninth step,执行 ZDO_JoinConfirmCB()函数
 201   if ( NLME_JoinRequest( ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->extendedPANID,
 202                         BUILD_UINT16( ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdLSB, ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdMSB ),
 203                         ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->logicalChannel,
 204                         ZDO_Config_Node_Descriptor.CapabilityFlags ) != ZSuccess )
 205   {
 206     ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
 207                                 + ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
 208   }
 209   ......
 210 }
 211
 212 void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status ) //The ninth step(终端设备), 终端设备加入网络响应。
 213 {
 214   ......
 215   //将ZDO_NWK_JOIN_IND事件发送到ZDA层,执行 ZDApp_ProcessOSALMsg()函数。
 216   ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_JOIN_IND, sizeof(osal_event_hdr_t), (byte*)NULL );
 217 }
 218
 219 void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
 220 {
 221   ......
 222   case ZDO_NWK_JOIN_IND: //终端设备,加入网络反馈信息事件。
 223   if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
 224   {
 225     ZDApp_ProcessNetworkJoin(); //转到ZDApp_ProcessNetworkJoin(),执行ZDApp_ProcessNetworkJoin()函数。
 226   }
 227   break;
 228   ......
 229 }
 230
 231 在执行ZDApp_ProcessNetworkJoin()函数的时候,要分两种情况,一种是终端设备,一种是路由器:
 232 3)终端设备:
 233 void ZDApp_ProcessNetworkJoin( void ) //处理网络加入事件。
 234 {
 235   ......
 236   if ( nwkStatus == ZSuccess )
 237   {
 238     //设置 ZDO_STATE_CHANGE_EVT ,发送到ZDA层,执行 ZDApp_event_loop()函数。
 239     osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
 240   }
 241   ......
 242 }
 243 4)路由器:
 244 void ZDApp_ProcessNetworkJoin( void )
 245 {
 246   ......
 247   if ( ZSTACK_ROUTER_BUILD )
 248   {
 249     // NOTE: first two parameters are not used, see NLMEDE.h for details
 250     if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
 251     {
 252       NLME_StartRouterRequest( 0, 0, false ); //路由启动请求
 253     }
 254   }
 255   ......
 256 }
 257
 258 void ZDO_StartRouterConfirmCB( ZStatus_t Status )
 259 {
 260   nwkStatus = (byte)Status;
 261   ......
 262   osal_set_event( ZDAppTaskID, ZDO_ROUTER_START );
 263 }
 264
 265 UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
 266 {
 267   if ( events & ZDO_ROUTER_START )
 268   {
 269     if ( nwkStatus == ZSuccess )
 270     {
 271       if ( devState == DEV_END_DEVICE )
 272         devState = DEV_ROUTER; //设备状态变成路由器
 273       osal_pwrmgr_device( PWRMGR_ALWAYS_ON );
 274     }
 275     else
 276     {
 277       // remain as end device!!
 278     }
 279     osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT ); //设置ZDO状态改变事件
 280     // Return unprocessed events
 281     return (events ^ ZDO_ROUTER_START);
 282   }
 283 }
 284
 285 //The eighth step,执行ZDO状态改变事件
 286 UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
 287 {
 288   .......
 289   if ( events & ZDO_STATE_CHANGE_EVT ) //The eighth step, 网络改变事件,这个事件就是在设备加入网络成功后,
 290                                        //并在网络中的身份确定后产生的一个事件
 291   {
 292     ZDO_UpdateNwkStatus( devState ); //更新网络状态,转到The eleventh step,执行 ZDO_UpdateNwkStatus()函数。
 293     ......
 294   }
 295 }
 296
 297 //The ninth step,执行ZDO_UpdateNwkStatus()函数,完成网络状态更新
 298 void ZDO_UpdateNwkStatus(devStates_t state) //The ninth step, 更新网络状态
 299 {
 300   ......
 301   zdoSendStateChangeMsg(state, *(pItem->epDesc->task_id)); //发送状态改变消息到zdo层,这是The tenth step,转到
 302                                                            //zdoSendStateChangeMsg()函数
 303   .......
 304   ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr(); //调用NLME_GetShortAddr()函数,获得16位短地址。
 305   (void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.
 306                            //获得64位的IEEE地址。
 307 }
 308
 309 //The tenth step,执行zdoSendStateChangeMsg()函数
 310 static void zdoSendStateChangeMsg(uint8 state, uint8 taskId) //The tenth step,
 311 {
 312   osal_event_hdr_t *pMsg = (osal_event_hdr_t *)osal_msg_find(taskId, ZDO_STATE_CHANGE);
 313   if (NULL == pMsg)
 314   {
 315     if (NULL == (pMsg = (osal_event_hdr_t *)osal_msg_allocate(sizeof(osal_event_hdr_t))))
 316     {
 317       // Upon failure to notify any EndPoint of the state change, re-set the ZDO event to
 318       // try again later when more Heap may be available.
 319       osal_set_event(ZDAppTaskID, ZDO_STATE_CHANGE_EVT); //如果ZDO状态没有任何改变,再一次,跳到
 320                                                          //ZDO_STATE_CHANGE_EVT事件处理函数。
 321     }
 322     else
 323     {
 324       pMsg->event = ZDO_STATE_CHANGE; //如果ZDO状态改变了 了,把ZDO_STATE_CHANGE这个消息保存到pMsg
 325       pMsg->status = state;
 326       (void)osal_msg_send(taskId, (uint8 *)pMsg); //转到MT_TASK.C,去执行The eleven step, MT_ProcessIncomingCommand()函数
 327     }
 328   }
 329   ......
 330 }
 331
 332 //The eleventh step,去执行MT_ProcessIncomingCommand()函数
 333 void MT_ProcessIncomingCommand( mtOSALSerialData_t *msg )
 334 {
 335   ......
 336   case ZDO_STATE_CHANGE: //The thirteenth step, 接着跳到MT_ZdoStateChangeCB()函数。
 337                          //自此,协调器组网形成(终端设备成功加入网络)
 338   MT_ZdoStateChangeCB((osal_event_hdr_t *)msg);
 339   break;
 340   ......
 341 }
 342
 343 //第五步,
 344 //初始化玩系统任务事件后,正是开始执行操作系统,此时操作系统不断的检测有没有任务事件发生,
 345 //一旦检测到有事件发生,就转 到相应的处理函数,进行处理。
 346 void osal_start_system( void ) //第五步,正式执行操作系统
 347 {
 348 #if !defined ( ZBIT ) && !defined ( UBIT )
 349   for(;;) // Forever Loop //死循环
 350 #endif
 351   {
 352     uint8 idx = 0;
 353     osalTimeUpdate();
 354     Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer().
 355     do
 356     {
 357       if (tasksEvents[idx]) // Task is highest priority that is ready.
 358       {
 359         break; // 得到待处理的最高优先级任务索引号idx
 360       }
 361     } while (++idx < tasksCnt);
 362     if (idx < tasksCnt)
 363     {
 364       uint16 events;
 365       halIntState_t intState;
 366       HAL_ENTER_CRITICAL_SECTION(intState); //进入临界区
 367       events = tasksEvents[idx]; //提取需要处理的任务中的事件
 368       tasksEvents[idx] = 0; // Clear the Events for this task. // 清除本次任务的事件
 369       HAL_EXIT_CRITICAL_SECTION(intState); //退出临界区
 370       events = (tasksArr[idx])( idx, events ); //通过指针调用任务处理函数 , 紧接着跳到相应的函数去处理,此为第五步
 371       HAL_ENTER_CRITICAL_SECTION(intState); //进入临界区
 372       tasksEvents[idx] |= events; // Add back unprocessed events to the current task. // 保存未处理的事件
 373       HAL_EXIT_CRITICAL_SECTION(intState); //退出临界区
 374     }
 375 #if defined( POWER_SAVING )
 376     else // Complete pass through all task events with no activity?
 377     {
 378       osal_pwrmgr_powerconserve(); // Put the processor/system into sleep
 379     }
 380 #endif
 381   }
 382 }
 383
 384 第二个功能:设备间的绑定
 385 /*当我们按下sw2,即JoyStick控杆的右键时,节点发出终端设备绑定请求,
 386 因为我们在SerialApp层,注册过了键盘响应事件,所以,当我们按 下右键时,
 387 我们会在SerialApp_ProcessEvent()函数里找到对应的键盘相应事件*/
 388 UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events )
 389 {
 390   ......
 391   case KEY_CHANGE: //键盘触发事件
 392     SerialApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
 393     //接着跳到相应的按键处理函数去执行
 394   break;
 395   .......
 396 }
 397 }
 398
 399 ZDO终端设备绑定请求:设备能告诉协调器他们想建立绑定表格报告。该协调器将使协调并在
 400 这两个设备上创建绑定表格条目。在这里是以SerialApp例子为例。
 401 void SerialApp_HandleKeys( uint8 shift, uint8 keys )
 402 {
 403   .......
 404     if ( keys & HAL_KEY_SW_2 ) // Joystick right
 405     {
 406       HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
 407       //终端设备绑定请求
 408       // Initiate an End Device Bind Request for the mandatory endpoint
 409       dstAddr.addrMode = Addr16Bit;
 410       dstAddr.addr.shortAddr = 0x0000; // Coordinator 地址
 411       ZDP_EndDeviceBindReq( &dstAddr, NLME_GetShortAddr(), //终端设备绑定请求
 412                            SerialApp_epDesc.endPoint,
 413                            SERIALAPP_PROFID,
 414                            SERIALAPP_MAX_CLUSTERS,
 415                            (cId_t *)SerialApp_ClusterList,
 416                            SERIALAPP_MAX_CLUSTERS,
 417                            (cId_t *)SerialApp_ClusterList,
 418                            FALSE );
 419     }
 420   ......
 421     if ( keys & HAL_KEY_SW_4 )
 422     {
 423       HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
 424       // Initiate a Match Description Request (Service Discovery)
 425       dstAddr.addrMode = AddrBroadcast; //广播地址
 426       dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
 427       ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR, //描述符匹配请求这也是两不同匹配方式,使用的按键不同
 428                        SERIALAPP_PROFID,
 429                        SERIALAPP_MAX_CLUSTERS,
 430                        (cId_t *)SerialApp_ClusterList,
 431                        SERIALAPP_MAX_CLUSTERS,
 432                        (cId_t *)SerialApp_ClusterList,
 433                        FALSE );
 434     }
 435 }
 436 }
 437
 438 说明:从上面可以看到,SW2是发送终端设备绑定请求方式,SW4是发送描述符匹配请求方式。
 439 如果按下SW2的话,使用终端设备绑定请求方式,这里是要通过终端告诉协调器他们想要建立
 440 绑定表格,协调器将协调这两个请求的设备,在两个设备上建立绑定表格条目。
 441 (1)终端设备向协调器发送终端设备绑定请求
 442 调用ZDP_EndDeviceBindReq()函数发送绑定请求。
 443 ZDP_EndDeviceBindReq( &dstAddr, //目的地址设为0x0000;
 444                      NLME_GetShortAddr(),
 445                      SerialApp_epDesc.endPoint, //EP号
 446                      SERIALAPP_PROFID,//Profile ID
 447                      SERIALAPP_MAX_CLUSTERS, //输入簇的数目
 448                      (cId_t *)SerialApp_ClusterList, //输入簇列表
 449                      SERIALAPP_MAX_CLUSTERS, //输出簇数目
 450                      (cId_t *)SerialApp_ClusterList,//输出簇列表
 451                      FALSE );
 452 该函数实际调用无线发送函数将绑定请求发送给协调器节点:默认clusterID为End_Device_Bind_req,最后通过AF_DataRequest()发送出去.
 453 fillAndSend( &ZDP_TransID, dstAddr, End_Device_Bind_req, len );
 454 最后通过AF_DataRequest()发送出去,这里的&afAddr,是目的地址; &ZDApp_epDesc ,是端口号; clusterID,是簇号; len+1,是数据的长度;
 455 //ZDP_TmpBuf-1,是数据的内容; transSeq,是数据的顺序号; ZDP_TxOptions,是发射的一个选项 ; AF_DEFAULT_RADIUS,是一个默认的半径(跳数)。
 456 AF_DataRequest( &afAddr, &ZDApp_epDesc, clusterID,
 457                (uint16)(len+1), (uint8*)(ZDP_TmpBuf-1),
 458                transSeq, ZDP_TxOptions, AF_DEFAULT_RADIUS );
 459
 460 (2) 协调器收到终端设备绑定请求End_Device_Bind_req
 461 这个信息会传送到ZDO层,在ZDO层的事件处理函数中,调用ZDApp_ProcessOSALMsg( (osal_event_hdr_t *)msg_ptr );
 462 UINT16 ZDApp_event_loop( byte task_id, UINT16 events )
 463 {
 464   uint8 *msg_ptr;
 465   if ( events & SYS_EVENT_MSG )
 466   {
 467     while ( (msg_ptr = osal_msg_receive( ZDAppTaskID )) )
 468     {
 469       ZDApp_ProcessOSALMsg( (osal_event_hdr_t *)msg_ptr );
 470       // Release the memory
 471       osal_msg_deallocate( msg_ptr );
 472     }
 473     // Return unprocessed events
 474     return (events ^ SYS_EVENT_MSG);
 475     .....................
 476   }
 477 }
 478
 479 void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
 480 {
 481   // Data Confirmation message fields
 482   byte sentEP; // This should always be 0
 483   byte sentStatus;
 484   afDataConfirm_t *afDataConfirm;
 485   switch ( msgPtr->event )
 486   {
 487     // Incoming ZDO Message
 488     case AF_INCOMING_MSG_CMD:
 489       ZDP_IncomingData( (afIncomingMSGPacket_t *)msgPtr );
 490     break;
 491     ................................
 492   }
 493 }
 494
 495 在ZDP_IncomingData( (afIncomingMSGPacket_t *)msgPtr );函数中
 496 void ZDP_IncomingData( afIncomingMSGPacket_t *pData )
 497 {
 498   uint8 x = 0;
 499   uint8 handled;
 500   zdoIncomingMsg_t inMsg; //解析clusterID这个消息
 501   inMsg.srcAddr.addrMode = Addr16Bit;
 502   inMsg.srcAddr.addr.shortAddr = pData->srcAddr.addr.shortAddr;
 503   inMsg.wasBroadcast = pData->wasBroadcast;
 504   inMsg.clusterID = pData->clusterId; //这个clusterID,在这里指的是,终端设备发送过来的End_Device_Bind_req这个消息
 505   inMsg.SecurityUse = pData->SecurityUse;
 506   inMsg.asduLen = pData->cmd.DataLength-1;
 507   inMsg.asdu = pData->cmd.Data+1;
 508   inMsg.TransSeq = pData->cmd.Data[0];
 509   handled = ZDO_SendMsgCBs( &inMsg );
 510 #if defined( MT_ZDO_FUNC )
 511   MT_ZdoRsp( &inMsg );
 512 #endif
 513   while ( zdpMsgProcs[x].clusterID != 0xFFFF )
 514   {
 515     if ( zdpMsgProcs[x].clusterID == inMsg.clusterID ) //在zdpMsgProcs[]中,查找,看看有没有跟End_Device_Bind_req相匹配的描述符。
 516     {
 517       zdpMsgProcs[x].pFn( &inMsg );
 518       return;
 519     }
 520     x++;
 521   }
 522   // Handle unhandled messages
 523   if ( !handled )
 524     ZDApp_InMsgCB( &inMsg );
 525 }
 526
 527 因为ZDO信息处理表zdpMsgProcs[ ]没有对应的End_Device_Bind_req簇,因此没有调用ZDO信息处理表中的处理函数,
 528 但是前面的ZDO_SendMsgCBs()会把这 个终端设备绑定请求发送到登记过这个ZDO信息的任务中去。那这个登记注册的程序在哪里呢?
 529 对于协调器来说,由于在void ZDApp_Init( byte task_id )函数中调用了ZDApp_RegisterCBs();面的函数。进行注册了终端绑定请求信息。
 530 void ZDApp_RegisterCBs( void )
 531 {
 532 #if defined ( ZDO_IEEEADDR_REQUEST ) || defined ( REFLECTOR )
 533   ZDO_RegisterForZDOMsg( ZDAppTaskID, IEEE_addr_rsp );
 534 #endif
 535 #if defined ( ZDO_NWKADDR_REQUEST ) || defined ( REFLECTOR )
 536   ZDO_RegisterForZDOMsg( ZDAppTaskID, NWK_addr_rsp );
 537 #endif
 538 #if defined ( ZDO_COORDINATOR )
 539   ZDO_RegisterForZDOMsg( ZDAppTaskID, Bind_rsp );
 540   ZDO_RegisterForZDOMsg( ZDAppTaskID, Unbind_rsp );
 541   ZDO_RegisterForZDOMsg( ZDAppTaskID, End_Device_Bind_req );
 542 #endif
 543 #if defined ( REFLECTOR )
 544   ZDO_RegisterForZDOMsg( ZDAppTaskID, Bind_req );
 545   ZDO_RegisterForZDOMsg( ZDAppTaskID, Unbind_req );
 546 #endif
 547 }
 548
 549 因此,协调器节点的 ZDApp 接收到外界输入的数据后,由于注册了 ZDO 反馈消息,即ZDO_CB_MSG,
 550 ZDApp 层任务事件处理函数将进行处理:也就是调用下面的程序。
 551 UINT16 ZDApp_event_loop( byte task_id, UINT16 events )
 552 {
 553   uint8 *msg_ptr;
 554   if ( events & SYS_EVENT_MSG )
 555   {
 556     while ( (msg_ptr = osal_msg_receive( ZDAppTaskID )) )
 557     {
 558       ZDApp_ProcessOSALMsg( (osal_event_hdr_t *)msg_ptr );
 559       // Release the memory
 560       osal_msg_deallocate( msg_ptr );
 561     }
 562     // Return unprocessed events
 563     return (events ^ SYS_EVENT_MSG);
 564     ..............................
 565   }
 566 }
 567
 568 在这里调用函数ZDApp_ProcessOSALMsg( (osal_event_hdr_t *)msg_ptr );在这个函数中我们可以看到对ZDO_CB_MSG事件的处理
 569 void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
 570 {
 571   // Data Confirmation message fields
 572   byte sentEP; // This should always be 0
 573   byte sentStatus;
 574   afDataConfirm_t *afDataConfirm;
 575   switch ( msgPtr->event )
 576   {
 577     // Incoming ZDO Message
 578   case AF_INCOMING_MSG_CMD:
 579     ZDP_IncomingData( (afIncomingMSGPacket_t *)msgPtr );
 580     break;
 581   case ZDO_CB_MSG:
 582     ZDApp_ProcessMsgCBs( (zdoIncomingMsg_t *)msgPtr );
 583     break;
 584     ....................................
 585   }
 586 }
 587
 588 调用ZDApp_ProcessMsgCBs()函数。在这个函数中根据ClusterID(这里是 End_Device_Bind_req)选择相对应的匹配描述符处理函数,
 589 void ZDApp_ProcessMsgCBs( zdoIncomingMsg_t *inMsg )
 590 {
 591   .......
 592 case End_Device_Bind_req:
 593   {
 594     ZDEndDeviceBind_t bindReq;
 595     ZDO_ParseEndDeviceBindReq( inMsg, &bindReq ); //解析绑定请求信息
 596     ZDO_MatchEndDeviceBind( &bindReq ); //然后向发送绑定请求的节点发送绑定响应消息:
 597     // Freeing the cluster lists - if allocated.
 598     if ( bindReq.numInClusters )
 599       osal_mem_free( bindReq.inClusters );
 600     if ( bindReq.numOutClusters )
 601       osal_mem_free( bindReq.outClusters );
 602   }
 603   break;
 604 #endif
 605 }
 606 }
 607
 608 下面是ZDO_MatchEndDeviceBind()函数的源代码
 609 void ZDO_MatchEndDeviceBind( ZDEndDeviceBind_t *bindReq )
 610 {
 611   zAddrType_t dstAddr;
 612   uint8 sendRsp = FALSE;
 613   uint8 status;
 614   // Is this the first request? 接收到的是第一个绑定请求
 615   if ( matchED == NULL )
 616   {
 617     // Create match info structure 创建匹配信息结构体
 618     matchED = (ZDMatchEndDeviceBind_t *)osal_mem_alloc( sizeof ( ZDMatchEndDeviceBind_t ) ); //分配空间
 619     if ( matchED )
 620     {
 621       // Clear the structure 先进行清除操作
 622       osal_memset( (uint8 *)matchED, 0, sizeof ( ZDMatchEndDeviceBind_t ) );
 623       // Copy the first request‘s information 复制第一个请求信息
 624       if ( !ZDO_CopyMatchInfo( &(matchED->ed1), bindReq ) ) //复制不成功后
 625       {
 626         status = ZDP_NO_ENTRY;
 627         sendRsp = TRUE;
 628       }
 629     }
 630     else //分配空间不成功
 631     {
 632       status = ZDP_NO_ENTRY;
 633       sendRsp = TRUE;
 634     }
 635     if ( !sendRsp ) //分配空间成功 ,复制数据结构成功
 636     {
 637       // Set into the correct state 设置正确的设备状态
 638       matchED->state = ZDMATCH_WAIT_REQ;
 639       // Setup the timeout 设置计时时间APS_SetEndDeviceBindTimeout(AIB_MaxBindingTime,
 640       ZDO_EndDeviceBindMatchTimeoutCB );
 641     }
 642   }
 643   else //接收到的不是第一个绑定请求
 644   {
 645     matchED->state = ZDMATCH_SENDING_BINDS; //状态为绑定中
 646     // Copy the 2nd request‘s information 拷贝第2个请求信息结构
 647     if ( !ZDO_CopyMatchInfo( &(matchED->ed2), bindReq ) ) //拷贝不成功
 648     {
 649       status = ZDP_NO_ENTRY;
 650       sendRsp = TRUE;
 651     }
 652     // Make a source match for ed1
 653     //对ed1的输出簇ID与ed2的输入簇ID进行比较,如果有符合的则会返回,相匹配的簇的数目
 654     matchED->ed1numMatched = ZDO_CompareClusterLists(
 655                                                      matchED->ed1.numOutClusters, matchED->ed1.outClusters,
 656                                                      matchED->ed2.numInClusters, matchED->ed2.inClusters, ZDOBuildBuf );
 657     if ( matchED->ed1numMatched ) //如果有返回ed1相匹配的簇
 658     {
 659       // Save the match list 申请空间保存相匹配的簇列表
 660       matchED->ed1Matched= osal_mem_alloc( (short)(matchED->ed1numMatched * sizeof ( uint16 )) );
 661       if ( matchED->ed1Matched ) //分配成功
 662       {
 663         //保存相匹配的簇列表
 664         osal_memcpy(matchED->ed1Matched,ZDOBuildBuf, (matchED->ed1numMatched * sizeof ( uint16 )) );
 665       }
 666       else //内存空间分配不成功
 667       {
 668         // Allocation error, stop
 669         status = ZDP_NO_ENTRY;
 670         sendRsp = TRUE;
 671       }
 672     }
 673     // Make a source match for ed2 以ed2为源
 674     //对ed2的终端匹配请求和ed1的簇列表相比较,返回相相匹配的簇的数目
 675     matchED->ed2numMatched = ZDO_CompareClusterLists(
 676                                                      matchED->ed2.numOutClusters, matchED->ed2.outClusters,
 677                                                      matchED->ed1.numInClusters, matchED->ed1.inClusters, ZDOBuildBuf );
 678     if ( matchED->ed2numMatched ) //如果匹配成功
 679     {
 680       // Save the match list 保存匹配的簇列表
 681       matchED->ed2Matched = osal_mem_alloc( (short)(matchED->ed2numMatched * sizeof ( uint16 )) );
 682       if ( matchED->ed2Matched )
 683       {
 684         osal_memcpy( matchED->ed2Matched, ZDOBuildBuf, (matchED->ed2numMatched * sizeof ( uint16 )) );
 685       }
 686       else
 687       {
 688         // Allocation error, stop
 689         status = ZDP_NO_ENTRY;
 690         sendRsp = TRUE;
 691       }
 692     }
 693     //如果两个相请求的终端设备,有相匹配的簇,并且保存成功
 694     if ( (sendRsp == FALSE) && (matchED->ed1numMatched || matchED->ed2numMatched) )
 695     {
 696       // Do the first unbind/bind state 发送响应信息给两个设备
 697       ZDMatchSendState( ZDMATCH_REASON_START, ZDP_SUCCESS, 0 );
 698     }
 699     else
 700     {
 701       status = ZDP_NO_MATCH;
 702       sendRsp = TRUE;
 703     }
 704   }
 705   if ( sendRsp ) //如果没有相匹配的或匹配不成功
 706   {
 707     // send response to this requester 发送匹配请求响应
 708     dstAddr.addrMode = Addr16Bit; //设置目的地址是16位的短地址
 709     dstAddr.addr.shortAddr = bindReq->srcAddr;
 710     //发送绑定终端响应函数status = ZDP_NO_MATCH;
 711     ZDP_EndDeviceBindRsp( bindReq->TransSeq, &dstAddr, status, bindReq->SecurityUse );
 712     if ( matchED->state == ZDMATCH_SENDING_BINDS )
 713     {
 714       // send response to first requester
 715       dstAddr.addrMode = Addr16Bit;
 716       dstAddr.addr.shortAddr = matchED->ed1.srcAddr;
 717       ZDP_EndDeviceBindRsp( matchED->ed1.TransSeq, &dstAddr, status, matchED->ed1.SecurityUse );
 718     }
 719     // Process ended - release memory used
 720     ZDO_RemoveMatchMemory();
 721   }
 722 }
 723
 724 ZDO_MatchEndDeviceBind() 函数,如果协调器接收到接收到第一个绑定请求,则分配内存空间进行保存并计时,
 725 如果不是第一个绑定请求,则分别以第一个和第二个绑定请求为源绑定,进行比 较匹配,如果比较匹配成功
 726 则发送匹配成功的信息End_Device_Bind_rsp给两个请求终端。因为在ZDMatchSendState()函数 中也是调用了
 727 ZDP_EndDeviceBindRsp()函数,对匹配请求响应进行了发送。如果匹配不成功则发送匹配失败的信息给两个终端。
 728 uint8 ZDMatchSendState( uint8 reason, uint8 status, uint8 TransSeq )
 729 {
 730   ..............................
 731   else
 732   {
 733     // Send the response messages to requesting devices
 734     // send response to first requester 发送响应信息给第一个请求终端,
 735     dstAddr.addr.shortAddr = matchED->ed1.srcAddr;
 736     ZDP_EndDeviceBindRsp( matchED->ed1.TransSeq, &dstAddr, rspStatus, matchED->ed1.SecurityUse );
 737     // send response to second requester 发送响应信息给第二请求终端
 738     if ( matchED->state == ZDMATCH_SENDING_BINDS )
 739     {
 740       dstAddr.addr.shortAddr = matchED->ed2.srcAddr;
 741       ZDP_EndDeviceBindRsp( matchED->ed2.TransSeq, &dstAddr, rspStatus, matchED->ed2.SecurityUse );
 742     }
 743     // Process ended - release memory used
 744     ZDO_RemoveMatchMemory();
 745   }
 746   return ( TRUE );
 747 }
 748
 749 (3)终端结点的响应
 750 由于终端节点在 SerialApp.c 中层注册过 End_Device_Bind_rsp 消息,因此当接收到协调器节点发来的
 751 绑定响应消息将交由 SerialApp 任务事件处理函数处理:
 752 UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events )
 753 {
 754   if ( events & SYS_EVENT_MSG )
 755   {
 756     afIncomingMSGPacket_t *MSGpkt;
 757     while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(SerialApp_TaskID )) )
 758     {
 759       switch ( MSGpkt->hdr.event )
 760       {
 761         case ZDO_CB_MSG:
 762           SerialApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
 763         break;
 764         ...................................
 765       }
 766     }
 767   }
 768 }
 769
 770 然后,调用 SerialApp_ProcessZDOMsgs()函数。进行事件处理。
 771 static void SerialApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )
 772 {
 773   switch ( inMsg->clusterID )
 774   {
 775   case End_Device_Bind_rsp:
 776     if ( ZDO_ParseBindRsp( inMsg ) == ZSuccess )
 777     {
 778       // Light LED
 779       HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
 780     }
 781 #if defined(BLINK_LEDS)
 782     else
 783     {
 784       // Flash LED to show failure
 785       HalLedSet ( HAL_LED_4, HAL_LED_MODE_FLASH );
 786     }
 787 #endif
 788     break;
 789     ................................
 790   }
 791 }
 792
 793 第三个功能:实现两个节点间的串口通信 “串口终端1”的数据,如何被“节点 1”所接收,并且发送出去的?
 794 串口数据是由哪层来负责的呢?--HAL。 。 。恩,猜对了。但这个肯定不是靠猜的,其中的过程就不讲了。
 795 让我们从主循环(osal_start_system)的Hal_ProcessPoll函数找下去(用source insight的同学可以用 ctrl +)Hal_ProcessPoll ==> HalUARTPoll ==> HalUARTPollDMA
 796 这 个 HalUARTPollDMA 函数里最后有这样一句话:dmaCfg.uartCB(HAL_UART_DMA-1, evt); 对dmaCfg.uartCB 这个函数进行了调用,
 797 ctrl / 搜索这个 dmaCfg.uartCB,发现 SerialApp_Init 函数有两句话:
 798 uartConfig.callBackFunc = SerialApp_CallBack;
 799 HalUARTOpen (SERIAL_APP_PORT, &uartConfig);
 800 此 处将 dmaCfg.uartCB 这个函数注册成为 SerialApp_CallBack, 也就是说 SerialApp_CallBack函数每次循环中被调用一次,
 801 对串口的内容进行查询,如果 DMA 中接收到了数据,则调用HalUARTRead,将 DMA 数据读至数据 buffer 并通过 AF_DataRequest 函数发送出去,
 802 注意:出去的信息的 CLUSTERID(信息簇ID)号为 SERIALAPP_CLUSTERID1。
 803 总结一下这个过程: 串口数据==>DMA接收==>主循环中通过SerialApp_CallBack 查询==>从 DMA获取并发送到空中。 具体流程如下:
 804 void SerialApp_Init( uint8 task_id )
 805 { ......
 806   uartConfig.configured = TRUE; // 2x30 don‘t care - see uart driver.
 807   uartConfig.baudRate = SERIAL_APP_BAUD;
 808   uartConfig.flowControl = TRUE;
 809   uartConfig.flowControlThreshold = SERIAL_APP_THRESH; // 2x30 don‘t care - see uart driver.
 810   uartConfig.rx.maxBufSize = SERIAL_APP_RX_SZ; // 2x30 don‘t care - see uart driver.
 811   uartConfig.tx.maxBufSize = SERIAL_APP_TX_SZ; // 2x30 don‘t care - see uart driver.
 812   uartConfig.idleTimeout = SERIAL_APP_IDLE; // 2x30 don‘t care - see uart driver.
 813   uartConfig.intEnable = TRUE; // 2x30 don‘t care - see uart driver.
 814   uartConfig.callBackFunc = SerialApp_CallBack; //调用SerialApp_CallBack函数,对串口内容进行查询
 815   HalUARTOpen (SERIAL_APP_PORT, &uartConfig);
 816   ......
 817 }
 818
 819 static void SerialApp_CallBack(uint8 port, uint8 event)
 820 {
 821   (void)port;
 822   //如果 DMA 中接收到了数据
 823   if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)) &&(SerialApp_TxLen < SERIAL_APP_TX_MAX))
 824 #if SERIAL_APP_LOOPBACK
 825     !SerialApp_TxLen)
 826 #else
 827
 828 #endif
 829 {
 830   SerialApp_Send(); //调用串口发送函数,将从串口接受到的数据,发送出去
 831 }
 832 }
 833
 834 static void SerialApp_Send(void)
 835 {
 836 #if SERIAL_APP_LOOPBACK //初始化时,SERIAL_APP_LOOPBACK=false ,所以不执行if这个预编译,转到else去执行
 837   if (SerialApp_TxLen < SERIAL_APP_TX_MAX)
 838   {
 839     SerialApp_TxLen += HalUARTRead(SERIAL_APP_PORT, SerialApp_TxBuf+SerialApp_TxLen+1,
 840                                    SERIAL_APP_TX_MAX-SerialApp_TxLen);
 841   }
 842   if (SerialApp_TxLen)
 843   {
 844     (void)SerialApp_TxAddr;
 845     if (HalUARTWrite(SERIAL_APP_PORT, SerialApp_TxBuf+1, SerialApp_TxLen))
 846     {
 847       SerialApp_TxLen = 0;
 848     }
 849     else
 850     {
 851       osal_set_event(SerialApp_TaskID, SERIALAPP_SEND_EVT);
 852     }
 853   }
 854 #else
 855   if (!SerialApp_TxLen &&
 856       (SerialApp_TxLen = HalUARTRead(SERIAL_APP_PORT, SerialApp_TxBuf+1, SERIAL_APP_TX_MAX)))
 857   {
 858     // Pre-pend sequence number to the Tx message.
 859     SerialApp_TxBuf[0] = ++SerialApp_TxSeq;
 860   }
 861   if (SerialApp_TxLen)
 862   {
 863     if (afStatus_SUCCESS != AF_DataRequest(&SerialApp_TxAddr, //通过AF_DataRequest()函数,将数据从空中发送出去
 864                                            (endPointDesc_t *)&SerialApp_epDesc,
 865                                            SERIALAPP_CLUSTERID1,
 866                                            SerialApp_TxLen+1, SerialApp_TxBuf,
 867                                            &SerialApp_MsgID, 0, AF_DEFAULT_RADIUS))
 868     {
 869       osal_set_event(SerialApp_TaskID, SERIALAPP_SEND_EVT); //如果数据没有发送成功,重新发送
 870     }
 871   }
 872 #endif
 873 }
 874
 875 UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events )
 876 {
 877   if ( events & SERIALAPP_SEND_EVT ) //当数据没有发送成功时
 878   {
 879     SerialApp_Send();
 880     return ( events ^ SERIALAPP_SEND_EVT );
 881   }
 882 }
 883
 884 节点2 在收到空中的信号后,如何传递给与其相连的串口终端?
 885 节点 2 从空中捕获到信号后, 在应用层上首先收到信息的就是 SerialApp_ProcessEvent 这个函数了,
 886 它收到一个 AF_INCOMING_MSG_CMD 的事件,并通知 SerialApp_ProcessMSGCmd,执行以下代码 :
 887 UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events ) //当有事件传递到应用层的时候,执行此处
 888 {
 889   ...... while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SerialApp_TaskID )) )
 890   {
 891     switch ( MSGpkt->hdr.event )
 892     {
 893       ......
 894       case AF_INCOMING_MSG_CMD: //在这个实验中,使用串口通讯时,触发的事件,从空中捕获到信号。
 895         SerialApp_ProcessMSGCmd( MSGpkt ); //处理这个消息
 896       break;
 897       ......
 898     }
 899   }
 900 }
 901
 902 void SerialApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt ) //对从空中捕获到的信号进行处理
 903 {
 904   uint8 stat;
 905   uint8 seqnb;
 906   uint8 delay;
 907   switch ( pkt->clusterId )
 908   {
 909     // A message with a serial data block to be transmitted on the serial port.
 910     case SERIALAPP_CLUSTERID1: //节点一发送过来的信息的 CLUSTERID(信息簇ID)号为 SERIALAPP_CLUSTERID1
 911     // Store the address for sending and retrying.
 912     osal_memcpy(&SerialApp_RxAddr, &(pkt->srcAddr), sizeof( afAddrType_t ));
 913     seqnb = pkt->cmd.Data[0];
 914     // Keep message if not a repeat packet
 915     if ( (seqnb > SerialApp_RxSeq) || // Normal
 916         ((seqnb < 0x80 ) && ( SerialApp_RxSeq > 0x80)) ) // Wrap-around
 917     {
 918       // Transmit the data on the serial port.
 919       if ( HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) ) ) //通过串口发送数据到PC机
 920       {
 921         // Save for next incoming message
 922         SerialApp_RxSeq = seqnb;
 923         stat = OTA_SUCCESS;
 924       }
 925       else
 926       {
 927         stat = OTA_SER_BUSY;
 928       }
 929     }
 930     else
 931     {
 932       stat = OTA_DUP_MSG;
 933     }
 934     // Select approproiate OTA flow-control delay.
 935     delay = (stat == OTA_SER_BUSY) ? SERIALAPP_NAK_DELAY : SERIALAPP_ACK_DELAY;
 936     // Build & send OTA response message.
 937     SerialApp_RspBuf[0] = stat;
 938     SerialApp_RspBuf[1] = seqnb;
 939     SerialApp_RspBuf[2] = LO_UINT16( delay );
 940     SerialApp_RspBuf[3] = HI_UINT16( delay );
 941     osal_set_event( SerialApp_TaskID, SERIALAPP_RESP_EVT ); //受到数据后,向节点1发送一个响应事件,跳到SerialApp_ProcessEvent()
 942     osal_stop_timerEx(SerialApp_TaskID, SERIALAPP_RESP_EVT);
 943     break;
 944     ......
 945   }
 946 }
 947
 948 UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events )
 949 {
 950   ......
 951     if ( events & SERIALAPP_RESP_EVT ) //串口响应事件,表示成功接受来自节点1的数据,
 952     {
 953       SerialApp_Resp(); //向节点1发送 成功接受的response
 954       return ( events ^ SERIALAPP_RESP_EVT );
 955     }
 956   ......
 957 }
 958
 959 static void SerialApp_Resp(void)
 960 {
 961   if (afStatus_SUCCESS != AF_DataRequest(&SerialApp_RxAddr, //通过AF_DataRequest函数,讲接收成功响应从空中发送出去
 962                                          (endPointDesc_t *)&SerialApp_epDesc,
 963                                          SERIALAPP_CLUSTERID2,
 964                                          SERIAL_APP_RSP_CNT, SerialApp_RspBuf,
 965                                          &SerialApp_MsgID, 0, AF_DEFAULT_RADIUS))
 966   {
 967     osal_set_event(SerialApp_TaskID, SERIALAPP_RESP_EVT); //如果发送失败,重新发送
 968   }
 969 }
 970
 971 节点1,接收到来自节点2的response。
 972 UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events )
 973 {
 974   ......
 975     while ( (MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SerialApp_TaskID )) )
 976     {
 977       switch ( MSGpkt->hdr.event )
 978       {
 979         ......
 980       case AF_INCOMING_MSG_CMD: //在这个实验中,使用串口通讯时,触发的事件,从空中捕获到信号。
 981         SerialApp_ProcessMSGCmd( MSGpkt ); //处理这个消息
 982         break;
 983         ......
 984       }
 985     }
 986 }
 987
 988 SERIALAPP_CLUSTERID2代表接收到发送成功的response,取消自动重发,如果不,自动重发。
 989 void SerialApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt )
 990 {
 991   ......
 992   // A response to a received serial data block.
 993   case SERIALAPP_CLUSTERID2: //SerialWsn_CLUSTERID2代表接收到发送成功的response
 994     if ((pkt->cmd.Data[1] == SerialApp_TxSeq) &&
 995         ((pkt->cmd.Data[0] == OTA_SUCCESS) || (pkt->cmd.Data[0] == OTA_DUP_MSG)))
 996     {
 997       SerialApp_TxLen = 0;
 998       osal_stop_timerEx(SerialApp_TaskID, SERIALAPP_SEND_EVT); //当收到发送成功的response,停止自动从发
 999    }
1000    else
1001    {
1002      // Re-start timeout according to delay sent from other device.
1003      delay = BUILD_UINT16( pkt->cmd.Data[2], pkt->cmd.Data[3] );
1004      osal_start_timerEx( SerialApp_TaskID, SERIALAPP_SEND_EVT, delay ); //没有收到成功的response,自动重发
1005    }
1006   break;
1007     default:
1008   break;
1009 }

原文地址:https://www.cnblogs.com/Ya-nana/p/10311758.html

时间: 2024-10-10 07:35:56

Zigbee协议栈学习之串口透明传输的相关文章

cc2530-----串口透明传输分析

Zigbee协议栈学习之串口透明传输实验(SerialApp)流程分析   第一个功能:协调器的组网,终端设备和路由设备发现网络以及加入网络 //第一步:Z-Stack 由 main()函数开始执行,main()函数共做了 2 件事:一是系统初始化,另外一件是开始执行轮转查询式操作系统 int main( void ) { ....... // Initialize the operating system osal_init_system(); //第二步,操作系统初始化 ...... osa

zigbee协议栈应用与组网(二):串口基础实验

资料里的实验都是已经做好了的,所以我下载了一个全新的ZStack-2.5.1a来做实验,按照步骤做,发现了很多问题. 第一步,配置串口. MT_UART.c中的MT_UartInit(); baudRate设置为115200(默认是38400),flowControl设置为FALSE. 第二步,预定义宏. MT_UartInit()后还有一小部分 1.2行根据预先定义的 ZTOOL或者ZAPP选择不同的数据处理函数. 后面的P1和P2则是串 口0和串口1.我们用ZTOOL,串口0.我们可以在op

(zigbee学习总结一)zigbee协议栈中OSAL运行机理

在基于zigbee协议栈的应用程序开发过程中,用户只需要实现应用层的开发即可,zigbee应用程序框架中包含了最多240个应用程序对象,每个应用程序对象运行在不同的端口上,因此端口的最作用是区分不同的应用程序对象,可以把一个应用程序对象看成为一个任务.因此,需要一个机制来实现任务的切换.同步和互斥,这就是OSAL产生的根源. OSAL用一句话来说就是指支持多任务运行的系统资源分配机制.OSAL中有三个参数非常重要,即:tasksCnt.tasksEvent[]和tasksArr[]. (1)ta

[ZigBee] 16、Zigbee协议栈应用(二)——基于OSAL的无线控制LED闪烁分析(下)

说在前面:上一篇介绍了无线LED闪烁实现的OSAL部分,本篇介绍如何实现无线数据收发及数据处理: 上一篇是用SI跟着流程查看源码,我个人认为以架构的思维去了解代码能让人更清晰 ::ZMain.c程序入口文件 这里chipcon_cstartup.s51是汇编的启动文件,ZMain.c相当于main文件,里面有main函数: 1 int main( void ) 2 { 3 osal_int_disable( INTS_ALL );// Turn off interrupts 关中断 4 HAL_

[ZigBee] 15、Zigbee协议栈应用(一)——Zigbee协议栈介绍及简单例子(长文,OSAL及Zigbee入门知识)

1.Zigbee协议栈简介 协议是一系列的通信标准,通信双方需要按照这一标准进行正常的数据发射和接收.协议栈是协议的具体实现形式,通俗讲协议栈就是协议和用户之间的一个接口,开发人员通过使用协议栈来使用这个协议,进而实现无线数据收发. 如图1所示:Zigbee协议分为两部分,IEEE 802.15.4定义了PHY(物理层)和MAC(介质访问层)技术规范:Zigbee联盟定义了NWK(网络层).APS(应用程序支持层).APL(应用层)技术规范.Zigbee协议栈就是将各个层定义的协议都集合在一起,

「ZigBee模块」zigbee协议栈网络管理

Zigbee协议栈网络管理 一.补充基础知识 每个cc2530芯片出厂时候都有一个全球唯一的32位MAC地址,当设备连入网络的时候,每个设备都能获得由协调器分配的16位短地址,协调器默认地址0x0000,很多时候网络就是通过短地址进行管理. 二.实验现象 路由器.设备终端发送自己定义的设备号给协调器,协调器通过接收到的设备号判断设备类型,并且获取设备的短地址,通过串口打印出来. 三.实验步骤 串口初始化 图1 先在SampleApp.c添加串口通信的头文件.(如图1) #include “MT_

【转】TI Z-stack协议栈学习-添加新任务

开始学习TI的zigbee协议栈,无线龙的资料看得比较乱,在网络找到不少分析协议栈的文章,先贴上来,等自己有空了再好好原创一下吧. 协议栈版本:ZStack-1.4.3-1.2.1 TI Z-stack协议栈学习-添加新任务 1.Zstack中如何实现自己的任务 http://zhenling.chen.blog.163.com/blog/static/1940851920097710392587/ 在Zstack(TI的Zigbee协议栈)中,对于每个用户自己新建立的任务通常需要两个相关的处理

ECC协议栈学习总结

            ECC协议栈学习总结 目录 1 前言    3 2  ECC通讯原理... 3 2.1   ECC通讯模型... 3 2.2   ECC通讯实现... 5 2.2.1 物理层实现..................................................................................................... .5 2.2.2 数据链路层实现...............................

Zigbee系列 学习笔记五(信道选择)

EEE 802.15.4/ZigBee工作在工业科学医疗(ISM)频段,定义了两个工作频段,即2.4 GHz频段和868/915 MHz频段.在IEEE 802.15.4中,总共分配了27个具有3种速率的信道:在2.4 GHz频段有16个速率为250kb/s的信道,在915 MHz频段有10个40 kb/s的信道,在868 MHz频段有1个20 kb/s的信道. 这些信道的中心频率按如下定义(k为信道数): Fc=868.3MHz,(k=0) Fc=906MHz+2(k-1)MHz,(k=1,2