我使用的协议栈版本及例子信息:
ZigBee2006\TexasInstruments\ZStack-1.4.3-1.2.1\Projects\zstack\Samples\SampleApp
首先借用前人的一个说明:
用户自己添加的应用任务程序在Zstack中的调用过程是:
(1).main() 执行(在ZMain.c中)
main() --->osal_init_system()
(2). osal_init_system()调用osalInitTasks(), (在OSAL.c中)
osal_init_system() --->osalInitTasks()
(3). osalInitTasks()调用SampleApp_Init() ,(在OSAL_SampleApp.c中)
osalInitTasks() --->SampleApp_Init()
在osalInitTasks()中实现了多个任务初始化的设置,其中macTaskInit( taskID++)到ZDApp_Init( taskID++ )的几行代码表示对于几个系统运行初始化任务的调用,而用户自己实现的SampleApp_Init()在最后,这里taskID随着任务的增加也随之递增.所以用户自己实现的任务的初始化操作应该在osalInitTasks()中增加.
//----------------------------------------------------------------------------------------------------
1、首先来看下主函数main()
ZSEG int main( void) //主函数的功能就是完成初始化任务,然后进入OSAL
{
// Turn off interrupts
osal_int_disable( INTS_ALL);
//Initialize HAL
HAL_BOARD_INIT();
// Make suresupply voltage is high enough to run
zmain_vdd_check();
//Initialize stack memory
zmain_ram_init();
//Initialize board I/O
InitBoard( OB_COLD );
// InitialzeHAL drivers
HalDriverInit();
//Initialize NV System
osal_nv_init( NULL );
// Determine the extended address
zmain_ext_addr();
//Initialize basic NV items
zgInit();
//Initialize the MAC
ZMacInit();
#ifndef NONWK
// Since the AF isn't a task, call it's initializationroutine
afInit();
#endif
#ifdefLCD_SUPPORTED
HalLcdInit();
#endif
// Initialize the operatingsystem
osal_init_system();
// Allowinterrupts
osal_int_enable( INTS_ALL);
// Finalboard initialization
InitBoard( OB_READY );
//HalLcdInit();
// Display information about this device
zmain_dev_info();
#ifdef LCD_SUPPORTED
zmain_lcd_init();
#endif
osal_start_system(); // No Return from here没有返回,即进入操作系统!!!
}
说明:初始化各软硬件后进入系统主循环函数。
这里重点是两个函数:系统初始化函数 osal_init_system(); 系统主循环函数osal_start_system();
下面记录下个人个人对系统初始化流程和系统主循环流程的学习。这里先记录下系统初始化流程。
//----------------------------------------------------------------------------------------------------
2、系统初始化流程
2.1osal_init_system()——系统初始化函数
byte osal_init_system( void )
{
// Initialize the Memory AllocationSystem
osal_mem_init();
// Initialize the message queue
osal_qHead = NULL;
#if defined( OSAL_TOTAL_MEM )
osal_msg_cnt = 0;
#endif
// Initialize the timers
osalTimerInit();
// Initialize the Power ManagementSystem
osal_pwrmgr_init();
// Initialize the system tasks.
osalInitTasks(); //初始化系统任务
// Setup efficient search for thefirst free block of heap.
osal_mem_kick();
return ( ZSUCCESS );
}
说明:这里重点是初始化系统任务函数:osalInitTasks(); 下面进入系统任务的初始化:
//----------------------------------------------------------------------------------------------------
2.2 osalInitTasks(); ——任务初始化函数
void osalInitTasks( void )
{
uint8 taskID = 0;
//osal_mem_alloc()为当前OSAL中的各任务分配存储空间(实际上是一个任务数组),函数返回指向任务缓冲
//区的指针,因此tasksEvents指向该任务数组(任务队列).注意tasksEvents和后面谈到的tasksArr[]里的顺
//序是一一对应的, tasksArr[]中的第i个事件处理函数对应于tasksEvents中的第i个任务的事件.
tasksEvents = (uint16 *)osal_mem_alloc(sizeof( uint16 ) * tasksCnt);
//osal_memset()把开辟的内存全部设置为0;sizeof( uint16 )是4个字节,即一个任务
//的长度(同样是uint16定义),乘以任务数量tasksCnt,即全部内存空间
osal_memset( tasksEvents, 0, (sizeof( uint16 ) *tasksCnt)); //OSAL.c中定义
macTaskInit( taskID++); //初始化各层任务 mac_taskID=0;
nwk_init( taskID++); //nwk_taskID=1;
Hal_Init( taskID++); //Hal_taskID=2;
#if defined( MT_TASK )
MT_TaskInit( taskID++); //MT_taskID=3;(if defined)
#endif
APS_Init( taskID++); //APS_taskID=4;
ZDApp_Init( taskID++); //ZDAPP_taskID=5;
SampleApp_Init( taskID ); //SampleApp_taskID=6;用户创建的任务
}
说明:任务初始化,就是为系统的各个任务分配存储空间,当然,这个空间初始化时为全0(NULL),然后为各任务分配taskID;这里的顺序要注意.系统主循环函数里tasksEvents[ idx]和tasksArr[idx]的idx与这里taskID是一一对应关系。后面再分析。
指针数组tasksEvents[]里面最终分别指向的是各任务存储空间
指针数组tasksArr[ ]里面最终分别指向的是各任务事件处理函数
这两个指针数组里面各元素的顺序要一一对应,因为后面需要相应任务调用相应事件处理函数.
对这两个数组的定义请参见后面.
问题:对于osal_mem_alloc()这个函数返回的是一个指向任务数组的指针,看前人分析的,我还没有去看这个函数。
说明:那么这里重点是各任务的初始化,MAC层和NWK层的未开源看不到,先记录下用户自己添加的任务初始化函数SampleApp_Init(taskID );
//----------------------------------------------------------------------------------------------------
2.3 SampleApp_Init( taskID); ——用户应用任务初始化函数
void SampleApp_Init( uint8 task_id)
{
SampleApp_TaskID =task_id; //osal分配的任务ID,这里为6,随着用户添加任务的增多而改变
SampleApp_NwkState =DEV_INIT; //设备状态设定为ZDO层中定义的初始化状态(无连接)
SampleApp_TransID = 0; //消息发送ID(多消息时有顺序之分)
// Device hardware initialization can be added here or in main()(Zmain.c).
// If the hardware is application specific - addit here.
// If the hardware is other parts of the deviceadd it in main().
#if defined ( SOFT_START )
//如果选择了SOFT编译选项,则作为协调器启动
// The "Demo" target is setup tohave SOFT_START and HOLD_AUTO_START
// SOFT_START is a compile option that allowsthe device to start
// as a coordinator ifone isn't found.
// We are looking at a jumper (defined inSampleAppHw.c) to be jumpered
// together - if they are - we will start up acoordinator. Otherwise,
// the device will start as a router.
// if ( readCoordinatorJumper() )
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
//else
//zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // SOFT_START
#if defined ( HOLD_AUTO_START )
//如果定义了HOLD_AUTO_START选项,则调用层的ZDOInitDevice,按照默认顺
//序网络中的第一个设备作为协调器,其他的设备作为子设备
// HOLD_AUTO_START is a compile option that will surpressZDApp
// fromstarting the device and wait for the application to
// startthe device.
ZDOInitDevice(0);
#endif
//---------------------------
//周期消息,广播发送
// Setup for the periodic message's destinationaddress 周期消息事件
// Broadcast to everyone
SampleApp_Periodic_DstAddr.addrMode =(afAddrMode_t)AddrBroadcast ; //发送模式(广播)
SampleApp_Periodic_DstAddr.endPoint =SAMPLEAPP_ENDPOINT; //指定端点号EP20
SampleApp_Periodic_DstAddr.addr.shortAddr =0xFFFF; //指定目的网络地址为广播地址
//--------------------------
//闪烁消息:发送到组
// Setup for the flash command's destinationaddress - Group1 闪烁消息事件
SampleApp_Flash_DstAddr.addrMode =(afAddrMode_t)afAddrGroup; //(组寻址)
SampleApp_Flash_DstAddr.endPoint =SAMPLEAPP_ENDPOINT; //EP20
SampleApp_Flash_DstAddr.addr.shortAddr =SAMPLEAPP_FLASH_GROUP; //组号0x0003
//-------------------------
// Fill out the endpointdescription.
SampleApp_epDesc.endPoint =SAMPLEAPP_ENDPOINT; //SampleApp EP描述符的EP号:20
SampleApp_epDesc.task_id =&SampleApp_TaskID; //SampleAppEP描述符的任务ID:6
SampleApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t*)&SampleApp_SimpleDesc; //SampleApp EP简单描述符
SampleApp_epDesc.latencyReq =noLatencyReqs; //延时策略
// Register the endpoint description with theAF
afRegister(&SampleApp_epDesc );
// Register for all key events -This app will handle all key events
RegisterForKeys( SampleApp_TaskID);
// By default, all devices start out in Group1 为闪烁消息配置的组
SampleApp_Group.ID =0x0003; //组号
osal_memcpy( SampleApp_Group.name, "Group 3",7 ); //设定组名
aps_AddGroup( SAMPLEAPP_ENDPOINT,&SampleApp_Group ); //把该组登记添加到APS中
#if defined ( LCD_SUPPORTED )
//HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1);
Print8(HAL_LCD_LINE_2,20,"SampleApp",1);
#endif
}
说明: 在SampleAPP例子中,应用层提供了节点间两种逻辑关系:一种是周期性消息发送,另一种是Flash消息发送。我个人认为就是两个簇,比如节点1的EP20与节点2的EP20通信,(可以单播,广播,间接,组传递),这两种逻辑关系属于两节点的EP20简单描述符下簇列表元素.且可以看到SampleApp_SendPeriodicMessage( void)与SampleApp_SendFlashMessage()下的clusterID项分别为SAMPLEAPP_PERIODIC_CLUSTERID和SAMPLEAPP_FLASH_CLUSTERID。
用户应用任务初始化大致是:设置本应用发送数据的方式和目的地址寻址模式,登记注册本应用所用到的端点,以及配置相关发送模式所需的参数.
(个人觉得就此应用来说,ZC,ZR,ZD用到的都是EP20,具体以后再作记录)
//----------------------------------------------------------------------------------------------------
以上为OSAL初始化大体流程,OSAL以及各软硬部件初始化完成后,就进入了系统主循环函数osal_start_system();系统主循环流程个人记录见下篇