| 5.点播通讯-无线通讯(深入学习协议栈的组网,建网相关流程) |
| 实验内容: |
|
|
| 实验多终端通讯 |
| 掌握点对点通讯 |
|
提示:如果 3 个模块,可将其中一个节点做路由器,再观察现象更清楚。 点播:就是点对点通信,也就是 2 个设备之间的通讯,不容许有第三个设备收到信息。 实现现象: |
|
将程序分别下载到协调器、终端,连接串口。如果 3 个模块,可将其中一个做路由器,上电可以看到只有协调 器在一个周期内收到信息。也就是说路由器和终端均与地址为 0x00(协调器)的设备通信,不与其他设备通 信。确定通信对象的就是节点的短地址,实现点对点传输。 |
| 实验详解: |
|
我们在“3.广播组网-无线数据传输”例子中,通过简单的修改即可完成点播实验。相同的工程阅读代码更容 易,等大家掌握到一定程度后,我们再换别的例子讲解。 |
| 打 开 “ ..CC2530 第 |
| 5 |
| 章 |
| zigbee |
| 协 议 栈 应 用 与 组 网 5. 点 播 通 讯 - 无 线 通 讯 |
|
ZStack-2.5.1aProjectszstackSamplesSampleAppCC2530DBSampleApp.eww”工程。在开始之前 我们先了解下面两个重要结构: |
| typedef enum |
| //枚举类型 |
| { |
| afAddrNotPresent = AddrNotPresent, |
|
afAddr16Bit afAddr64Bit afAddrGroup |
|
= Addr16Bit, = Addr64Bit, = AddrGroup, |
|
//点播方式 16 位短地址通讯 //64 位 IEEE 地址(物理) //组播方式 |
|
afAddrBroadcast = AddrBroadcast } afAddrMode_t; |
| //广播方式 |
|
typedef struct { union { |
| uint16 |
| shortAddr; |
| //短地址 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 1 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |

|
ZLongAddr_t extAddr; } addr; |
| //IEEE地址 |
|
afAddrMode_t addrMode; byte endPoint; |
|
//传送模式 //端点号 |
| uint16 panId; |
| // used for the INTER_PAN feature |
| } afAddrType_t; |
| 1. |
| 找到 afAddrType_t SampleApp_Periodic_DstAddr;代码下面增加一行代码如下: |
| 2. |
|
搜索 afAddrGroup,在它下增加对 SampleApp_P2P_DstAddr 配置,可直接复制广播的配置修改即可, 增加后如下: |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 2 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |

| 协调器的地址规定为 0x0000 |
| 3. |
| 增加发送函数,相信现在大家对下面的函数应该很熟悉了。 |
| void SampleApp_Send_P2P_Message( void ) |
| { |
| uint8 data[11]="0123456789"; |
| if ( AF_DataRequest( &SampleApp_P2P_DstAddr, &SampleApp_epDesc, |
| SAMPLEAPP_P2P_CLUSTERID, |
| 10, |
| data, |
| &SampleApp_TransID, |
| AF_DISCV_ROUTE, |
| AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) |
| { |
| } |
| else |
| { |
| // Error occurred in request to send. |
|
} } |
| 4. |
| 其 中 SampleApp_P2P_DstAddr 是 我 们 之 前 自 己 定 义 的 , SAMPLEAPP_P2P_CLUSTERID 是 在 |
| SampleApp.h 中增加的,如下: |
| #define SAMPLEAPP_MAX_CLUSTERS |
| 3 |
| #define SAMPLEAPP_PERIODIC_CLUSTERID 1 |
|
#define SAMPLEAPP_FLASH_CLUSTERID #define SAMPLEAPP_P2P_CLUSTERID |
| 2 |
| 3 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 3 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |

| 5. |
| 搜索 SampleApp_ProcessEvent,找到 if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT ) 修改 |
| 成如下代码: |
| if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT ) |
| { |
| // Send the periodic message |
| //SampleApp_SendPeriodicMessage(); //注释原来的发送函数 |
| SampleApp_Send_P2P_Message(); |
| //增加点播的发送函数 |
| // Setup to send message again in normal period (+ a little jitter) |
|
osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT, (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) ); |
| // return unprocessed events |
| return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT); |
| } |
| 6. |
| 在接收方面,搜索找到 SampleApp_MessageMSGCB,我们进行如下修改(增加红色部分): |
| void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) |
| { |
| uint16 flashTime; |
| switch ( pkt->clusterId ) |
| { |
| case SAMPLEAPP_P2P_CLUSTERID: |
| HalUARTWrite(0, "Rx:", 3); |
| //提示接收到数据 |
| HalUARTWrite(0, pkt->cmd.Data, pkt->cmd.DataLength); //串口输出接收到的数据 |
|
HalUARTWrite(0, "n", 1); break; |
| // 回车换行 |
|
case SAMPLEAPP_PERIODIC_CLUSTERID: break; |
|
case SAMPLEAPP_FLASH_CLUSTERID: flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] ); HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) ); break; |
| } |
| } |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 4 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| 7. |
| 协调器不需要周期发数据,注释协调器的周期事件 |
| case ZDO_STATE_CHANGE: |
| SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); |
| if ( //(SampleApp_NwkState == DEV_ZB_COORD) || |
| (SampleApp_NwkState == DEV_ROUTER) |
| || (SampleApp_NwkState == DEV_END_DEVICE) ) |
| { |
| // Start sending the periodic message in a regular interval. |
| osal_start_timerEx( SampleApp_TaskID, |
| SAMPLEAPP_SEND_PERIODIC_MSG_EVT, |
| SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT ); |
| } |
| else |
| { |
| // Device is no longer in the network |
| } |
| break; |
|
最后别忘了加上图 1 中的函数声明,不然编译报错的。将修改后的程序分别编译、下载到协调器、路由器、终 端,如果条件允许都连接串口。可以看到只有协调器一个周期性收到字符串。也就是说终端与地址为 0x00(协 调器)的设备通信,不与其他设备通信。实现点对点传输。如下图所示: |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 5 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
|
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ 补充知识: |
|
有意向深入学习者参考文档和视频,深入学习协议栈的组网,建网相关流程。平时我们只关 心应用层,会组网,实现传感器的数据采集,无线传输就算掌握 ZigBee 通讯了,并非每个 人都需要了解底层代码运行情况,普通学习者也可以大概看看即可。 |
| ZIGBee 组网流程 建立网络和设备入网 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 6 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |

| 协调器的组网,终端设备和路由设备发现网络以及加入网络 |
| 协调器、路由器和终端节点相同执行部分 |
| //第一步:Z-Stack 由 main()函数开始执行,main()函数共做了 2 件事: |
| 一是系统初始化,另外一件是开始执行轮转查询式操作系统 |
| int main( void ) |
| { |
| ....... |
| // Initialize the operating system |
|
osal_init_system(); //第二步,操作系统初始化 ...... |
| osal_start_system(); //初始化完系统任务事件后,正式开始执行操作系统 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 7 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |

| ...... |
| } |
| //第二步,进入 osal_init_system()函数,执行操作系统初始化 |
| uint8 osal_init_system( void ) //初始化操作系统,其中最重要的是,初始化操作系统任务 |
| { |
|
// Initialize the Memory Allocation System osal_mem_init(); |
|
// Initialize the message queue osal_qHead = NULL; |
| // Initialize the timers |
| osalTimerInit(); |
|
// Initialize the Power Management System osal_pwrmgr_init(); |
|
// Initialize the system tasks. osalInitTasks(); //第三步,执行操作系统任务初始化函数 // Setup efficient search for the first free block of heap. osal_mem_kick(); |
| return ( SUCCESS ); |
| } |
|
//第三步,进入 osalInitTasks()函数,执行操作系统任务初始化 void osalInitTasks( void ) |
| { |
| uint8 taskID = 0; |
|
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt); osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt)); //任务优先级由高向低依次排列,高优先级对应 taskID 的值反而小 macTaskInit( taskID++ ); //不需要用户考虑 |
|
nwk_init( taskID++ ); Hal_Init( taskID++ ); #if defined( MT_TASK ) MT_TaskInit( taskID++ ); #endif |
| //不需要用户考虑 |
| //硬件抽象层初始化,需要我们考虑 |
| APS_Init( taskID++ ); |
| //不需要用户考虑 |
|
#if defined ( ZIGBEE_FRAGMENTATION ) APSF_Init( taskID++ ); |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 8 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| #endif |
| ZDApp_Init( taskID++ ); //第四步,ZDApp 层,初始化 ,执行ZDApp_init函数后,如果是协调器将建立 |
| 网络,如果是终端设备将加入网络。 |
| #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT ) |
|
ZDNwkMgr_Init( taskID++ ); #endif |
| SampleApp_Init ( taskID ); //应用层 SampleApp 层初始化,需要用户考虑 |
| 在此处设置了一个按键触发 |
|
事件,当有按键按下的时候,产生一个系统消息 } |
|
//第四步,进入 ZDApp_init()函数,执行 ZDApp 层初始化 void ZDApp_Init( uint8 task_id ) |
| { |
| // Save the task ID |
| ZDAppTaskID = task_id; |
|
// Initialize the ZDO global device short address storage ZDAppNwkAddr.addrMode = Addr16Bit; ZDAppNwkAddr.addr.shortAddr = INVALID_NODE_ADDR; (void)NLME_GetExtAddr(); // Load the saveExtAddr pointer. // Check for manual "Hold Auto Start" ZDAppCheckForHoldKey(); |
|
// Initialize ZDO items and setup the device - type of device to create. ZDO_Init(); |
|
// Register the endpoint description with the AF // This task doesn't have a Simple description, but we still need // to register the endpoint. |
|
afRegister( (endPointDesc_t *)&ZDApp_epDesc ); #if defined( ZDO_USERDESC_RESPONSE ) ZDApp_InitUserDesc(); |
|
#endif // ZDO_USERDESC_RESPONSE // Start the device? |
| if ( devState != DEV_HOLD ) |
| //devState 初值为 DEV_INIT , 所以在初始化 ZDA 层时,就执行该条 |
| 件语句 |
| { |
| ZDOInitDevice( 0 ); |
| //接着转到 ZDOInitDevice()函数 |
| } |
| else |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 9 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| { |
| // Blink LED to indicate HOLD_START |
| HalLedBlink ( HAL_LED_4, 0, 50, 500 ); |
| } |
|
ZDApp_RegisterCBs(); } |
| //第五步 执行 ZDOInitDevice()函数,执行设备初始化 |
| uint8 ZDOInitDevice( uint16 startDelay ) |
| { |
| ....... |
| // Trigger the network start |
| ZDApp_NetworkInit( extendedDelay ); //第六步 网络初始化,跳到相应的函数里头 |
|
....... } |
| //第七步 执行 ZDApp_NetWorkInit()函数网络初始化 |
| void ZDApp_NetworkInit( uint16 delay ) |
| { |
| if ( delay ) |
| { |
| // Wait awhile before starting the device |
| osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay ); //发送 ZDO_NETWORK_INIT(网 |
| 络初始化)消息到 ZDApp 层,转到 ZDApp 层,执行 ZDApp_event_loop() 函数 |
| } |
| else |
| { |
| osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT ); |
|
} } |
| //第八步 转到 ZDApp_event_loop()函数 |
| UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events ) |
| { |
| if ( events & ZDO_NETWORK_INIT ) |
| //网络初始化事件处理 |
| { |
| // Initialize apps and start the network |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 10 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| devState = DEV_INIT; |
| //设备逻辑类型,启动模式,信标时间,超帧长度,接着去启动设备,执行 ZDO_StartDevice() |
| ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode, |
| DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER ); |
| // Return unprocessed events |
| return (events ^ ZDO_NETWORK_INIT); |
|
} } |
| //执行 ZDO_StartDevice()函数,启动设备 |
| void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, byte beaconOrder, byte |
| superframeOrder ) |
| { |
| ...... |
| if ( ZG_BUILD_COORDINATOR_TYPE && logicalType == NODETYPE_COORDINATOR ) |
| //当设备作为 |
| 协调器时,执行这个条件语句。 |
| { |
| if ( startMode == MODE_HARD ) |
| { |
| devState = DEV_COORD_STARTING; |
|
//调用 NLME_NetworkFormationRequest()向网络层发送形成网络请求,由于些函数源码没开源,是通过 ZDO_NetworkFormationConfirmCB()函数反馈结果。如果协议栈同意协调器节点建网并且网络建立成功, 则会点亮LED灯,同时函数最后还会触发事件:osal_set_event(ZDAppTaskID, ZDO_NETWORK_START )。 可查看 ZDO_NetworkFormationConfirmCB |
| ret |
| = |
| NLME_NetworkFormationRequest( |
| zgConfigPANID, |
| zgApsUseExtendedPANID, |
| zgDefaultChannelList, |
|
zgDefaultStartingScanDuration, beaconOrder, superframeOrder, false ); |
| } |
| if ( ZG_BUILD_JOINING_TYPE && (logicalType == NODETYPE_ROUTER || logicalType == |
| NODETYPE_DEVICE) ) //当为终端设备或路由时 |
| { |
|
if ( (startMode == MODE_JOIN) || (startMode == MODE_REJOIN) ) { |
| devState = DEV_NWK_DISC; |
|
// zgDefaultChannelList 与协调器形成网络的通道号匹配。 网络发现请求。 // 继而转到 ZDO_NetworkDiscoveryConfirmCB()函数 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 11 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList, zgDefaultStartingScanDuration ); |
| } |
| } |
|
...... } |
| //分两种情况,1.协调器 |
| 2.路由器或终端设备 |
| 1)协调器 |
| void ZDO_NetworkFormationConfirmCB( ZStatus_t Status ) //给予 ZDO 层网络形成反馈信息(协调器) |
| { |
| osal_set_event( ZDAppTaskID, ZDO_NETWORK_START ); //发送网络启动事件 到 ZDApp 层,接着转到 |
| ZDApp_event_loop()函数 |
| ...... |
| } |
| UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events ) |
| { |
| ...... |
| if ( events & ZDO_NETWORK_START ) // 网络启动事件 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 12 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |

| { |
| ZDApp_NetworkStartEvt(); //网络启动事件,接着执行 ZDApp_NetworkStartEvt()函数 |
| ...... |
| } |
| } |
| void ZDApp_NetworkStartEvt( void ) |
| //处理网络启动事件 |
| { |
| ...... |
| osal_pwrmgr_device( PWRMGR_ALWAYS_ON ); |
| //电源总是上电 |
|
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT ); //设置网络状态改变事件,发送到 ZDApp 层,转到 ZDApp_event_loop()函数,找到相对应的网络改变事件 ...... |
| } |
|
这 里 网 络 启 动 后 , 触 发 了 ZDO 设 备 状 态 改 变 的 事 件 , osal_set_event(ZDAppTaskID, ZDO_STATE_CHANGE_EVT ); 同 样 , 跳 转 到 函 数 内 部 ZDApp_event_loop() 内 部 看 看 , 此 时 发 现 与 ZDO_STATE_CHANGE_EVT 相对应的 if 分支执行函数 ZDO_UpdateNwkStatus(devState );即更新网络状态 信息。 |
| 函数 ZDO_UpdateNwkStatus()内部是如何更新网络信息的呢? |
|
该函数的作用是将网络状态改变 state 这一消息通知给在 AF 层注册过的所有端点的任务,除了端口 0.一共 有 255 个端点,端点 0 保留与 ZDO 接口,255 广播,端点 241~254 为扩展口,其他用户可用. SampleApp_Init()函数中通过 afRegister 在 AF 层注册了端口为 20 的应用对象。该函数的第二个参数就是在 AF 层 注 册 的 SampleApp 的 任 务 ID, 发 送 信 息 的 函 数 为 : zdoSendStateChangeMsg(state, *(pItem->epDesc->task_id)); |
| 到这里为止,协调器节点基本上就已经创建和配置好了一个无线网络。 |
| 2)路由器或终端设备 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 13 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| // 当发现有网络存在时,网络层将给予 ZDO 层发现网络反馈信息 |
| ZStatus_t ZDO_NetworkDiscoveryConfirmCB( uint8 ResultCount, networkDesc_t *NetworkList ) |
| { |
| ....... |
| //把网络发现这个反馈消息,发送到 ZDA 层,转到 ZDApp_ProcessOSALMsg(),执行 |
| ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_DISC_CNF, sizeof(ZDO_NetworkDiscoveryCfm_t), |
| (uint8 *)&msg ); |
| } |
| void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr ) |
| { |
| ...... |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 14 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |

|
case ZDO_NWK_DISC_CNF: ...... |
| //网络发现响应。 |
|
//当发现有网络存在时,网络层将给予 ZDO 层发现网络反馈信息。然后由网络层发起加入网络请求,如加入 网 络 成 功 , 则 网 络 层 将 给 予 ZDO 层 加 入 网 络 反 馈 , 执 行 NLME_JoinRequest() 函 数 。 然 后 执 行 ZDO_JoinConfirmCB()函数 |
| if ( NLME_JoinRequest( ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->extendedPANID, |
| BUILD_UINT16( |
| ((ZDO_NetworkDiscoveryCfm_t |
| *)msgPtr)->panIdLSB, |
| ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->panIdMSB ), |
| ((ZDO_NetworkDiscoveryCfm_t *)msgPtr)->logicalChannel, |
| ZDO_Config_Node_Descriptor.CapabilityFlags ) != ZSuccess ) |
| { |
| ZDApp_NetworkInit( (uint16)(NWK_START_DELAY |
| + ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) ); |
| } |
|
...... } |
| voidZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status ) //设备加入网络响应。 |
| { |
| ...... |
| //将 ZDO_NWK_JOIN_IND 事件发送到 ZDA 层,执行 ZDApp_ProcessOSALMsg()函数。 |
| ZDApp_SendMsg( ZDAppTaskID,ZDO_NWK_JOIN_IND, sizeof(osal_event_hdr_t), (byte*)NULL ); |
| } |
| void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr ) |
| { |
| ...... |
| case ZDO_NWK_JOIN_IND: |
| //加入网络反馈信息事件。 |
|
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE ) { |
| ZDApp_ProcessNetworkJoin(); |
| // |
| 转 |
| 到 |
| ZDApp_ProcessNetworkJoin() |
| , |
| 执 |
| 行 |
| ZDApp_ProcessNetworkJoin()函数。 |
|
} break; ...... |
| } |
| 在执行 ZDApp_ProcessNetworkJoin()函数的时候,要分两种情况,一种是终端设备,一种是路由器: |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 15 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| void ZDApp_ProcessNetworkJoin( void ) |
| { |
| ...... |
| if ( ZSTACK_ROUTER_BUILD ) |
| { |
| // NOTE: first two parameters are not used, see NLMEDE.h for details |
|
if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE ) { |
| NLME_StartRouterRequest( 0, 0, false ); |
| //路由启动请求 |
| } |
| } |
|
...... } |
| void ZDO_StartRouterConfirmCB( ZStatus_t Status ) //请求反馈函数 |
| { |
| nwkStatus = (byte)Status; |
| ...... |
| osal_set_event(ZDAppTaskID,ZDO_ROUTER_START); |
| } |
| UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events ) |
| { |
| if ( events & ZDO_ROUTER_START ) |
| { |
| if ( nwkStatus == ZSuccess ) |
| { |
| if ( devState == DEV_END_DEVICE ) |
| devState = DEV_ROUTER; |
| //设备状态变成路由器 |
| osal_pwrmgr_device( PWRMGR_ALWAYS_ON ); |
| } |
|
else { |
| // remain as end device!! |
| } |
|
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT ); // Return unprocessed events |
| //设置 ZDO 状态改变事件 |
| return (events ^ ZDO_ROUTER_START); |
| } |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 16 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| } |
| //执行 ZDO 状态改变事件 |
| UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events ) |
| { |
| ....... |
| if ( events & ZDO_STATE_CHANGE_EVT ) // 网络改变事件,这个事件就是在设备加入网络成功后,并在 |
| 网络中的身份确定后产生的一个事件 |
| { |
| ZDO_UpdateNwkStatus( devState ); //更新网络状态,执行 ZDO_UpdateNwkStatus()函数。 |
| ...... |
| } |
| } |
| //执行 ZDO_UpdateNwkStatus()函数,完成网络状态更新 |
| void ZDO_UpdateNwkStatus(devStates_t state) //更新网络状态 |
| { |
| ...... |
| zdoSendStateChangeMsg(state, *(pItem->epDesc->task_id)); //发送状态改变消息到 zdo 层,转到 |
| zdoSendStateChangeMsg()函数 |
| ....... |
| ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr(); //调用 NLME_GetShortAddr()函数,获得 |
| 16 位短地址。 |
|
(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer. //获得 64 位的 IEEE 地址。 } |
| //执行 zdoSendStateChangeMsg()函数 |
| static void zdoSendStateChangeMsg(uint8 state, uint8 taskId) |
| { |
| osal_event_hdr_t *pMsg = (osal_event_hdr_t *)osal_msg_find(taskId, ZDO_STATE_CHANGE); |
| if (NULL == pMsg) |
| { |
|
if (NULL == (pMsg = (osal_event_hdr_t *)osal_msg_allocate(sizeof(osal_event_hdr_t)))) { |
|
// Upon failure to notify any EndPoint of the state change, re-set the ZDO event to // try again later when more Heap may be available. |
|
osal_set_event(ZDAppTaskID, ZDO_STATE_CHANGE_EVT); //如果 ZDO 状态没有任何改变,再一 次,跳到 ZDO_STATE_CHANGE_EVT 事件处理函数。 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 17 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| } |
|
else { |
| pMsg->event = ZDO_STATE_CHANGE; |
| //如果 ZDO 状态改变了 了,把 ZDO_STATE_CHANGE 这 |
| 个消息保存到 pMsg |
| pMsg->status = state; |
| (void)osal_msg_send(taskId, (uint8 *)pMsg); |
| } |
|
} ...... } |
|
调用函数 ZDApp_event_loop()进行处理。进入到函数内部,找到相对于 ZDO_STATE_CHANGE_EVT 的 if 分支。该 if 分支内部执行了函数 ZDO_UpdateNwkStatus(devState ),即更新网络状态函数,将网络状态 改 变 state 这 一 消 息 通 知 给 在 AF 层 注 册 过 的 所 有 端 点 的 任 务 此 函 数 内 部 执 行 zdoSendStateChangeMsg(state, *(pItem->epDesc->task_id)); |
|
发送状态改变消息到 zdo 层,而该函数内部执行的是一个 switch 选择结构,找到分支:case ZDO_STATE_CHANGE,则是内部执行了函数: MT_ZdoStateChangeCB((osal_event_hdr_t*)msg); //自 此,协调器组网形成(终端设备成功加入网络) |
| 终端 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 18 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| //初始化玩系统任务事件后,正是开始执行操作系统,此时操作系统不断的检测有没有任务事件发生,一旦检 |
|
测到有事件发生,就转到相应的处理函数,进行处理。 voidosal_start_system(void) //正式执行操作系统 { |
| #if !defined ( ZBIT ) && !defined ( UBIT ) |
| for(;;) // Forever Loop |
| //死循环 |
| #endif |
| { |
| uint8 idx = 0; |
| osalTimeUpdate(); |
| Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer(). |
| do { |
| if (tasksEvents[idx]) // Task is highest priority that is ready. |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 19 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |

|
{ } |
| break; |
| // 得到待处理的最高优先级任务索引号 idx |
| } while (++idx < tasksCnt); |
| if (idx < tasksCnt) |
| { |
| uint16 events; |
| halIntState_t intState; |
| HAL_ENTER_CRITICAL_SECTION(intState); //进入临界区 |
| events = tasksEvents[idx]; |
| //提取需要处理的任务中的事件 |
| tasksEvents[idx] = 0; // Clear the Events for this task. // 清除本次任务的事件 |
| HAL_EXIT_CRITICAL_SECTION(intState); |
| //退出临界区 |
|
events = (tasksArr[idx])( idx, events ); //通过指针调用任务处理函数 , 紧接着跳到相应的函数去处理 HAL_ENTER_CRITICAL_SECTION(intState); //进入临界区 |
| tasksEvents[idx] |= events; // Add back unprocessed events to the current task. // 保存未处理的 |
| 事件 |
| HAL_EXIT_CRITICAL_SECTION(intState); |
| //退出临界区 |
| } |
| #if defined( POWER_SAVING ) |
| else // Complete pass through all task events with no activity? |
| { |
|
osal_pwrmgr_powerconserve(); // Put the processor/system into sleep } |
| #endif |
| } |
| } |
| // The order in this table must be identical to the task initialization calls below in osalInitTask. |
|
const pTaskEventHandlerFn tasksArr[] = { macEventLoop, |
| nwk_event_loop, |
| Hal_ProcessEvent, |
|
#if defined( MT_TASK ) MT_ProcessEvent, |
| #endif |
| APS_event_loop, |
| #if defined ( ZIGBEE_FRAGMENTATION ) |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 20 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| APSF_ProcessEvent, |
| #endif |
| ZDApp_event_loop, |
| #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT ) |
| ZDNwkMgr_event_loop, |
| #endif |
|
SampleApp_ProcessEvent }; |
|
const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] ); uint16 *tasksEvents; |
| void osalInitTasks( void ) |
| { |
| uint8 taskID = 0; |
| // 分配内存,返回指向缓冲区的指针 |
|
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt); // 设置所分配的内存空间单元值为 0 |
| osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt)); |
| // 任务优先级由高向低依次排列,高优先级对应 taskID 的值反而小 |
| macTaskInit( taskID++ ); //macTaskInit(0) ,用户不需考虑 |
|
nwk_init( taskID++ ); Hal_Init( taskID++ ); #if defined( MT_TASK ) MT_TaskInit( taskID++ ); #endif |
| //nwk_init(1),用户不需考虑 |
| //Hal_Init(2) ,用户需考虑 |
| //如果定义 MT_TASK 则调用 MT_TaskInit() |
| APS_Init( taskID++ ); |
| //APS_Init(3) ,用户不需考虑 |
|
#if defined ( ZIGBEE_FRAGMENTATION ) APSF_Init( taskID++ ); #endif |
| ZDApp_Init( taskID++ ); |
| //ZDApp_Init(4) ,用户需考虑 |
| #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT ) |
|
ZDNwkMgr_Init( taskID++ ); #endif |
| //用户创建的任务 |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 21 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |
| SampleApp_Init(taskID); //SampleApp_Init_Init(5),用户需考虑。重要! } |
| 创同科技 专业专注无线通讯 勇于创新追求卓越品质 22 |
| 网址:http://ctkj.lzkj.org.cn 技术支持与项目合作(Tel):13964326707 QQ:173301163 |