CC254x--OSAL
OSAL運行原理
藍牙協(xié)議棧PROFILE、所有的應用程序、驅(qū)動等都是圍繞著OSAL組織運行的。OSAL(Operating System Abstraction Layer)操作系統(tǒng)抽象層,它不是一個真正的操作系統(tǒng)(它沒有 Context Switch 上下文切換功能),但它巧妙地組織各任務,支持任務優(yōu)先級,任務之間可以通過事件和消息來通信,為任務提供軟定時器和動態(tài)內(nèi)存分配。要避免的陷阱是,應用任務的單個函數(shù)運行時間不能太長 (如操作大批量數(shù)據(jù)的 Flash 寫),否則它無法及時調(diào)度高優(yōu)先級的 LL(Link Layer)任務而導致藍牙通信中斷。
OSAL 為每一個任務函數(shù)分配了一個 16 位的EVENT 事件,每一位代表一個事件,其中最高位代表的事件為 SYS_EVENT_MSG,這個事件被 OSAL 系統(tǒng)保留,其他的 15 位可以由用戶定義,OSAL 在主循環(huán)里運行每次都會檢查每個任務函數(shù)的是否有事件發(fā)生(事件置位),如果有事件發(fā)生,將通過 taskid 來調(diào)用發(fā)生事件的任務函數(shù),并將發(fā)生的事件傳遞到該函數(shù)中去,由任務函數(shù)處理對應的事件。
為什么要將返回值設(shè)置到tasksEvents中,就是因為其本質(zhì)是一個單任務循環(huán),如果某個子任務時間執(zhí)行過長,會影響更高優(yōu)先級的任務的響應變慢,影響整體性能。因此如果一個任務執(zhí)行比較長,宜進行分割,在返回值那里設(shè)置繼續(xù)處理事件,然后返回大循環(huán),看看有沒有更高優(yōu)先級的任務需要執(zhí)行。
事件和任務對應關(guān)系
事件和任務的事件處理函數(shù)是如何關(guān)聯(lián)起來的呢?
建立一個事件表,保存各個任務對應的事件。【uint16 *tasksEvents;】。tasksEvents為指向一個內(nèi)存分配的事件數(shù)組的指針。比如:tasksEvents[0]為第0個任務的事件變量(short int)。
建立另一個函數(shù)表,保存各個任務事件處理函數(shù)的地址。【const pTaskEventHandlerFn tasksArr[] =】將會根據(jù)tasksArr[x]去執(zhí)行對應的回調(diào)函數(shù)。
然后將這兩張表建立某種對應關(guān)系,【void osalInitTasks( void ),初始化task_id和tasksArr[]的函數(shù)指針對應關(guān)系】【uint8 osal_set_event( uint8 task_id, uint16 event_flag ),設(shè)置事件發(fā)生】,藍牙協(xié)議棧也會調(diào)用并設(shè)置任務,具體的實現(xiàn)已經(jīng)被封裝起來了。
當某一事件發(fā)生時則查找函數(shù)表找到對應的事件處理函數(shù)即可。【events = (tasksArr[idx])( idx, events );,調(diào)用idx變好的函數(shù)指針回調(diào)函數(shù)】
OSAL是一種事件驅(qū)動的輪詢式操作系統(tǒng)。事件驅(qū)動是指發(fā)生事件后采取相應的事件處理方法,輪詢指的是不斷地查詢是否有事件發(fā)生。
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
在系統(tǒng)初始化時,將所有任務的事件初始化為0。通過taskEvents[idx]是否為0來判斷是否有事件發(fā)生【if (tasksEvents[idx])】。如果有事件發(fā)生,則查找函數(shù)對應的事件處理函數(shù)對事件進行處理【events = (tasksArr[idx])( idx, events );】。
事件表使用數(shù)組來實現(xiàn),數(shù)組的每一項對應任務的事件,每一位表示一個事件;函數(shù)表使用函數(shù)指針數(shù)據(jù)來實現(xiàn),數(shù)組的每一項是一個函數(shù)指針,指向了事件處理函數(shù)。
OSAL提供的API
總體而言,大致可以分為10個方面:1.消息管理
2.任務同步
3.時間管理
4.中斷管理
5.任務管理
6.內(nèi)存管理
7.電源管理
8.非易失性閃存管理
9.時鐘管理
10.其他常用
事件
OSAL為每個任務函數(shù)分配了一個16位的事件變量,每一位代表一個事件。最高位0x8000保留為系統(tǒng)事件SYS_ENENT_MSG。其余的15位留給用戶自定義需要的事件。通常事件由定時器啟動,比如2s后我要點亮LED1,這就需要發(fā)送一個點亮LED1的事件,然后等待,當2s后接收到點亮LED1事件的時候調(diào)用HAL層開關(guān)LED1的函數(shù)開啟LED1。
消息
MAG是比EVENT事件更具體并且可以攜帶數(shù)據(jù)的一種通信方式。而且MSG的標記是按數(shù)值,而不是按位。比如0x02和0x03是兩個不同的消息,但是對于事件0x03則是0x01和0x02事件的組合。MSG收發(fā)使用osal_mag_send()和osal_msg_receive();當調(diào)用osal_msg_send()發(fā)送一個MSG的同時會在EVENT列表中觸發(fā)一個message ready event。為了降低消息傳遞的開支,通常傳遞指向消息的指針。
消息與事件的區(qū)別
講解消息隊列之前需要講解一下消息與事件的區(qū)別。
事件是驅(qū)動任務去執(zhí)行某些操作的條件,當系統(tǒng)中產(chǎn)生了一個事件,OSAL 將這個事件傳遞給相應的任務后,任務才能執(zhí)行一個相應的操作(調(diào)用事件處理函數(shù)去處理)。
通常某些事件發(fā)生時,又伴隨著一些附加信息的產(chǎn)生,例如:主機 GATT 接收到數(shù)據(jù)后,會產(chǎn)生 GATT_MSG_EVENT 消息,但是任務的事件處理函數(shù)在處理這個事件的時候,還需要得到所收到的數(shù)據(jù)。
因此,這就需要將事件和數(shù)據(jù)封裝成一個消息,將消息發(fā)送到消息隊列osal_msg_send,然后在事件處理函數(shù)中就可以使用 osal_msg_receive 從消息隊列中得到該消息。這里需要說明一點,消息一般用于不同任務函數(shù)之間的數(shù)據(jù)傳遞,因為不同的任務具有各自的堆棧空間。在同一任務中使用全局函數(shù)或者用戶事件完全能夠勝任。當然消息也可以在同一個任務中傳遞數(shù)據(jù)。
EVENT用于同一任務函數(shù)傳遞命令,而MSG則用于不同的任務函數(shù)傳遞命令數(shù)據(jù)。
這里需要說明一點,消息一般用于不同任務函數(shù)之間的數(shù)據(jù)傳遞,因為不同的任務具有各自的堆棧空間。在同一任務中使用全局函數(shù)或者用戶事件完全能夠勝任。當然消息也可以在同一個任務中傳遞數(shù)據(jù)。
事件處理
消息處理
OSAL 維護了一個消息隊列,每一個消息都會被放到這個消息隊列中去,當任務接收到事件后,可以從消息隊列中獲取屬于自己的消息,然后調(diào)用消息處理函數(shù)進行相應的處理即可。
Osal_msg_allocate()為消息分配緩存空間,分配之后,可以填充消息,然后通過osal_msg_send( ) 將消息發(fā)送出去,然后任務函數(shù)中通過 osal_msg_reveive()函數(shù)接收屬于 自己的消息,并處理,最后調(diào)用osal_msg_deallocate() 函數(shù)銷毀由Osal_msg_allocate()分配的內(nèi)存空間。
下面是按鍵的消息處理過程,按鍵的消息最終將會發(fā)送到第一次注冊的任務中去。
這里需要說明一點,消息一般用于不同任務函數(shù)之間的數(shù)據(jù)傳遞,因為不同的任務具有各自的堆棧空間。在同一任務中使用全局函數(shù)或者用戶事件完全能夠勝任。當然消息也可以在同一個任務中傳遞數(shù)據(jù)。
事實上,它只是發(fā)了一個KEY_CHANGE事件,而鍵值是以MSG消息的形式發(fā)到系統(tǒng)的消息隊列,而該消息也會帶上目標taskId的標識。
如下代碼可以從消息隊列中得到一個消息:pMsg = osal_msg_receive( registeredKeysTaskID))
時間管理
時間管理API用于開啟和關(guān)閉定時器,定時時間一般為毫秒級定時。
osal_start_reload_timer()和osal_start_timerEx()功能一樣,但是本接口還多了一個功能:就是定時時間到后相應事件被執(zhí)行,并重新加載定時器,也就是又重新設(shè)置了定時器,繼續(xù)進行定時工作,除非調(diào)“osal_stop_timerEx()”接口,否則一直循環(huán)定時操作。
總結(jié)
以上是生活随笔為你收集整理的CC254x--OSAL的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 代码段编辑器SnippetEditor
- 下一篇: 漏洞挖掘之信息收集