CC2540蓝牙开发二 OSAL系统

前言

简单的运行了下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适用于资源有限的硬件平台,通过遍历事件缓存列表来调度到指定的任务中, 任务间通过可消息来进行通信,对其进行裁剪后可以方便移植到自己的其他应用平台中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值