前言
简朴的运行了下2540的蓝牙Demo,为了应用能顺利跑起来,还需要相识OSAL系统的机制和原理
如有异议,接待留言指正
概述
OSAL 操纵系统抽象层 (Operating System Abstraction Layer),一种类多任务运行的系统资源分配机制,并不是真正意义上的操纵调治系统,但是上层抽象出的API接口对应用开发者比力友好,而且占用资源较少,适用于资源极其有限的硬件平台
框架
OSAL提供调治、内存管理和消息通报功能;HAL提供了对硬件层抽象的访问,将软件层与硬件层举行关联,方便移植
流程
事件可以由中断或其他任务中举行触发,被需要处理惩罚事件的任务获取执行;事件触发后可附带消息体举行数据通报交互
代码解读
初始化事件任务
- 在主函数 main() 中会调用osalInitTasks举行任务初始化,内部为任务各自维护的初始化函数,自定义新增的任务也可以在此函数内举行初始化
- void osalInitTasks( void ){ uint8 taskID = 0; tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt); //开发事件缓存2 * tasksCnt /* The tasksEvents allocated pointer must be valid */ if (tasksEvents != NULL) { osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));//清除事件缓存 } else { HAL_ASSERT_FORCED(); } /* LL Task */ LL_Init( taskID++ ); /* Hal Task */ Hal_Init( taskID++ ); /* HCI Task */ HCI_Init( taskID++ );#if defined ( OSAL_CBTIMER_NUM_TASKS ) /* Callback Timer Tasks */ osal_CbTimerInit( taskID ); taskID += OSAL_CBTIMER_NUM_TASKS;#endif /* L2CAP Task */ L2CAP_Init( taskID++ ); /* GAP Task */ GAP_Init( taskID++ ); /* SM Task */ SM_Init( taskID++ ); /* GATT Task */ GATT_Init( taskID++ ); /* Profiles */ GAPRole_Init( taskID++ ); GAPBondMgr_Init( taskID++ ); GATTServApp_Init( taskID++ ); /* Application */ SimpleBLEPeripheral_Init( taskID );}
复制代码 启动OSAL
简化了未生效的预编译
- osal_start_system:OSAL启动函数,在for循环中执行osal_run_system()
- void osal_start_system( void ){ for(;;) // Forever Loop { osal_run_system(); //osal运行系统 }}
复制代码 任务事件管理
- 根据tasksEvents来判断是否有事件,序号idx从0开始遍历,所以tasksArr函数指针数组中靠前的任务优先级较高;const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );与任务事件表长度对应
- tasksEvents开发的缓存中,为每个任务分配了两个字节(与任务偏移序号一一对应),每个bit代表一个事件(每个任务支持最大16个事件),非0则体现存在需要处理惩罚的事件
- void osal_run_system( void ){ uint8 idx = 0; do { if (tasksEvents[idx]) // 从高优先级判断是否有事件 { break; } } 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);//开中断 activeTaskID = idx; //生效任务标志,在osal内部使用 events = (tasksArr[idx])( idx, events );//执行对应事件的任务函数 activeTaskID = TASK_NO_TASK;//执行完成 失效任务标志 HAL_ENTER_CRITICAL_SECTION(intState);//关中断 tasksEvents[idx] |= events; // 增加任务返回的事件 HAL_EXIT_CRITICAL_SECTION(intState);//开中断 }}
复制代码 应用任务
在SimpleBle工程中自定义了两个事件
- 设备启动事件(SBP_START_DEVICE_EVT):用于蓝牙启动想要执行的操纵(蓝牙状态回调);
- 周期性定时事件(SBP_PERIODIC_EVT):定时处理惩罚事件
- // Simple BLE Peripheral Task Events#define SBP_START_DEVICE_EVT 0x0001 //设备启动事件#define SBP_PERIODIC_EVT 0x0002 //周期性定时事件
复制代码 工程协议栈中定义了全局的事件 SYS_EVENT_MSG,固定为0x8000
- uint16 SimpleBLEPeripheral_ProcessEvent( uint8 task_id, uint16 events ){ VOID task_id; // OSAL required parameter that isn't used in this function if ( events & SYS_EVENT_MSG ) // 系统自带的全局事件 { uint8 *pMsg;//吸收消息指针 if ( (pMsg = osal_msg_receive( simpleBLEPeripheral_TaskID )) != NULL )//读取缓存数据 { simpleBLEPeripheral_ProcessOSALMsg( (osal_event_hdr_t *)pMsg );//处理惩罚数据 // Release the OSAL message VOID osal_msg_deallocate( pMsg );//释放数据缓存资源 } // return unprocessed events return (events ^ SYS_EVENT_MSG);//清除当前执行事件,返回未处理惩罚事件 } if ( events & SBP_START_DEVICE_EVT )//启动事件 { // Start the Device VOID GAPRole_StartDevice( &simpleBLEPeripheral_PeripheralCBs );//设备启动 // Start Bond Manager VOID GAPBondMgr_Register( &simpleBLEPeripheral_BondMgrCBs );//注册绑定回调 // Set timer for first periodic event osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );//启动周期事件 return ( events ^ SBP_START_DEVICE_EVT );//清除当前执行事件,返回未处理惩罚事件 } if ( events & SBP_PERIODIC_EVT )//周期事件 { // Restart timer if ( SBP_PERIODIC_EVT_PERIOD )//时间有效 { osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );//每次生效后需要重新启动 } // Perform periodic application task performPeriodicTask();//定时处理惩罚的任务 return (events ^ SBP_PERIODIC_EVT);//清除当前执行事件,返回未处理惩罚事件 } // Discard unknown events return 0; //无事件返回0}
复制代码 消息收发
任务间需要有数据交互时,可以使用消息机制举行数据收发
- 系统使用了堆空间分配的方法,在TSK1任务一中开发缓存存储需要发送的数据,TSK2任务二吸收到消息处理惩罚完成后举行释放,通过指针所在的方式举行通报
消息发送接口:uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr ),内部会自动触发SYS_EVENT_MSG系统事件
- destination_task :任务id,系统初始化时唯一分配
- msg_ptr:消息缓存
截取一段按键消息发送的例子
- 消息的数据布局可以参考按键消息的数据布局举行修改,必须指定通报给的任务Id
- uint8 OnBoard_SendKeys( uint8 keys, uint8 state ){ keyChange_t *msgPtr; if ( registeredKeysTaskID != NO_TASK_ID ) { // Send the address to the task msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) ); //分配消息缓存,数据布局可自定义 if ( msgPtr ) { msgPtr->hdr.event = KEY_CHANGE;//消息类型 msgPtr->state = state; msgPtr->keys = keys; osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr ); //发送消息 } return ( SUCCESS ); } else return ( FAILURE );}
复制代码 消息吸收接口:uint8 *osal_msg_receive( uint8 task_id )匹配任务Id乐成后返回吸收到的消息缓存所在,数据调用完成后必须释放,否则会出现内存泄漏
- if ( events & SYS_EVENT_MSG ) // 系统自带的全局事件{ uint8 *pMsg; if ( (pMsg = osal_msg_receive( simpleBLEPeripheral_TaskID )) != NULL )//读取缓存数据 { simpleBLEPeripheral_ProcessOSALMsg( (osal_event_hdr_t *)pMsg );//处理惩罚数据 // Release the OSAL message VOID osal_msg_deallocate( pMsg );//释放数据缓存资源 } // return unprocessed events return (events ^ SYS_EVENT_MSG);//清除当前执行事件,返回未处理惩罚事件}
复制代码 事件发送函数:uint8 osal_set_event( uint8 task_id, uint16 event_flag )可以自定义事件并调取该接口触发事件任务
消息数据通报机制:osal系统通过单链表的方式举行对消息缓存的增删管理
- typedef struct{ void *next; #ifdef OSAL_PORT2TIRTOS /* Limited OSAL port to TI-RTOS requires compatibility with ROM * code compiled with USE_ICALL compile flag. */ uint32 reserved; #endif /* OSAL_PORT2TIRTOS */ uint16 len; uint8 dest_id;} osal_msg_hdr_t;#endif /* USE_ICALL */
复制代码 总结
OSAL适用于资源有限的硬件平台,通过遍历事件缓存列表来调治到指定的任务中, 任务间通过可消息来举行通信,对其举行裁剪后可以方便移植到自己的其他应用平台中
来源:https://blog.csdn.net/libin55/article/details/111942621
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |