【正文】
handleUnsolicited 自動上報功能以及 switch s_type 具體響應(yīng)信息。具體響應(yīng)需要 handleFinalResponse 這樣的標準響應(yīng)來最終完成。 ① onUnsolicite(主動上報響應(yīng)) static void onUnsolicited (const char *s, const char *sms_pdu);短信的 AT 設(shè)計難度較高。 response 的主要的解析過程由 中的函數(shù)完成,其本質(zhì)就是字符串按塊解析,具體的解析方式由每條命令或上報信息自行決定。此處不再詳述。 onUnsolicited 24 信息科學與技術(shù)學院學士學位論文 只解析出頭部 (一般是 +XXXX 的形式 ),然后按類型決定下一步操作,操作為 RIL_onUnsolicitedResponse 和 RIL_requestTimedCallback 兩種。 第一, RIL_onUnsolicitedResponse: solicite 的信息直接返回給上層。通過 Parcel傳遞,將 RESPONSE_UNSOLICITED, unsolResponse( request 號)先寫入 Parcel,然后通過 s_unsolResponses 數(shù)組,查找到對應(yīng)的 responseFunction 完成進一步的的解析,存入 Parcel 中。最終通過 sendResponse 將其傳遞回原進程。流程如下: sendResponsesendResponseRawblockingWritewrite to s_fdCommand(前面建 立起來的和上層框架的 socket 連接 )。 第二, RIL_requestTimedCallback:通過 event 機制實現(xiàn)的 timer 機制,回調(diào)對應(yīng)的內(nèi)部處理函數(shù)。通過 internalRequestTimedCallback 將回調(diào)添加到 event 循環(huán),最終完成 callback 上掛的函數(shù)的回調(diào)。比如 pollSIMState, onPDPContextListChanged 等回調(diào), 不用返回上層, 內(nèi)部處理就可以。 ② switch s_type(命令的具體響應(yīng))及 handleFinalResponse(標準響應(yīng)) 命令的類型( s_type)在 send mand 時設(shè)置。有 NO_RESULT、 NUMERIC、SINGLELINE、 MULTILINE 幾種,供不同的 AT 使用。比如 AT+CSQ 是 singleline, 返回 at+csq=xx,xx,再加一行 OK,比如一些設(shè)置命令,就是 no_result, 只有一行 OK或 ERROR。 這幾個類型的解析都很相似,通過一定的判斷(如比較 AT 頭標記等),如果是對應(yīng)的響應(yīng),就通過 addIntermediate 掛到一個臨時結(jié)果。 sp_responsep_intermediates 隊列中,如果不是對應(yīng)響應(yīng),則其應(yīng)該是穿插其中的自動上報,用 onUnsolicite 來處理。具體響應(yīng)只起一個獲取響應(yīng)信息到臨時結(jié)果、等待具體分析的作用。無論有無具體響應(yīng),最終都會以標準響應(yīng) handleFinalResponse來處理,也就是接受到 OK, ERROR 等標準 response 來結(jié)束,這是大多數(shù) AT 命令的規(guī)范。 handleFinalResponse 會設(shè)置 s_mandcond 這一 object ,也就是at_send_mand_full_nolock 等待的對象。 至 此,響應(yīng)的完整信息已經(jīng)完全獲得, send mand 可以進一步處理返回的信息(臨時結(jié)果、以及標準返回的成功或失敗都在 sp_response 中)。 pp_outResponse 25 信息科學與技術(shù)學院學士學位論文 參數(shù)將 sp_response 返回給調(diào)用 at_send_mand_full_nolock 的函數(shù)。 p_response 如果返回失?。ㄒ簿褪菢藴薯憫?yīng)的 ERROR 等造成),則通過RIL_onRequestComplete 發(fā)送返回數(shù)據(jù)給上層,結(jié)束命令;如果成功,則進一步分析p_responsep_intermediates,同樣是通 過 里的函數(shù)進行分析,并同樣將結(jié)果通過 RIL_onRequestComplete 返回。 RIL_onRequestComplete 和 RIL_onUnsolicitedResponse 很相似,功能也一致。 通過 Parcel 來傳遞回上層,同樣是先寫入 RESPONSE_SOLICITED(區(qū)別于 RESPONSE_UNSOLICITED), pRItoken(上層傳下的 request 號),錯誤碼( send mand 的 錯 誤 , 不 是 AT 響 應(yīng) )。 如 果 有 AT 響 應(yīng) , 通 過 訪 問pRIpCIresponseFunction 來完成具體 response 的解析,并寫入 Parcel。 然后通過同樣的途徑: sendResponsesendResponseRawblockingWritewrite to s_fdCommand 完成最終的響應(yīng)傳遞,如圖 44 所示。 R e s p o n s e 流 程Vendor RILAndroidR I L i m p l r i l d p h o n eb a s e b a n dI n c o m i n g c a l lP i c k u p ?L i s t e n t h r e a dO n U n s o l i c i t e dR e s p o n s e ( )C o n n e c t i o nE s t a b l i s h e d 圖 44 Response 流程圖 26 信息科學與技術(shù)學院學士學位論文 Read loop 要解決的問題是:解析從 Modem 發(fā)過來的回應(yīng)。如果遇到主動上報消息則通過 handleUnsolicited 上報的 javaril ;如果是命令的應(yīng)答,則通過handleFinalResponse 通知 send_at_mand 有應(yīng)答結(jié)果。 Rild 層初始化時獲取 提供的函數(shù)列表結(jié)構(gòu)體。 Eventloop 將根據(jù)不同的命令類型獲取 javaril 消息,解析出需要的參數(shù),并調(diào)用 onRequest 函數(shù)進行分發(fā)處理。 send_at_mand 是同步的,命令發(fā)送后, send_at_mand 將等待在命令處理完成。 ③ RIL 跟上層通訊主要采用兩種方式: 一種是通過 Socket 發(fā)送與接收消息的方式來實現(xiàn), C 方面,這個 Socket 在 里面可以找到它的創(chuàng)建代碼: s_fdListen = android_get_control_socket(SOCKET_NAME_RIL)。 JAVA 方面 ,在 中: s = new LocalSocket()。 l = new LocalSocketAddress(SOCKET_NAME_RIL, )。 (l)。 另外一種方式就 是直接通過 TCP/IP 直接訪問內(nèi)核中的 shared memory,進行 RPC調(diào)用,這種方式主要應(yīng)用在數(shù)據(jù)模式上,一是因為 Android 的每個 Activity 隨時都會有可能需要網(wǎng)絡(luò)連接接收發(fā)送數(shù)據(jù), 因此必須提供一種實時性較高的訪問方式,二是因為可以提高通訊效率。 Kernel 層 此處主要是對 usb serial driver 的加載,這里使用的 usb serial driver 是來自 linux內(nèi)核下的通用 usb serial 驅(qū)動。 Usb serial 驅(qū)動控制插入其中的 usb 3G( ZTE MG3732)設(shè)備,提供虛擬的串口,如 ttyUSB0, ttyUSB1。 為了讓 usb serial 驅(qū)動為 3G 模塊所使用,需要修改驅(qū)動源碼,使內(nèi)核能夠識別設(shè)備。主要是在內(nèi)核 /driver/usb/serial/ 中,增加設(shè)備的 vid 和 pid,也就是產(chǎn)品 27 信息科學與技術(shù)學院學士學位論文 號和出廠號。代碼如下所示: { USB_DEVICE(0x19d2, 0xffff) }, { USB_DEVICE(0x19d2, 0xffec) }, 并且還需要配置內(nèi)核: Device Drivers [*] USB support * Support for Hosside USB //* OHCI HCDsupport * USB Serial Converter support * USB driver for GSM and CDMA modems 這樣內(nèi)核就支持 ZTE MG3732 3G 模塊了。當驅(qū)動成功加載后,插入 3G 模塊后,在 /dev/目錄下就可以看到 ttyUSB0, ttyUSB1 等字符設(shè)備文件。 本章小結(jié) 本章對 APP 層、 Framework 層進行了簡單的分析,重點介紹了 RIL 層和 Kernel層的實現(xiàn)。對 App 層、 Framework 層的分析是為了實現(xiàn) RIL 層,知道 RIL 層從上層接收到什么。 RIL 層主要實現(xiàn)了兩個流程,即 Request 流程和 Response 流程。 Request流程就是接收上層的事件轉(zhuǎn)化為 AT 命令傳輸?shù)接布?Response 流程就是把硬件響應(yīng)的命令再解析,然后返回給上層。 28 信息科學與技術(shù)學院學士學位論文 5 基于 Android 系統(tǒng)的 3G 模塊( MG3732)開發(fā) RIL 層的開發(fā) 為了使 RIL 層支持該 3G 模塊,首先要在 RIL 層添加對該模塊的支持。代碼如ril/referenceril/ 中: LOCAL_CFLAGS += DZTE_MG3732 MG3732 模塊 Response 的數(shù)據(jù)與普通的模塊有所區(qū)別,所以獲取 Response 信息的 代 碼 有 所 不 同 。 這 里 需 要 獲 取 Response 信 息 代 碼 , 具 體 代 碼 在ril/referenceril/ 中: static const char *urc_readline() //讀取 Response 信息 { ssize_t count。 char *p_read = NULL。 char *p_eol = NULL。 char *ret。 if (*s_URCBufferCur == 39。\039。) { s_URCBufferCur = s_URCBuffer。 *s_URCBufferCur = 39。\039。 p_read = s_URCBuffer。 } else { while (*s_URCBufferCur == 39。\r39。 || *s_URCBufferCur == 39。\n39。) s_URCBufferCur++。 p_eol = findNextEOL(s_URCBufferCur)。 if (p_eol == NULL) { size_t len。 len = strlen(s_URCBufferCur)。 memmove(s_URCBuffer, s_URCBufferCur, len + 1)。 29 信息科學與技術(shù)學院學士學位論文 p_read = s_URCBuffer + len。 s_URCBufferCur = s_URCBuffer。 } } while (p_eol == NULL) { if (0 == MAX_AT_RESPONSE (p_read s_URCBuffer)) { LOGE(ERROR: Input line exceeded buffer\ n)。 s_URCBufferCur = s_URCBuffer。 *s_URCBufferCur = 39。\039。 p_read = s_URCBuffer。 } do { count = read(urc_fd, p_read, MAX_AT_RESPONSE (p_read s_URCBuffer))。 } while (count 0 amp。amp。 errno ==