Zigbee学习-添加一个简单应用到OSAL中
来源:互联网 发布:程序员创业知乎 编辑:程序博客网 时间:2024/05/16 09:45
Zstack是Zigbee协议的代码实现,本次总结我在学习TI在51内核上开发的Zstack,由于zigbee栈实现起来非常复杂而困难,因此在本Zstack中引入了操作系统-OSAL,用来协调、调度各个任务,本篇将总结SampleApp在OSAL中的初始化及任务轮训的实现机制。当系统上电后,开始执行Zmian中的main函数,如下:
int main( void ){ // Turn off interrupts osal_int_disable( INTS_ALL ); //关闭所有中断 // Initialization for board related stuff such as LEDs HAL_BOARD_INIT(); //初始化系统时钟 // Make sure supply voltage is high enough to run zmain_vdd_check(); //检查芯片电压是否正常 // Initialize board I/O InitBoard( OB_COLD ); //初始化I/O ,LED 、Timer 等 // Initialze HAL drivers HalDriverInit(); //初始化芯片各硬件模块 // Initialize NV System osal_nv_init( NULL ); //初始化Flash 存储器 // Initialize the MAC ZMacInit(); //初始化MAC 层 // Determine the extended address zmain_ext_addr(); //确定IEEE 64位地址 // Initialize basic NV items zgInit(); //初始化非易失变量#ifndef NONWK // Since the AF isn't a task, call it's initialization routine afInit();#endif // Initialize the operating system <span style="color: rgb(255, 0, 0);">osal_init_system(); //初始化操作系统</span> // Allow interrupts osal_int_enable( INTS_ALL ); //使能全部中断 // Final board initialization InitBoard( OB_READY ); //最终板载初始化 // Display information about this device zmain_dev_info(); //显示设备信息 /* Display the device info on the LCD */#ifdef LCD_SUPPORTED zmain_lcd_init(); //初始化LCD#endifosalInitTasks(); #ifdef WDT_IN_PM1 /* If WDT is used, this is a good place to enable it. */ WatchDogEnable( WDTIMX );#endif <span style="color:#ff0000;">osal_start_system(); // No Return from here 执行操作系统,进去后不会返回</span> return 0; // Shouldn't get here.} // main()
其中红色标注osal_init_system()及osal_start_system()需要特别注意,其中osal_start_system()为启动操作系统(后面有介绍),而osal_init_system()为操作系统的初始化操作,其源代码如下:
uint8 osal_init_system( void ){ // Initialize the Memory Allocation System osal_mem_init(); // Initialize the message queue osal_qHead = NULL; // Initialize the timers osalTimerInit(); // Initialize the Power Management System osal_pwrmgr_init(); // Initialize the system tasks. <span style="color:#ff0000;"> osalInitTasks(); </span> // Setup efficient search for the first free block of heap. osal_mem_kick(); return ( SUCCESS );}如上,操作系统的初始化包含了内存、消息队列、电源管理、任务队列等,其中我们需要特别关注红色标注的osalInitTasks(),此函数负责初始化系统任务,我们所写SampleApp任务在此函数内被初始化,源码如下:
void osalInitTasks( void ){ uint8 taskID = 0; // 分配内存,返回指向缓冲区的指针 tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt); // 设置所分配的内存空间单元值为0 osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt)); // 任务优先级由高向低依次排列,高优先级对应taskID 的值反而小 macTaskInit( taskID++ ); //macTaskInit(0) ,用户不需考虑 nwk_init( taskID++ ); //nwk_init(1),用户不需考虑 Hal_Init( taskID++ ); //Hal_Init(2) ,用户需考虑#if defined( MT_TASK ) MT_TaskInit( taskID++ );#endif APS_Init( taskID++ ); //APS_Init(3) ,用户不需考虑#if defined ( ZIGBEE_FRAGMENTATION ) APSF_Init( taskID++ );#endif ZDApp_Init( taskID++ ); //ZDApp_Init(4) ,用户需考虑#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT ) ZDNwkMgr_Init( taskID++ );#endif //用户创建的任务 <span style="color:#ff0000;">SampleApp_Init( taskID ); </span> // SampleApp_Init _Init(5) ,用户需考虑}
红色标注部分是我们必须要写的,其中taskID为任务编号,升序排列,越大优先级越低,当初始化完任务后,操作系统启动后会不停查询任务事件,并根据taskID进行基于优先级的区别处理,在本次应用中其代码如下:
void SampleApp_Init( uint8 task_id ){ SampleApp_TaskID = task_id; //osal分配的任务ID随着用户添加任务的增多而改变 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 - add it here. // If the hardware is other parts of the device add it in main(). #if defined ( BUILD_ALL_DEVICES ) // The "Demo" 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() ) zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR; else zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;#endif // BUILD_ALL_DEVICES//该段的意思是,如果设置了HOLD_AUTO_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; //指定端点号:20 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; //指定端点号:20,1~240 SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;//组号0x0001 // Fill out the endpoint description. 定义本设备用来通信的APS层端点描述符 SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; //指定端点号:20 SampleApp_epDesc.task_id = &SampleApp_TaskID; //SampleApp 描述符的任务ID SampleApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;//SampleApp简单描述符 SampleApp_epDesc.latencyReq = noLatencyReqs; //延时策略<span style="color:#ff0000;"> // 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 ); // 登记所有的按键事件</span> // 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 );//把该组登记添加到APS中#if defined ( LCD_SUPPORTED ) HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 ); //如果支持LCD,显示提示信息#endif}如上,红色标注部分依然是我们需要特别注意的,afRegister( &SampleApp_epDesc )该函数将endpoint注册至AF(即Aapplication Frame)层,该层负责管理端点进行数据传输;而RegisterForKeys( SampleApp_TaskID )是将所有的按键事件注册绑定到我们SampleApp中,注册后当有按键事件发生时,可以在系统的任务轮询中进入SampleApp的时间相应函数中,在本应用中该函数为SampleApp_ProcessEvent( uint8 task_id, uint16 events );
操作系统的启动由osal_start_system()函数负责,该函数为整个上电启动过程最后的操作,进入该函数后会不停查询处理任务事件,该函数原型如下:
void osal_start_system( void ){#if !defined ( ZBIT ) && !defined ( UBIT ) for(;;) // Forever Loop#endif { uint8 idx = 0; osalTimeUpdate(); //扫描哪个事件被触发了,然后置相应的标志位 Hal_ProcessPoll(); //轮询TIMER与UART This replaces MT_SerialPoll() and osal_check_timer(). do { if (tasksEvents[idx]) // Task is highest priority that is ready. { break; //得到待处理的最高优先级任务索引号 idx } } while (++idx < tasksCnt); if (idx < tasksCnt) { uint16 events; halIntState_t intState; HAL_ENTER_CRITICAL_SECTION(intState);// 进入临界区,保护 events = tasksEvents[idx]; //提取需要处理的任务中的事件 tasksEvents[idx] = 0; //清除本次任务的事件 HAL_EXIT_CRITICAL_SECTION(intState); // 退出临界区 <span style="color:#ff0000;"> events = (tasksArr[idx])( idx, events )</span>;//通过指针调用任务处理函数,关键,其中sampleAPP的处理函数即从此处调用 HAL_ENTER_CRITICAL_SECTION(intState); //进入临界区 tasksEvents[idx] |= events; // 保存未处理的事件 Add back unprocessed events to the current task. HAL_EXIT_CRITICAL_SECTION(intState); // 退出临界区 }#if defined( POWER_SAVING ) else // Complete pass through all task events with no activity? { osal_pwrmgr_powerconserve(); // Put the processor/system into sleep }#endif }}如上,该函数为不断轮训任务时间,并根据任务ID进行处理(红色标注部分),跟踪tasksArr[idx]发现其被赋值如下:
const pTaskEventHandlerFn tasksArr[] = { macEventLoop, 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 <span style="color:#ff0000;">SampleApp_ProcessEvent</span>};其中 SampleApp_ProcessEvent为我们自定义应用事件处理函数,函数名可自定义,在本次应用中该函数的原型如下:
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ){ afIncomingMSGPacket_t *MSGpkt; (void)task_id; // Intentionally unreferenced parameter if ( events & SYS_EVENT_MSG ) //接收系统消息再进行判断 { //接收属于本应用任务SampleApp的消息,以SampleApp_TaskID标记 MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); while ( MSGpkt ) { switch ( MSGpkt->hdr.event ) { // Received when a key is pressed case <span style="color:#ff0000;">KEY_CHANGE</span>://按键事件 HalLedBlink(HAL_LED_2, 0, 50, 200);//如果是则Led1间隔200ms闪烁 SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys ); break; // Received when a messages is received (OTA) for this endpoint case <span style="color:#ff0000;">AF_INCOMING_MSG_CMD:</span>//接收数据事件,调用函数AF_DataRequest()接收数据 SampleApp_MessageMSGCB( MSGpkt );//调用回调函数对收到的数据进行处理 break; // Received whenever the device changes state in the network case <span style="color:#ff0000;">ZDO_STATE_CHANGE:</span> //只要网络状态发生改变,就通过ZDO_STATE_CHANGE事件通知所有的任务。 //同时完成对协调器,路由器,终端的设置 SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //if ( (SampleApp_NwkState == DEV_ZB_COORD)//实验中协调器只接收数据所以取消发送事件 if ( (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; default: break; } // Release the memory 事件处理完了,释放消息占用的内存 osal_msg_deallocate( (uint8 *)MSGpkt ); // Next - if one is available 指针指向下一个放在缓冲区的待处理的事件, //返回while ( MSGpkt )重新处理事件,直到缓冲区没有等待处理事件为止 MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); } // return unprocessed events 返回未处理的事件 return (events ^ SYS_EVENT_MSG); }如上,红色标注部分为事件类型,当系统发生该类事件时,会进入该函数,部分事件需要注册,如KEY_CHANGE事件;
暂歇一会,明天继续,,,,,,
0 0
- Zigbee学习-添加一个简单应用到OSAL中
- zigbee中OSAL中的task ,event, message
- zigbee学习一OSAL运行方式的理解和简单组网实验
- Zigbee协议栈中OSAL的运行机理
- ZIGBEE--OSAL调度机制
- zigbee OSAL NV操作
- ZigBee-OSAL初始化流程
- zigbee 2:OSAL概要
- ZigBee OSAL流程分析
- zigbee学习笔记--电源管理OSAL机制的ZigBee低功耗管理(CC2530)
- zigbee学习笔记--电源管理OSAL机制的ZigBee低功耗管理(CC2530)
- Android:如何把一个应用添加到Settings列表中...
- Zigbee学习之创建自己的简单应用
- ZigBee OSAL NV 区操作
- ZigBee-OSAL主循环流程
- Zigbee中添加用户任务
- ZigBee学习之7——OSAL(操作系统抽象层)API解读
- POI简单应用,实现将测试结果添加到Excel中
- 吐槽!!!
- Guarded Blocks 保护块
- 关于常量指针、指针常量等
- 活性(Liveness)
- Java web 学习笔记 Html CSS 小节
- Zigbee学习-添加一个简单应用到OSAL中
- IOS 之 多态
- asp.net mvc 的webApi (一)自己手动创建
- 内在锁和同步
- 【剑指offer】面试题24:二叉搜索树的后续前序遍历序列
- 深刻理解Nginx之Nginx与Python(1)
- 在VS2005中添加成员变量
- 原子访问(Atomic Access)
- nand2tetris【5】