SampleApp工程详解

更新时间:2023-10-03 00:50:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

该project实现了按键发送的功能。 同时实现了信息的广播和组播:

SampleApp_SendPeriodicMessage( void ); //阶段发送,广播形式 SampleApp_SendFlashMessage(); //闪烁发送,组播形式

同时按键up键可以进行控制信息的发送,即控制Group1中所有设备的LED1灯的闪烁时间。 按键right键进行设备加入/退出Group1的切换。

由于在SampleApp_Init( uint8 task_id )中添加了SampleApp_Init(taskID);(最后一个任务)

在操作系统启动的过程中,调用SampleApp_Init( uint8 task_id )

调用顺序:main( void )->osal_init_system();->osalInitTasks()->SampleApp_Init( taskID );

void SampleApp_Init( uint8 task_id ) {

SampleApp_TaskID = task_id; SampleApp_NwkState = DEV_INIT; SampleApp_TransID = 0;

// Device hardware initialization can be added here or in main() (Zmain.c). // If the hardware is application specific - add it here.

// If the hardware is other parts of the device add it in main(). #if defined ( BUILD_ALL_DEVICES )

// The \target is setup to have BUILD_ALL_DEVICES and HOLD_AUTO_START

// We are looking at a jumper (defined in SampleAppHw.c) to be jumpered // together - if they are - we will start up a coordinator. Otherwise, // the device will start as a router.

if ( readCoordinatorJumper() ) //根据P02和P03是否有跳线来判断是协调器还是路由器 zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR; else

zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER; #endif // BUILD_ALL_DEVICES #if defined ( HOLD_AUTO_START )

// HOLD_AUTO_START is a compile option that will surpress ZDApp // from starting the device and wait for the application to // start the device.

ZDOInitDevice(0); //开始启动设备,协调器建立网络此时LED3闪烁,别的设备加入网络,加入后LED3一直亮着,说明加入成功 #endif

// Setup for the periodic message's destination address //这儿设置了组播和广播的短地址以及填写了端点号 // Broadcast to everyone

SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast; SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;

// Setup for the flash command's destination address - Group 1 SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup; SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;

SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP; // Fill out the endpoint description.

SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_epDesc.task_id = &SampleApp_TaskID; SampleApp_epDesc.simpleDesc

= (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc; SampleApp_epDesc.latencyReq = noLatencyReqs; // Register the endpoint description with the AF

afRegister( &SampleApp_epDesc ); //将填写好的端点向AF层进行注册,以便收到符合的消息时可以送到应用层

// Register for all key events - This app will handle all key events

RegisterForKeys( SampleApp_TaskID ); //注册所有的按键信息,由SampleApp_TaskID对应的SampleApp_ProcessEvent()进行处理

// By default, all devices start out in Group 1 //这儿填写的组的内容,如组名,组标识,然后加入SAMPLEAPP_ENDPOINT组中 SampleApp_Group.ID = 0x0001;

osal_memcpy( SampleApp_Group.name, \1\7 ); aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group ); #if defined ( LCD_SUPPORTED )

HalLcdWriteString( \HAL_LCD_LINE_1 ); #endif }

这样的初始工作就已经完成了,接下来的就是分析按键事件及响应过程了

首先当网络形成时,下层会向应用层发送消息ZDO_STATE_CHANGE它由SampleApp_ProcessEvent()进行处理

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;

可以看出它启动了一个定时器,每次时间到时会触发SAMPLEAPP_SEND_PERIODIC_MSG_EVT事件,它由SampleApp_ProcessE vent()进行处理 if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT ) {

// Send the periodic message

SampleApp_SendPeriodicMessage(); //发送广播信息

// 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); }

我们可以看出,在发送广播信息后又设置了同样的定时器,从而循环的发送。

当有案件时,由于对按键进行了注册,所以由SampleApp_ProcessEvent()进行处理 case KEY_CHANGE:

SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );//进行本函数进行处理 break;

void SampleApp_HandleKeys( uint8 shift, uint8 keys ) {

(void)shift; // Intentionally unreferenced parameter

if ( keys & HAL_KEY_SW_1 ) {

SampleApp_SendFlashMessage( SAMPLEAPP_FLASH_DURATION ); //发送闪烁控制信息 }

if ( keys & HAL_KEY_SW_2 ) {

/* The Flashr Command is sent to Group 1.

* This key toggles this device in and out of group 1. * If this device doesn't belong to group 1, this application * will not receive the Flash command sent to group 1. */

aps_Group_t *grp;

grp = aps_FindGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );//若已经加入组中,则退出组,若没有加入则加入 if ( grp ) {

// Remove from the group

aps_RemoveGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP ); //(该函数的源码不公开,只公布接口) } else {

// Add to the flash group

aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group ); } } }

再看 SampleApp_SendFlashMessage函数

void SampleApp_SendFlashMessage( uint16 flashTime ) //主要调用AF_DataRequest()函数发送 {

uint8 buffer[3];

buffer[0] = (uint8)(SampleAppFlashCounter++); buffer[1] = LO_UINT16( flashTime ); buffer[2] = HI_UINT16( flashTime );

if ( AF_DataRequest( &SampleApp_Flash_DstAddr, &SampleApp_epDesc, SAMPLEAPP_FLASH_CLUSTERID, 3, buffer,

&SampleApp_TransID, AF_DISCV_ROUTE,

AF_DEFAULT_RADIUS ) == afStatus_SUCCESS ) { } else {

// Error occurred in request to send. } }

别的设备在接受到后,仍然由SampleApp_ProcessEvent()进行处理 case AF_INCOMING_MSG_CMD:

SampleApp_MessageMSGCB( MSGpkt ); break;

可见它由 SampleApp_MessageMSGCB( MSGpkt );处理

void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) {

uint16 flashTime; switch ( pkt->clusterId ) {

case SAMPLEAPP_PERIODIC_CLUSTERID: //对于收到的广播信息,忽略 break;

case SAMPLEAPP_FLASH_CLUSTERID:

flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] ); //对接受到的组播信息,控制LED4即LED1的闪烁

HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) ); break; } }

这样的话我们就搞清楚了其中的脉络,总之,他就是举了一个按键发送的简单的例子,循环发送广播信息,按UP发送组播信息。

对接收到的广播信息不予理睬,对收到的组播信息控制LED1的闪烁。 同时按键Right时进行设备加入/退出组的切换。

SAMPLEAPP 程序主要说明

2012-05-03 10:12:54| 分类: zigbee | 标签: |字号大中小 订阅

程序执行流程如下:

ZMain.c的main()--->osal.c的osal_init_system()---->OSAL_SampleApp.c的

osalInitTasks()之后分两部分执行-------->首先执行SampleApp.c的 SampleApp_Init(),接着执行osal.c中的事件循环,不停的执行

SampleApp_ProcessEvent(),进行应用层事件检测 两个关键函数 1.SampleApp_Init

2.SampleApp_ProcessEvent 分析如下 SampleApp_init

void SampleApp_Init( uint8 task_id ) {

//osal应用层的任务ID赋值 SampleApp_TaskID = task_id;

//设备状态设定为ZDO层中定义的初始化状态 SampleApp_NwkState = DEV_INIT; //定义消息ID

SampleApp_TransID = 0;

//后面的demo例子中用到这个编译选项 #if defined ( SOFT_START )

//如果选择了SOFT编译选项,则作为协调器启动

zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR; #endif // SOFT_START

//如果定义了HOLD_AUTO_START选项,则调用层的ZDOInitDevice,按照默认顺

//序网络中的第一个设备作为协调器,其他的设备作为子设备 #if defined ( HOLD_AUTO_START ) ZDOInitDevice(0); #endif //定义广播地址 //地址模式

SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast; //指定端点号

SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT

//指定目的网络地址为广播地址

SampleApp_Periodic_DstAddr.addr. shortAddr = 0xFFFF;

// 设定flash中命令即按键命令要发送的目的地址

SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup; SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;

SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;

// 定义本设备用来通信的APS层端点描述符 //端点号

SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; //任务ID

SampleApp_epDesc.task_id = &SampleApp_TaskID; //简单描述符

SampleApp_epDesc.simpleDesc

= (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc; //延时策略

SampleApp_epDesc.latencyReq = noLatencyReqs;

// 向AF层注册端点描述符 afRegister( &SampleApp_epDesc );

// 向osal层注册按键消息 RegisterForKeys( SampleApp_TaskID );

// 设定一个新的组 //组号

SampleApp_Group.ID = 0x0003; //设定组名

osal_memcpy( SampleApp_Group.name, \//把该组添加到网络中

aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );

#if defined ( LCD_SUPPORTED )

//如果选择了LCD_SUPPORTED编译选项,会打印一串字符 Print8(HAL_LCD_LINE_2,20,\#endif }

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) {

//定义应用层数据包

afIncomingMSGPacket_t *MSGpkt; //判断osal层的消息类型 //如果系统消息到来

if ( events & SYS_EVENT_MSG ) {

//接收数据包

MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(

SampleApp_TaskID ); //如果数据包不为空 while ( MSGpkt ) {

//判断消息类型

switch ( MSGpkt->hdr.event ) {

// 如果是按键消息 case KEY_CHANGE:

//调用按键处理函数

SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state,

((keyChange_t *)MSGpkt)->keys ); break;

// 如果是别的组设备周期发送的消息 case AF_INCOMING_MSG_CMD: //调用对周期消息的处理函数

SampleApp_MessageMSGCB( MSGpkt ); break;

// 如果是设备状态变换的命令 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) ) {

// 按正常间隔启动一个定时器

osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT, SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT ); } else {

//设备不在网络中的不做任何处理 // Device is no longer in the network } break;

default: break; }

// 释放消息占用的存储区

osal_msg_deallocate( (uint8 *)MSGpkt );

// 判断操作系统层是否有未处理的数据包,继续处理缓冲区中的包 MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(

SampleApp_TaskID ); }

//判断是否有未处理的系统消息,有则接收数据包,放到缓冲区一个个处理 return (events ^ SYS_EVENT_MSG); }

// 判断是否有定时消息

if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT ) {

// 定时时间到发送一个消息

SampleApp_SendPeriodicMessage();

// 重新启动定时器

osal_start_timerEx( SampleApp_TaskID,

SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF))

);

// 判断是否有未处理的周期消息,有则继续处理

return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT); }

// 其它事件不予处理,直接返回 return 0; }

本文来源:https://www.bwwdw.com/article/xcod.html

Top