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 |