实验设备
硬件:PC 机一台;ZB2530(底板、核心板、仿真器、USB 线) 一套
软件:win7 系统,IAR 8.20 集成开发环境
本实验是基于GenericApp无线收发,编者在第2讲也有讲过,当时也是用的TI提供的源码改编的,比较完善,而现在编者将带领大家编写较为简单的协议栈,实现个性化订制,下图为该实验的模型。
打开工程:
基于GenericApp无线收发实验\Projects\zstack\Samples\GenericApp\CC2530DB。
OSAL_Example.c
#include "ZComDef.h"
#include "hal_drivers.h" //硬件驱动头文件
#include "OSAL.h" //操作系统头文件
#include "OSAL_Tasks.h" //操作系统任务头文件
#if defined ( MT_TASK ) //串口应用头文件
#include "MT.h"
#include "MT_TASK.h"
#endif
#include "nwk.h" //网络层头文件
#include "APS.h" //应用支持层头文件
#include "ZDApp.h" //设备对象头文件
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
#include "ZDNwkMgr.h"
#endif
#if defined ( ZIGBEE_FRAGMENTATION )
#include "aps_frag.h"
#endif
#include "Common.h"
// 任务注册
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop, //MAC任务循环
nwk_event_loop, //网络层任务函数
Hal_ProcessEvent, //硬件层函数
#if defined( MT_TASK )
MT_ProcessEvent, //串口支持层定义
#endif
APS_event_loop, //应用支持层任务事件函数
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_ProcessEvent,
#endif
ZDApp_event_loop, //设备对象层函数
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_event_loop,
#endif
GenericApp_ProcessEvent //自己定义的任务处理函数
};
const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
uint16 *tasksEvents;
void osalInitTasks( void )//完成了任务ID的分配,以及所有任务的初始化
{
uint8 taskID = 0;
//分配内存空间
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
macTaskInit( taskID++ );//MAC层的任务ID号
nwk_init( taskID++ ); //网络ID分配
Hal_Init( taskID++ ); //硬件ID分配
#if defined( MT_TASK )
MT_TaskInit( taskID++ );
#endif
APS_Init( taskID++ );
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_Init( taskID++ );
#endif
ZDApp_Init( taskID++ );
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_Init( taskID++ );
#endif
GenericApp_Init( taskID );//自己任务初始化函数
}
第 1-22 行包含一些相关函数的头文件,相对固定不用过多研究
第 24-41 行 tasksArr 数组里面存放所有任务的任务处理函数,如果操作系查询到了该任务的 ID那么就会调用对应的任务处理函数,该数组的顺序必须和 osalInitTasks 函数的初始化顺序相同。
第 43 行 tasksCnt 保存了任务的个数
第 44 行 tasksEvent 这是一个指针,指向了事件标的首地址
第 45-68 行完成了任务 ID 的分配,以及所有任务的初始化。GenericApp_Init( taskID );是自己任务初始化函数。我们程序初始化部分都可写在此函数中,具体详解在协调器程序中给出。
协调器源码分析
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "Common.h"
#include "DebugTrace.h"
#if !defined( WIN32 )
#include "OnBoard.h"
#endif
/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
#include "OSAL_Nv.h"
const cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] =
{
GENERICAPP_CLUSTERID
};
const SimpleDescriptionFormat_t GenericApp_SimpleDesc =
{
GENERICAPP_ENDPOINT, // int Endpoint;
GENERICAPP_PROFID, // uint16 AppProfId[2];
GENERICAPP_DEVICEID, // uint16 AppDeviceId[2];
GENERICAPP_DEVICE_VERSION, // int AppDevVer:4;
GENERICAPP_FLAGS, // int AppFlags:4;
GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)GenericApp_ClusterList, // byte *pAppInClusterList;
GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)GenericApp_ClusterList // byte *pAppInClusterList;
};
endPointDesc_t GenericApp_epDesc;
byte GenericApp_TaskID;
byte GenericApp_TransID;
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void GenericApp_SendTheMessage(void);
void GenericApp_Init( byte task_id )
{
GenericApp_TaskID = task_id;//osal分配的任务ID随着用户添加任务的增多而改变
GenericApp_TransID = 0;//消息发送ID(多消息时有顺序之分)
//定义本设备用来通信的APS层端点描述符
GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;//应用程序的端口号
GenericApp_epDesc.task_id = &GenericApp_TaskID; //描述符的任务ID
GenericApp_epDesc.simpleDesc //简单描述符
= (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;
GenericApp_epDesc.latencyReq = noLatencyReqs; //延时策略
afRegister( &GenericApp_epDesc ); //向AF层登记描述符
}
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
afIncomingMSGPacket_t *MSGpkt;
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case AF_INCOMING_MSG_CMD:
GenericApp_MessageMSGCB(MSGpkt);
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt );
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
}
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
void GenericApp_MessageMSGCB(afIncomingMSGPacket_t *pkt)
{
unsigned char buf[3];
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
osal_memset(buf, 0 , 3);
osal_memcpy(buf, pkt->cmd.Data, 2);
if(buf[0]=='D' && buf[1]=='1')
{
HalLedBlink(HAL_LED_1, 0, 50, 500);
GenericApp_SendTheMessage();
}
else
{
HalLedSet(HAL_LED_1, HAL_LED_MODE_ON);
}
break;
}
}
void GenericApp_SendTheMessage(void)
{
byte SendData[3]="D1";
afAddrType_t devDstAddr;
devDstAddr.addrMode=(afAddrMode_t)Addr16Bit;
devDstAddr.endPoint=GENERICAPP_ENDPOINT;
devDstAddr.addr.shortAddr=0xFFFF;
AF_DataRequest(&devDstAddr,
&GenericApp_epDesc,
GENERICAPP_CLUSTERID,
2,
SendData,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS);
}
第 1-19 行包含一些相关函数的头文件
第 21-24 行GENERICAPP_CLUSTERID 为簇 ID 列表,消息发送和接收需要用的,如果定义多个簇 ID 就在这里增加,以前的实验我们已增加过了,这里只提一下。
第 26-37 行简单描述符的定义,定义终端号、终端支持的设备 ID、设备描述的版本、终端支持的输入簇数目等信息,格式相对固定。
第 39 行 endPointDesc_t GenericApp_epDesc; //简单描述符。
第 40 行 byte GenericApp_TaskID; //osal 分配的任务 ID 随着用户添加任务的增多而改变。
第 41 行 byte GenericApp_TransID; //消息发送 ID(多消息时有顺序之分)
第 46-58 行 GenericApp_Init 函数,程序初始化部分都可写在此函数
第 60-83 行事件处理函数。
第 85-106 行接收数据。
第 108-125 行发送数据。
以上代码是在 TI GenericApp 例程复制过来的,我们对 GenericApp.c 中的代码进行了裁剪,帮助大家更容易掌握 GenericApp,同时我们把协调器和终端的代码独立开,让初学者不易混淆。 明白了其中的原理后,再去看其它程序那就是小菜一碟了。至于终端只有三个地方不同,我们讲不同处即可,大部分一样。相信学到现在的水平,应该完全可以看懂了
终端源码分析
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "Common.h"
#include "DebugTrace.h"
#if !defined( WIN32 )
#include "OnBoard.h"
#endif
/* HAL */
#include "hal_lcd.h"
#include "hal_led.h"
#include "hal_key.h"
#include "hal_uart.h"
const cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] =
{
GENERICAPP_CLUSTERID
};
const SimpleDescriptionFormat_t GenericApp_SimpleDesc =
{
GENERICAPP_ENDPOINT, // int Endpoint;
GENERICAPP_PROFID, // uint16 AppProfId[2];
GENERICAPP_DEVICEID, // uint16 AppDeviceId[2];
GENERICAPP_DEVICE_VERSION, // int AppDevVer:4;
GENERICAPP_FLAGS, // int AppFlags:4;
GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)GenericApp_ClusterList, // byte *pAppInClusterList;
GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)GenericApp_ClusterList // byte *pAppInClusterList;
};
endPointDesc_t GenericApp_epDesc;
byte GenericApp_TaskID;
byte GenericApp_TransID;
devStates_t GenericApp_NwkState;
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void GenericApp_SendTheMessage( void );
void GenericApp_Init( byte task_id )
{
GenericApp_TaskID = task_id;
GenericApp_NwkState=DEV_INIT;
GenericApp_TransID = 0;
GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;
GenericApp_epDesc.task_id = &GenericApp_TaskID;
GenericApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;
GenericApp_epDesc.latencyReq = noLatencyReqs;
afRegister( &GenericApp_epDesc );
}
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
afIncomingMSGPacket_t *MSGpkt;
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case AF_INCOMING_MSG_CMD:
GenericApp_MessageMSGCB(MSGpkt);
break;
case ZDO_STATE_CHANGE:
GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if(GenericApp_NwkState == DEV_END_DEVICE)
{
GenericApp_SendTheMessage();
}
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt );
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
return 0;
}
void GenericApp_MessageMSGCB(afIncomingMSGPacket_t *pkt)
{
unsigned char buf[3];
switch ( pkt->clusterId )
{
case GENERICAPP_CLUSTERID:
osal_memset(buf, 0 , 3);
osal_memcpy(buf, pkt->cmd.Data, 2);
if(buf[0]=='D' && buf[1]=='1')
{
HalLedBlink(HAL_LED_1, 0, 50, 500);
}
else
{
HalLedSet(HAL_LED_1,HAL_LED_MODE_ON);
}
break;
}
}
void GenericApp_SendTheMessage(void)
{
byte SendData[3]="D1";
afAddrType_t devDstAddr;
devDstAddr.addrMode=(afAddrMode_t)Addr16Bit;
devDstAddr.endPoint=GENERICAPP_ENDPOINT;
devDstAddr.addr.shortAddr=0x0000;
AF_DataRequest(&devDstAddr,
&GenericApp_epDesc,
GENERICAPP_CLUSTERID,
2,
SendData,
&GenericApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS);
}
实验现象
1)选择 CoodinatorEB-Pro, 下载到开发板 A;作为协调器;
2)选择 EndDeviceEB-Pro, 下载到开发板 B;作为终端设备
3)给两块开发板上电,协调器组网,终端联网成功后发“D1”, 协调器收到数据“D1”后Led1 闪烁;同时也发“D1”给终端,终端收到后 Led1 也闪烁。