ble學習筆記九----------ble協議棧之OSAL的執行機理

weixin_30553065發表於2014-10-30

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 );

 

 

轉載於:https://www.cnblogs.com/retacn-yue/p/6194246.html

相關文章