1、 添加任务
在协议栈中的OSAL.c文件中,byte osal_init_system( void )函数的功能是初始化OS、添加任务到OS任务表中。在这个函数中通过调用osalAddTasks()函数来定制项目所需要应用的任务,该函数属于应用层和OS之间的接口函数,一般项目的建立需要根据系统的需要自己编写改函数,并将函数放到应用层。osalAddTasks()函数是通过osalTaskAdd()函数完成任务添加。
值得注意的是在一个空的协议栈里osalAddTasks()只是在OSAL_Custom.h中申明,并未写出具体操作,需要我们在自己在接口处编写,osalTaskAdd()函数也是自己加进去的
osalTaskAdd()已经不支持,现在用下面的方法添加任务
在协议栈ZStack-CC2430-1.4.3中是这样添加任务的:
1)任务初始化函数的添加
main ()
--->byte osal_init_system( void ) 【OSAL.c】
--->osalInitTasks()【OSAL_SampleApp.c】 //初始化系统任务
---> void SampleApp_Init( uint8 task_id )【SampleApp.c】//应用初始化
2)任务处理函数的流程
首先在任务函数列表中添加处理函数
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK )
MT_ProcessEvent,
#endif
APS_event_loop,
ZDApp_event_loop,
SampleApp_ProcessEvent
};
该列表中处理函数的出现的顺序需要和osalInitTasks()函数中初始化的顺序一致
oid osalInitTasks( void )
{
uint8 taskID = 0;
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
macTaskInit( taskID++ );
nwk_init( taskID++ );
Hal_Init( taskID++ );
#if defined( MT_TASK )
MT_TaskInit( taskID++ );
#endif
APS_Init( taskID++ );
ZDApp_Init( taskID++ );
SampleApp_Init( taskID ); //注意顺序要和pTaskEventHandlerFn中处理函数一致
}
2、 任务初始化--- void SampleApp_Init( uint8 task_id )【SampleApp.c】
命名规则:应用名_init()
初始化内容:
初始化Application Objects对应的变量
相应Application Objects的实例化—afRegister()
注册应用OSAL或HAL系统服务—RegisterForKeys()
/*********************************************************************
* @fn SampleApp_Init
*
* @brief Initialization function for the Generic App Task.
* This is called during initialization and should contain
* any application specific initialization (ie. hardware
* initialization/setup, table initialization, power up
* notificaiton ... ).
*
* @param task_id - the ID assigned by OSAL. This ID should be
* used to send messages and set timers.
*
* @return none
*/
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 ( SOFT_START )
// The "Demo" target is setup to have SOFT_START and HOLD_AUTO_START
// SOFT_START is a compile option that allows the device to start
// as a coordinator if one isn't found.
// 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() )
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
else
zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // SOFT_START
#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);
#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 );
// Register for all key events - This app will handle all key events
RegisterForKeys( SampleApp_TaskID ); //注册按键事件后,按键回调函数将会把OSAl系统事件KEY_CHANGE发送到注册的SampleApp_TaskID
// By default, all devices start out in Group 1
SampleApp_Group.ID = 0x0001;
osal_memcpy( SampleApp_Group.name, "Group 1", 7 );
aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );
#if defined ( LCD_SUPPORTED )
HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );
#endif
}
3、 任务处理---uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )【SampleApp.c】
1)当SampleApp_TaskID对应的OSAL事件发生时,在OSAL的主循环函数会调用该处理函数;
2)SYS_EVENT_MSG是全局系统消息,该消息包含以下消息:
--AF_DATA_CONFIRM_CMD
--AF_INCOMING_MSG_CMD
--KEY_CHANGE
--ZDO_STATE_CHANGE
3)如果一个OSAL任务已经注册为按键按下通知,则任何的按键事件将会以KEY_CHANGE系统事件消息的形式接收。有两种可能的程序流程会使一个任务接收到此KEY_CHANGE
物理层按键的程序流程如下:
--HAL检测按键状态(通过H/W中断或H/W循环检测);
--HAL OSAL任务检测到一个按键状态变化,并调用OSAL按键变化回调函数;
--OSAL按键变化回调函数发送OSAL系统事件消息KEY_CHANGE到通过RegisterForKeys()注册的TaskID
4)TransID 其作用是识别消息,可为每个不同的Endpoint或每个clusterID对应的事件设置一TransID以对其进行区别。
/*********************************************************************
* @fn SampleApp_ProcessEvent
*
* @brief Generic Application Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The OSAL assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return none
*/
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); //从OS的消息队列中接收一个消息
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
// Received when a key is pressed
case KEY_CHANGE:
SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys ); //按键处理函数
break;
// Received when a messages is received (OTA) for this endpoint
case AF_INCOMING_MSG_CMD:
SampleApp_MessageMSGCB( MSGpkt ); //对于接收消息的节点,将执行此函数
break;