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
新增新任務的操作:
1 新任務的初始化函式
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
};
2 新任務的事件處理函式
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 );