zoukankan      html  css  js  c++  java
  • ble学习笔记九----------ble协议栈之OSAL的运行机理

    OSAL的运行机理

     

    事件表

    函数表

    使用查表法来取得事件所对应函数 

     

    taskCnt  任务总数

    taskEvents 指向事件表首地址的指针

    taskArr 事件处理函数数组,每一项都是一个函数指针

    由此可以看出,osal是一种基于事件驱动 的轮询式操作系统

    在使用共享变量时需要保证变量不被其他变量访问,常用关中断的方法,示例

    OSAL.C文件的osal_start_system()方法中可以看到

     HAL_ENTER_CRITICAL_SECTION(intState);//关中断

      ....

     HAL_EXIT_CRITICAL_SECTION(intState);//恢复中断

    //osal_start_system()函数的示例代码如下:

    void osal_start_system( void )

    {

       for(;;)  // Forever Loop

       {

        osal_run_system();

      }

    }

    osal_run_system()函数的示例代码如下:

    void osal_run_system( void )

    {

      /*事件表中索引*/

      uint8 idx = 0;

    #ifndef HAL_BOARD_CC2538

      /*更新定时器*/

      osalTimeUpdate();

    #endif

      /*查看硬件方法是否有事件发生*/

      Hal_ProcessPoll();

      

      /*循环查看事件表是否有事件发生 */

      /*每个二进制位表示一个事件*/

      do {

        if (tasksEvents[idx])  // Task is highest priority that is ready.

        {

          break;

        }

      } while (++idx < tasksCnt);

      if (idx < tasksCnt)

      {

        uint16 events;

        halIntState_t intState;

        HAL_ENTER_CRITICAL_SECTION(intState);

        /*读取事件*/

        events = tasksEvents[idx];

        /*事件标志清零*/

        tasksEvents[idx] = 0;  // Clear the Events for this task.

        HAL_EXIT_CRITICAL_SECTION(intState);

        /*调用事件处理函数处理*/

        activeTaskID = idx;

        events = (tasksArr[idx])( idx, events );

        activeTaskID = TASK_NO_TASK;

        HAL_ENTER_CRITICAL_SECTION(intState);

        /*将未处理的事件重新放到事件表中*/

        /*如何在事件处理函数中返回未处理事件?*/

        /*SimpleBLEPeripheral_ProcessEvent*/

        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

      /* Yield in case cooperative scheduling is being used. */

    #if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)

      {

        osal_task_yield();

      }

    #endif

    }

    如何在事件处理函数中返回未处理的事件

    查看SimpleBLEPeripheral.c文件中的SimpleBLEPeripheral_ProcessEvent()函数,原型如下

    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

        /*设置定时时间,到时后周期事件的任务id被置起*/

        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;

    }

    OSAL消息队列

    事件+外设数据组装成消息----->存放到消息队列--->事件处理函数从消息队列中读取消息k



    osal.h文件中定义了消息头,示例代码如下:

    typedef struct

    {

      uint8  event;

      uint8  status;

    } osal_event_hdr_t;

    OSAL添加新任务

    OSAL_SimpleBLEPeripheral.c文件中可以看到:

    tasksArr[]  存放所有任务的事件处理函数的地址

    osalInitTasks() 任务初始化函数,给每一个任务分配id 

    添加新任务的操作:

    新任务的初始化函数

    const pTaskEventHandlerFn tasksArr[] =

    {

      LL_ProcessEvent,                                                  // task 0

      Hal_ProcessEvent,                                                 // task 1

      HCI_ProcessEvent,                                                 // task 2

    #if defined ( OSAL_CBTIMER_NUM_TASKS )

      OSAL_CBTIMER_PROCESS_EVENT( osal_CbTimerProcessEvent ),           // task 3

    #endif

      L2CAP_ProcessEvent,                                               // task 4

      GAP_ProcessEvent,                                                 // task 5

      GATT_ProcessEvent,                                                // task 6

      SM_ProcessEvent,                                                  // task 7

      GAPRole_ProcessEvent,                                             // task 8

      GAPBondMgr_ProcessEvent,                                          // task 9

      GATTServApp_ProcessEvent,                                         // task 10

      SimpleBLEPeripheral_ProcessEvent                                  // task 11

    };

    新任务的事件处理函数

    void osalInitTasks( void )

    {

      uint8 taskID = 0;

      tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);

      osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

      /* 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++ );

      /* GATT Task */

      GATT_Init( taskID++ );

      /* SM Task */

      SM_Init( taskID++ );

      /* Profiles */

      GAPRole_Init( taskID++ );

      GAPBondMgr_Init( taskID++ );

      GATTServApp_Init( taskID++ );

      /* Application */

      SimpleBLEPeripheral_Init( taskID );

    }

    :

    1 tassArr[]数组里各事件处理函数的排列顺序要与osalInitTasks()函数中调用各任务初

    始化函数的顺序保持一致

    2 osalInitTasks()分配的id .需要任务定义一个全局变量来保存

    OSAL应用编程接口 

    消息管理

    任务同步

    时间管理

    中断管理

    任务管理

    内存管理

    电源管理

    非易失性闪存管理

    消处管理接口的定义在osal.h文件中可以看到,示例代码如下:

    /*** Message Management ***/

    /***  消息管理API ***/

      /*

       * Task Message Allocation

       * 为消息分配缓存空间

       */

      extern uint8 * osal_msg_allocate(uint16 len );

      /*

       * Task Message Deallocation

       * 为消息释放缓存空间

       */

      extern uint8 osal_msg_deallocate( uint8 *msg_ptr );

      /*

       * Send a Task Message

       * 任务发送消息到消息队列

       */

      extern uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr );

      /*

       * Push a Task Message to head of queue

       * 将任务消息压入栈顶

       */

      extern uint8 osal_msg_push_front( uint8 destination_task, uint8 *msg_ptr );

      /*

       * Receive a Task Message

       * 任务从消息队列中读取属于自已的消息

       */

      extern uint8 *osal_msg_receive( uint8 task_id );

      /*

       * Find in place a matching Task Message / Event.

       */

      extern osal_event_hdr_t *osal_msg_find(uint8 task_id, uint8 event);

      /*

       * Enqueue a Task Message

       */

      extern void osal_msg_enqueue( osal_msg_q_t *q_ptr, void *msg_ptr );

      /*

       * Enqueue a Task Message Up to Max

       */

      extern uint8 osal_msg_enqueue_max( osal_msg_q_t *q_ptr, void *msg_ptr, uint8 max );

      /*

       * Dequeue a Task Message

       */

      extern void *osal_msg_dequeue( osal_msg_q_t *q_ptr );

      /*

       * Push a Task Message to head of queue

       */

      extern void osal_msg_push( osal_msg_q_t *q_ptr, void *msg_ptr );

      /*

       * Extract and remove a Task Message from queue

       */

      extern void osal_msg_extract( osal_msg_q_t *q_ptr, void *msg_ptr, void *prev_ptr );

    任务同步管理接口 在文件OSAL.h中定义,示例代码如下:

    /*** Task Synchronization  ***/

      /*

       * Set a Task Event

       * 设置任务事件

       */

      extern uint8 osal_set_event( uint8 task_id, uint16 event_flag );

      /*

       * Clear a Task Event

       * 清除任务事件

       */

      extern uint8 osal_clear_event( uint8 task_id, uint16 event_flag );

    时间管理接口 在文件OSAL_Timers.h中定义,示例代码如下:

     /*

       * Initialization for the OSAL Timer System.

       */

      extern void osalTimerInit( void );

      /*

       * Set a Timer

       * 设置定时时间,到时后,相应事件被设置

       */

      extern uint8 osal_start_timerEx( uint8 task_id, uint16 event_id, uint32 timeout_value );

      

      /*

       * Set a timer that reloads itself.

       */

      extern uint8 osal_start_reload_timer( uint8 taskID, uint16 event_id, uint32 timeout_value );

      /*

       * Stop a Timer

       * 停止定时器

       */

      extern uint8 osal_stop_timerEx( uint8 task_id, uint16 event_id );

      /*

       * Get the tick count of a Timer.

       */

      extern uint32 osal_get_timeoutEx( uint8 task_id, uint16 event_id );

      /*

       * Simulated Timer Interrupt Service Routine

       */

      extern void osal_timer_ISR( void );

      /*

       * Adjust timer tables

       */

      extern void osal_adjust_timers( void );

      /*

       * Update timer tables

       */

      extern void osalTimerUpdate( uint32 updateTime );

      /*

       * Count active timers

       */

      extern uint8 osal_timer_num_active( void );

      /*

       * Set the hardware timer interrupts for sleep mode.

       * These functions should only be called in OSAL_PwrMgr.c

       */

      extern void osal_sleep_timers( void );

      extern void osal_unsleep_timers( void );

     /*

      * Read the system clock - returns milliseconds

      */

      extern uint32 osal_GetSystemClock( void );

      /*

       * Get the next OSAL timer expiration.

       * This function should only be called in OSAL_PwrMgr.c

       */

      extern uint32 osal_next_timeout( void );

    中断管理接口 定义在soal.h文件中,示例代码如下:

    /*** Interrupt Management  ***/

      /*

       * Register Interrupt Service Routine (ISR)

       */

      extern uint8 osal_isr_register( uint8 interrupt_id, void (*isr_ptr)( uint8* ) );

      /*

       * Enable Interrupt

       * 开启中断

       */

      extern uint8 osal_int_enable( uint8 interrupt_id );

      /*

       * Disable Interrupt

       * 关闭中断

       */

      extern uint8 osal_int_disable( uint8 interrupt_id );

    任务管理接口 定义在soal.h文件中,

    /*** Task Management  ***/

      /*

       * Initialize the Task System

       * 初始化osal,第一个被调用的函数

       */

      extern uint8 osal_init_system( void );

      /*

       * System Processing Loop

       */

    #if defined (ZBIT)

      extern __declspec(dllexport)  void osal_start_system( void );

    #else

      /*包含一个无限循环,查询事件,执行处理函数,*/

      extern void osal_start_system( void );

    #endif

      /*

       * One Pass Throu the OSAL Processing Loop

       */

      extern void osal_run_system( void );

      /*

       * Get the active task ID

       * 取得任务id

       */

      extern uint8 osal_self( void );

    内存管理接口,定义在OSAL_Memory.h文件中定义

    /*

      * Initialize memory manager.

      */

      void osal_mem_init( void );

     /*

      * Setup efficient search for the first free block of heap.

      */

      void osal_mem_kick( void );

     /*

      * Allocate a block of memory.

      */

    #ifdef DPRINTF_OSALHEAPTRACE

      void *osal_mem_alloc_dbg( uint16 size, const char *fname, unsigned lnum );

    #define osal_mem_alloc(_size ) osal_mem_alloc_dbg(_size, __FILE__, __LINE__)

    #else /* DPRINTF_OSALHEAPTRACE */

      /*分配指定大小的缓冲区*/

      void *osal_mem_alloc( uint16 size );

    #endif /* DPRINTF_OSALHEAPTRACE */

     /*

      * Free a block of memory.

      */

    #ifdef DPRINTF_OSALHEAPTRACE

      void osal_mem_free_dbg( void *ptr, const char *fname, unsigned lnum );

    #define osal_mem_free(_ptr ) osal_mem_free_dbg(_ptr, __FILE__, __LINE__)

    #else /* DPRINTF_OSALHEAPTRACE */

      /*释放分配的缓冲区*/

      void osal_mem_free( void *ptr );

    #endif /* DPRINTF_OSALHEAPTRACE */

    #if ( OSALMEM_METRICS )

     /*

      * Return the maximum number of blocks ever allocated at once.

      */

      uint16 osal_heap_block_max( void );

     /*

      * Return the current number of blocks now allocated.

      */

      uint16 osal_heap_block_cnt( void );

     /*

      * Return the current number of free blocks.

      */

      uint16 osal_heap_block_free( void );

     /*

      * Return the current number of bytes allocated.

      */

      uint16 osal_heap_mem_used( void );

    #endif

    #if defined (ZTOOL_P1) || defined (ZTOOL_P2)

     /*

      * Return the highest number of bytes ever used in the heap.

      */

      uint16 osal_heap_high_water( void );

    #endif


    电源管理接口,定义在OSAL_PwrMgr.h文件中,示例代码如下

      /*

       * Initialize the power management system.

       *   This function is called from OSAL.

       *

       */

      extern void osal_pwrmgr_init( void );

      /*

       * This function is called by each task to state whether or not this

       * task wants to conserve power. The task will call this function to

       * vote whether it wants the OSAL to conserve power or it wants to

       * hold off on the power savings. By default, when a task is created,

       * its own power state is set to conserve. If the task always wants

       * to converse power, it doesn't need to call this function at all.

       * It is important for the task that changed the power manager task

       * state to PWRMGR_HOLD to switch back to PWRMGR_CONSERVE when the

       * hold period ends.

       */

      extern uint8 osal_pwrmgr_task_state( uint8 task_id, uint8 state );

      /*

       * This function is called on power-up, whenever the device characteristic

       * change (ex. Battery backed coordinator). This function works with the timer

       * to set HAL's power manager sleep state when power saving is entered.

       * This function should be called form HAL initialization. After power up

       * initialization, it should only be called from NWK or ZDO.

       */

      extern void osal_pwrmgr_device( uint8 pwrmgr_device );

      /*

       * This function is called from the main OSAL loop when there are

       * no events scheduled and shouldn't be called from anywhere else.

       */

      extern void osal_pwrmgr_powerconserve( void );

    非易失性闪存管理接口 定义没找到????????????

    static uint8  initNV( void );

    static void   setActivePage( uint8 pg );

    static void   setXferPage(void);

    static void   erasePage( uint8 pg );

    static void   cleanErasedPage( uint8 pg );

    static void   findOffset( void );

    static void   compactPage( uint8 pg );

    static void   writeWord( uint8 pg, uint16 offset, uint8 *pBuf );

    static void   writeWordM( uint8 pg, uint16 offset, uint8 *pBuf, osalSnvLen_t cnt );

  • 相关阅读:
    用Darwin和live555实现的直播框架
    用Darwin和live555实现的直播框架
    VS2010 C++编译报错LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
    VS2010编译和运行项目错误
    C#如何使用VS2010与SQL2008建立链接及初步调用(转)
    linQ to sql 查询生成的sql语句
    查看Linq to Sql生成的sql语句(转)
    linq to sql 项目移植后,数据库实体类需要重新创建?
    什么是Asp.net Core?和 .net core有什么区别?(转)
    ASP.NET Core 2.0 使用支付宝PC网站支付实现代码(转)
  • 原文地址:https://www.cnblogs.com/retacn-yue/p/6194246.html
Copyright © 2011-2022 走看看