OSAL初始化流程.docx
《OSAL初始化流程.docx》由会员分享,可在线阅读,更多相关《OSAL初始化流程.docx(19页珍藏版)》请在冰豆网上搜索。
OSAL初始化流程
转载OSAL初始化流程
我使用的协议栈版本及例子信息:
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()
ZSEGintmain(void)//主函数的功能就是完成初始化任务,然后进入OSAL
{
//Turnoffinterrupts
/*关闭中断*/
osal_int_disable(INTS_ALL);
//InitializeHAL
/*初始化硬件*/
HAL_BOARD_INIT();
//Makesuresupplyvoltageishighenoughtorun
/*电压检测,确保芯片能正常工作的电压*/
zmain_vdd_check();
//Initializestackmemory
/*初始化stack存储区*/
zmain_ram_init();
//InitializeboardI/O
/*初始化板载IO*/
InitBoard(OB_COLD);
//InitialzeHALdrivers
/*初始化硬件驱动*/
HalDriverInit();
//InitializeNVSystem
/*初始化NV系统*/
osal_nv_init(NULL);
//Determinetheextendedaddress
/*确定扩展地址(64位IEEE/物理地址)*/
zmain_ext_addr();
//InitializebasicNVitems
/*初始化基本NV条目*/
zgInit();
//InitializetheMAC
/*初始化MAC*/
ZMacInit();
#ifndefNONWK
//SincetheAFisn'tatask,callit'sinitializationroutine
afInit();
#endif
#ifdefLCD_SUPPORTED
HalLcdInit();
#endif
//Initializetheoperatingsystem
/*初始化操作系统*/
osal_init_system();
//Allowinterrupts
/*开启中断*/
osal_int_enable(INTS_ALL);
//Finalboardinitialization
/*最终板载初始化*/
InitBoard(OB_READY);
//HalLcdInit();
//Displayinformationaboutthisdevice
/*显示设备信息*/
zmain_dev_info();
/*DisplaythedeviceinfoontheLCD*/
#ifdefLCD_SUPPORTED
zmain_lcd_init();
#endif
osal_start_system();//NoReturnfromhere没有返回,即进入操作系统!
!
!
}
说明:
初始化各软硬件后进入系统主循环函数。
这里重点是两个函数:
系统初始化函数osal_init_system();系统主循环函数osal_start_system();
下面记录下个人个人对系统初始化流程和系统主循环流程的学习。
这里先记录下系统初始化流程。
//----------------------------------------------------------------------------------------------------
2、系统初始化流程
2.1osal_init_system()——系统初始化函数
byteosal_init_system(void)
{
//InitializetheMemoryAllocationSystem
/*初始化内存分配系统*/
osal_mem_init();
//Initializethemessagequeue
/*初始化系统消息队列*/
osal_qHead=NULL;
#ifdefined(OSAL_TOTAL_MEM)
osal_msg_cnt=0;
#endif
//Initializethetimers
/*初始化定时器*/
osalTimerInit();
//InitializethePowerManagementSystem
/*初始化电源管理系统*/
osal_pwrmgr_init();
//Initializethesystemtasks.
/*初始化系统任务*/
osalInitTasks();//初始化系统任务
//Setupefficientsearchforthefirstfreeblockofheap.
osal_mem_kick();
return(ZSUCCESS);
}
说明:
这里重点是初始化系统任务函数:
osalInitTasks();下面进入系统任务的初始化:
//----------------------------------------------------------------------------------------------------
2.2osalInitTasks();——任务初始化函数
voidosalInitTasks(void)
{
uint8taskID=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;
#ifdefined(MT_TASK)
MT_TaskInit(taskID++);//MT_taskID=3;(ifdefined)
#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.3SampleApp_Init(taskID);——用户应用任务初始化函数
voidSampleApp_Init(uint8task_id)
{
SampleApp_TaskID=task_id;//osal分配的任务ID,这里为6,随着用户添加任务的增多而改变
SampleApp_NwkState=DEV_INIT;//设备状态设定为ZDO层中定义的初始化状态(无连接)
/*初始化应用设备的网络类型,设备类型的改变都要产生一个事件—ZDO_STATE_CHANGE,从字面理解为
//ZDO状态发生了改变。
所以在设备初始化的时候一定要把它初始化为什么状态都没有。
那么它就要去检测
//整个环境,看是否能重新建立或者加入存在的网络。
但是有一种情况例外,就是当NV_RESTORE被设置的
//时候(NV_RESTORE是把信息保存在非易失存储器中),那么当设备断电或者某种意外重启时,由于网络
//状态存储在非易失存储器中,那么此时就只需要恢复其网络状态,而不需要重新建立或者加入网络了*/
SampleApp_TransID=0;//消息发送ID(多消息时有顺序之分)
//Devicehardwareinitializationcanbeaddedhereorinmain()(Zmain.c).
//Ifthehardwareisapplicationspecific-addithere.
//Ifthehardwareisotherpartsofthedeviceadditinmain().
#ifdefined(SOFT_START)
//如果选择了SOFT编译选项,则作为协调器启动
//The"Demo"targetissetuptohaveSOFT_STARTandHOLD_AUTO_START
//SOFT_STARTisacompileoptionthatallowsthedevicetostart
//asacoordinatorifoneisn'tfound.
//Wearelookingatajumper(definedinSampleAppHw.c)tobejumpered
//together-iftheyare-wewillstartupacoordinator.Otherwise,
//thedevicewillstartasarouter.
//if(readCoordinatorJumper())
zgDeviceLogicalType=ZG_DEVICETYPE_COORDINATOR;
//else
//zgDeviceLogicalType=ZG_DEVICETYPE_ROUTER;
#endif//SOFT_START
#ifdefined(HOLD_AUTO_START)
//如果定义了HOLD_AUTO_START选项,则调用层的ZDOInitDevice,按照默认顺
//序网络中的第一个设备作为协调器,其他的设备作为子设备
//HOLD_AUTO_STARTisacompileoptionthatwillsurpressZDApp
//fromstartingthedeviceandwaitfortheapplicationto
//startthedevice.
ZDOInitDevice(0);
#endif
/*设置发送数据的方式和目的地址寻址模式*/
//---------------------------
//周期消息,广播发送
//Setupfortheperiodicmessage'sdestinationaddress周期消息事件
//Broadcasttoeveryone
/*广播到所有设备*/
SampleApp_Periodic_DstAddr.addrMode=(afAddrMode_t)AddrBroadcast;//发送模式(广播)
SampleApp_Periodic_DstAddr.endPoint=SAMPLEAPP_ENDPOINT;//指定端点号EP20
SampleApp_Periodic_DstAddr.addr.shortAddr=0xFFFF;//指定目的网络地址为广播地址
/*单播到一个设备*/
/*WXL_SampleApp_Single_DstAddr.addrMode=(afAddrMode_t)Addr16Bit;;
WXL_SampleApp_Single_DstAddr.endPoint=WXL_SAMPLEAPP_ENDPOINT;*/
//--------------------------
//闪烁消息:
发送到组
//Setupfortheflashcommand'sdestinationaddress-Group1闪烁消息事件
/*设置endpointdescription.*/
SampleApp_Flash_DstAddr.addrMode=(afAddrMode_t)afAddrGroup;//(组寻址)
SampleApp_Flash_DstAddr.endPoint=SAMPLEAPP_ENDPOINT;//EP20
SampleApp_Flash_DstAddr.addr.shortAddr=SAMPLEAPP_FLASH_GROUP;//组号0x0003
//-------------------------
//Fillouttheendpointdescription.
/*定义本设备用来通信的APS层端点描述符*/
SampleApp_epDesc.endPoint=SAMPLEAPP_ENDPOINT;//SampleAppEP描述符的EP号:
20
SampleApp_epDesc.task_id=&SampleApp_TaskID;//SampleAppEP描述符的任务ID:
0
SampleApp_epDesc.simpleDesc
=(SimpleDescriptionFormat_t*)&SampleApp_SimpleDesc;//SampleAppEP简单描述符
SampleApp_epDesc.latencyReq=noLatencyReqs;//延时策略
//RegistertheendpointdescriptionwiththeAF
/*向AF层登记EP描述符*/
/*登记endpointdescription到AF,要对该应用进行初始化并在AF进行登记,告诉应用层有这么一个EP已
经开通可以使用,那么下层要是有关于该应用的信息或者应用要对下层做哪些操作,就自动得到下层的配
合。
*/
afRegister(&SampleApp_epDesc);
//Registerforallkeyevents-Thisappwillhandleallkeyevents
/*登记所有的按键事件*/
RegisterForKeys(SampleApp_TaskID);
//Bydefault,alldevicesstartoutinGroup1为闪烁消息配置的组
/*设定一个新的组*/
SampleApp_Group.ID=0x0003;//组号
osal_memcpy(SampleApp_Group.name,"Group3",7);//设定组名
aps_AddGroup(SAMPLEAPP_ENDPOINT,&SampleApp_Group);//把该组登记添加到APS中
/*如果支持LCD,显示一串字符*/
#ifdefined(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();系统主循环流程个人记录见下篇.
OSAL系统主循环函数:
voidosal_start_system(void)
{
#if!
defined(ZBIT)//不知道是什么
东西
for(;;)//ForeverLoop
#endif
{
uint8idx=0;
Hal_ProcessPoll();//ThisreplacesMT_SerialPoll()andosal_check_timer().
//轮询TIMER与UART
//--------------------------
//执行循环语句:
tasksEvents[idx]是一个指针变量,指向存放任务idx的存储空间,初始化时由
//osal_memset()设为0,只要不为空类型NULL,
//即有相对应任务事件发生,就break跳出循环体,通过下面的程序进行任务事件处理。
//如果为空,执行判断语句,即idx自增,再返回轮询有无各层的任务事件发生。
如果
//执行完循环语句都没有检测到有事件发生,idx=7,进入睡眠。
(对于本例子来说,任务数组里只有七个任务,tasksEvents[0]~tasksEvents[6],tasksEvents[6]就是用户自已添加的任务,idx随着用户添加任务的增多而增大)
do{
if(tasksEvents[idx])//Taskishighestprioritythatisready.
{
break;
}
}while(++idx//-------------------------
if(idx{
uint16events;
halIntState_tintState;//中断位状态
HAL_ENTER_CRITICAL_SECTION(intState);//中断临界状态:
保存先前中断状态,然后关中断
events=tasksEvents[idx];//uint16events;对应有事件发生的任务
tasksEvents[idx]=0;//CleartheEventsforthistask.NULL
HAL_EXIT_CRITICAL_SECTION(intState);//跳出中断临界状态:
恢复先前中断状态
events=(tasksArr[idx])(idx,events);//调用相对应的任务事件处理函数处理,各类事件处理函
//数M(task_id,event)返回的都是这个任务未被处理的事件
HAL_ENTER_CRITICAL_SECTION(intState);
tasksEvents[idx]|=events;//Addbackunprocessedeventstothecurrenttask.
//把刚才返回未处理的任务事件添加加当前任务中再进行处理
//(跳出此if(idx