SampleApp工程详解
更新时间:2023-10-03 00:50:01 阅读量: 综合文库 文档下载
- SampleApp应用推荐度:
- 相关推荐
该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; }
正在阅读:
SampleApp工程详解10-03
与狮子赛跑10-08
黄奇帆:如何判断五大领域产能过剩03-14
地基处理习题解答 - 图文11-22
2011-2012石景山区七年级上学期数学期末试题及答案10-05
4台账 分部(分项)工程安全技术交底06-04
北师大版七年级生物上册教案(全册完整版)09-02
沂水春风教案11-28
螺丝螺纹知识培训05-24
单位换算06-06
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 详解
- SampleApp
- 工程