什麼是QMI?
Qualcom Message Interface 高通信息接口
背景:2005-2006年部署(原高通MSMTM接口),所有服務最初都是由DATA團隊設計和維護的,功能是按照AT命令標準構建的,主要用於連接管理器類型應用程序,可通過USB連接(QMUX傳輸)連接到電腦。
2009年QMI取代RPC(Remote Procedure Call),QMI的範圍開始擴大,無線電接口層(RILs)開始向QMI過渡,並定義了必要的支持;底層由更健壯的通信(IPC路由器傳輸)替代,通過共享內存方式(SMD)在片上SOC之間可用。
高通平臺目前都是非對稱多核心,最主要的是AP和Modem。兩個處理器怎麼進行通信呢,我們把AP和Modem當作兩個主機,問題就變得了很簡單,TCP/IP協議不是一種非常成功的進程間跨主機通信方式。高通沒有采用這種方式,但是借鑑了TCP/IP的框架設計。它的框架是這樣的,內核態:基於共享內存(SMD)實現鏈路層,擴展協議域;用戶態,封裝出類似於socket函數的接口,用於用戶態使用。而我所描述的QMI就是用戶態使用的API接口,這些接口非常類似於socket,只要有個socket編程的經驗的是會容易理解的。
QMI提供什麼?
支持同步和異步接口;
支持在在多個處理器之間進行通信;
具有良好的可擴展性;
支持多客戶端併發運行;
支持多個服務端併發運行,且每個服務端還對應多個客戶端;
每個服務端還支持版本信息;
QMI架構
Messages
Request message ——一條request消息由客戶端發往服務端,並由服務端進行處理。
Reponse message——每一個request的消息都會有一個reponse消息與之對應,類似於一個函數的返回值。如果請求消息等效於調用函數,則響應消息等效於返回給調用方的結果。
Indiction message——這類消息是由服務端發給客戶端的異步消息,在任何indication message發送之前,客戶端首先需要通過request message與服務端建立連接,indication消息可以在任何時候發送。
消息的特點:
- 消息由Type-Length-Value(TLV)單元構成;
- 類型和長度是固定大小,而值是可變長度的;
- 每個消息中可以出現多個tlv值;
- 可以在該值中顯示多個數據元素;
- 對於每個消息的TLV id都是唯一的;
消息的結構:
- 由傳輸頭和服務級消息組成
- 每個傳輸的傳輸頭都是唯一的
Service Message服務級負載對於所有傳輸都是通用的,幷包含以下元素
消息ID
消息長度
零或多個可變長度的tlv
Clients
- 任何想要使用QMI的內部或外部客戶端應用程序
Services
- 任何想要使用QMI的內部應用服務程序
Common Libraries
- 爲客戶端(QCCI)和服務(QCSI)提供功能
- 通用API適用於所有平臺/傳輸
- 封裝傳輸和特定於平臺的更改,以便共享客戶機/服務代碼
- 爲每個服務消息提供編碼/解碼支持
Transports
QMUX
- 高通多路複用協議(QMUX);
- 原始傳輸通過一個有線USB以太網適配器;
- 支持MPSS處理器上的服務;
- 支持在應用程序(APPS)處理器或usb連接的主PC上的客戶端;
- QMUX的客戶端是用於特定於平臺的,不同平臺可能有差異;
IPC Router
- IPC路由器是一個面向消息(message-oriented)的路由器,用於支持Qualcomm QCCI QCSI;
- 增強了同一設備上處理器之間的傳輸;
- 通過SMD在路由節點之間傳遞QMI有效負載;
- 支持任何處理器上的客戶端和服務;
- API對於所有平臺都是通用的,即使實現不同;
QMI IDL
QMI接口是用接口定義語言(IDL)編寫的,IDL編譯器自動生成文件 .c和.h
編碼/解碼庫
- 庫是獨立的,並且與自動生成的文件解耦
- 編碼/解碼消息的元信息將在.c作爲Service_Object生成
- 在服務/客戶機啓動期間,元信息將註冊到QCSI/QCCI進行消息編碼/解碼
- 客戶端/服務可以使用QCCI/QCSI API發送/接收消息
QMI消息編碼標準
1. 不使用浮點型數據,而是使用Q16類型的固定點數,即提供16位2位補碼整數部分和16位小數部分的定點實現。
2. 命名約定
- 爲了使所有消息實現保持一致,service端需要固定的獨有的前綴
- 結構體以_type結尾
- 枚舉以_enum結尾
- 請求消息以_req_msg結尾,類型以_REQ結尾
- 消息迴應以_resp_msg結尾,類型以_RESP結尾
- 指示消息以_ind_msg結尾,類型以_IND結尾
QMI QCCI
QCCI是一套用於客戶端從服務器接收信息或者發送消息到服務器的API集合。
以下步驟描述初始化客戶機:
1. QMI客戶機創建一個通知句柄來接收服務到達和退出事件通知。然後是客戶端
用notifier句柄註冊一個通知回調函數;
2. 當服務到達時,將設置信號,並調用通知回調函數來客戶端關於服務到達的消息;
3.QMI客戶機在收到服務到達通知後解析服務地址;
4. QMI客戶機初始化服務的客戶機句柄,該服務的地址在步驟3中解析。然後,這個客戶端句柄用於與相關的QMI服務交換QMI消息;
5. 初始化客戶端句柄時,將向客戶端句柄註冊一個錯誤回調函數。此錯誤回調用於接收關於服務重啓或子系統重啓的任何通知;
6. 此時,QMI客戶機可以釋放notifier句柄,以避免任何資源泄漏;
7. QMI客戶機同步或異步發送請求消息,如上圖所示;
8. 當所有相關的QMI消息通信完成時,QMI客戶機釋放客戶機句柄。
QCCI APIs Callback function prototypes
- qmi_client_recv_raw_msg_async_cb
- qmi_client_recv_msg_async_cb
- qmi_client_ind_cb
Connection APIs
- qmi_client_notifier_init
- qmi_client_init
- qmi_client_get_service_list
Message sending APIs
- qmi_client_send_raw_msg_sync
- qmi_client_send_msg_sync
- qmi_client_delete_async_txn
Release connection APIs
- qmi_client_release
Encode and decode APIs
- qmi_client_message_encode
- qmi_client_message_decode
QMI QCSI
QCSI是用於接收客戶端的請求及對其作出響應。另外,它也用來發送指示消息(indication message)以及對消息進行編解碼(encode/decode),這個消息由server端主動發出。
消息的類型有如下三種:
Request message ——一條request消息由客戶端發往服務端,並由服務端進行處理。
Reponse message——每一個request的消息都會有一個reponse消息與之對應,類似於一個函數的返回值。如果請求消息等效於調用函數,則響應消息等效於返回給調用方的結果。
Indiction message——這類消息是由服務端發給客戶端的異步消息。在任何indication message發送之前,客戶端首先需要通過request message與服務端建立連接。indication消息可以在任何時候發送。Callback function prototypes
- qmi_csi_connect
- qmi_csi_disconnect
- qmi_csi_process_req
Registration APIs
- qmi_csi_register
- qmi_csi_unregister
Message sending APIs
- qmi_csi_send_resp
- qmi_csi_send_ind
- qmi_csi_send_broadcast_ind
Event handling APIs
- qmi_csi_handle_event
QMI SERVER
這個api構建在QCSI框架之上
其主要目的是方便客戶機以更少的工作量實現服務器
該框架允許用戶編寫基於對象的服務器,擴展核心服務器對象。核心服務器對象提供每個服務都需要的通用功能
Callback Function Prototypes
- qmi_csi_connect
- qmi_csi_disconnect
- qmi_csi_process_req
Constructor/Destructor APIs
- qmi_core_server_new
- qmi_core_server_delete
Registration APIs
- qmi_core_server_register
- qmi_core_server_unregister
- qmi_core_server_register_client
- qmi_core_server_unregister_client
Message Dispatch APIs
- qmi_core_server_dispatch_msg
- qmi_core_server_send_ind
- qmi_core_server_send_resp
QMUX
QMI Multiplexing Protocol(QMUX):QMI的複用協議
消息從控制點經過類似socket的線程傳到QMI接口後,QMI負責對數據進行封裝,加上QMUX消息的頭,發送到QMUX層,
再通過QMUX層傳到共享內存到BP側。
整個QMUX控制信道的結構如上圖,
- I/FType:QMI將控制點數據封裝後,發送到QMUX前,加的消息頭,長度爲一個byte,值通常爲0x01,表示這個消息爲QMUX消息,如果是其他值,則爲其他消息。
- Length: QMUX消息的長度,不包括I/F Type。
- ControlFlags:控制位,表示消息傳輸的方向。長度爲1個byte,只有第7個bit是標誌位,其他位爲0,bit7=1說明QMUX消息由服務端發送,bit7=0由控制點發送。
- Clien ID: 控制點的標識,在控制點和服務端都需要賦值,當在服務端發出的消息Client ID的值爲0xFF,表示該消息爲廣播消息,由服務端主動發出,被所有控制點搜到。
QMUX SDU和TLV結構:
在整個控制信道的消息中,出去消息標識頭I/F Type,和QMUX消息頭,數據傳輸在QMUXSDU中完成,QMUX SDU裏面的數據需要支持Type Length Value(TLV)的格式。
TLV格式的數據存放在QMI Service Message裏面的Value中。
- Control Flags:表示消息是請求、響應還是指示。