【正文】
handleUnsolicited 自動(dòng)上報(bào)功能以及 switch s_type 具體響應(yīng)信息。具體響應(yīng)需要 handleFinalResponse 這樣的標(biāo)準(zhǔn)響應(yīng)來最終完成。 ① onUnsolicite(主動(dòng)上報(bào)響應(yīng)) static void onUnsolicited (const char *s, const char *sms_pdu);短信的 AT 設(shè)計(jì)難度較高。 response 的主要的解析過程由 中的函數(shù)完成,其本質(zhì)就是字符串按塊解析,具體的解析方式由每條命令或上報(bào)信息自行決定。此處不再詳述。 onUnsolicited 24 信息科學(xué)與技術(shù)學(xué)院學(xué)士學(xué)位論文 只解析出頭部 (一般是 +XXXX 的形式 ),然后按類型決定下一步操作,操作為 RIL_onUnsolicitedResponse 和 RIL_requestTimedCallback 兩種。 第一, RIL_onUnsolicitedResponse: solicite 的信息直接返回給上層。通過 Parcel傳遞,將 RESPONSE_UNSOLICITED, unsolResponse( request 號(hào))先寫入 Parcel,然后通過 s_unsolResponses 數(shù)組,查找到對(duì)應(yīng)的 responseFunction 完成進(jìn)一步的的解析,存入 Parcel 中。最終通過 sendResponse 將其傳遞回原進(jìn)程。流程如下: sendResponsesendResponseRawblockingWritewrite to s_fdCommand(前面建 立起來的和上層框架的 socket 連接 )。 第二, RIL_requestTimedCallback:通過 event 機(jī)制實(shí)現(xiàn)的 timer 機(jī)制,回調(diào)對(duì)應(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(標(biāo)準(zhǔn)響應(yīng)) 命令的類型( s_type)在 send mand 時(shí)設(shè)置。有 NO_RESULT、 NUMERIC、SINGLELINE、 MULTILINE 幾種,供不同的 AT 使用。比如 AT+CSQ 是 singleline, 返回 at+csq=xx,xx,再加一行 OK,比如一些設(shè)置命令,就是 no_result, 只有一行 OK或 ERROR。 這幾個(gè)類型的解析都很相似,通過一定的判斷(如比較 AT 頭標(biāo)記等),如果是對(duì)應(yīng)的響應(yīng),就通過 addIntermediate 掛到一個(gè)臨時(shí)結(jié)果。 sp_responsep_intermediates 隊(duì)列中,如果不是對(duì)應(yīng)響應(yīng),則其應(yīng)該是穿插其中的自動(dòng)上報(bào),用 onUnsolicite 來處理。具體響應(yīng)只起一個(gè)獲取響應(yīng)信息到臨時(shí)結(jié)果、等待具體分析的作用。無論有無具體響應(yīng),最終都會(huì)以標(biāo)準(zhǔn)響應(yīng) handleFinalResponse來處理,也就是接受到 OK, ERROR 等標(biāo)準(zhǔn) response 來結(jié)束,這是大多數(shù) AT 命令的規(guī)范。 handleFinalResponse 會(huì)設(shè)置 s_mandcond 這一 object ,也就是at_send_mand_full_nolock 等待的對(duì)象。 至 此,響應(yīng)的完整信息已經(jīng)完全獲得, send mand 可以進(jìn)一步處理返回的信息(臨時(shí)結(jié)果、以及標(biāo)準(zhǔn)返回的成功或失敗都在 sp_response 中)。 pp_outResponse 25 信息科學(xué)與技術(shù)學(xué)院學(xué)士學(xué)位論文 參數(shù)將 sp_response 返回給調(diào)用 at_send_mand_full_nolock 的函數(shù)。 p_response 如果返回失敗(也就是標(biāo)準(zhǔn)響應(yīng)的 ERROR 等造成),則通過RIL_onRequestComplete 發(fā)送返回?cái)?shù)據(jù)給上層,結(jié)束命令;如果成功,則進(jìn)一步分析p_responsep_intermediates,同樣是通 過 里的函數(shù)進(jìn)行分析,并同樣將結(jié)果通過 RIL_onRequestComplete 返回。 RIL_onRequestComplete 和 RIL_onUnsolicitedResponse 很相似,功能也一致。 通過 Parcel 來傳遞回上層,同樣是先寫入 RESPONSE_SOLICITED(區(qū)別于 RESPONSE_UNSOLICITED), pRItoken(上層傳下的 request 號(hào)),錯(cuò)誤碼( send mand 的 錯(cuò) 誤 , 不 是 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 信息科學(xué)與技術(shù)學(xué)院學(xué)士學(xué)位論文 Read loop 要解決的問題是:解析從 Modem 發(fā)過來的回應(yīng)。如果遇到主動(dòng)上報(bào)消息則通過 handleUnsolicited 上報(bào)的 javaril ;如果是命令的應(yīng)答,則通過handleFinalResponse 通知 send_at_mand 有應(yīng)答結(jié)果。 Rild 層初始化時(shí)獲取 提供的函數(shù)列表結(jié)構(gòu)體。 Eventloop 將根據(jù)不同的命令類型獲取 javaril 消息,解析出需要的參數(shù),并調(diào)用 onRequest 函數(shù)進(jìn)行分發(fā)處理。 send_at_mand 是同步的,命令發(fā)送后, send_at_mand 將等待在命令處理完成。 ③ RIL 跟上層通訊主要采用兩種方式: 一種是通過 Socket 發(fā)送與接收消息的方式來實(shí)現(xiàn), C 方面,這個(gè) 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,進(jìn)行 RPC調(diào)用,這種方式主要應(yīng)用在數(shù)據(jù)模式上,一是因?yàn)?Android 的每個(gè) Activity 隨時(shí)都會(huì)有可能需要網(wǎng)絡(luò)連接接收發(fā)送數(shù)據(jù), 因此必須提供一種實(shí)時(shí)性較高的訪問方式,二是因?yàn)榭梢蕴岣咄ㄓ嵭省? Kernel 層 此處主要是對(duì) usb serial driver 的加載,這里使用的 usb serial driver 是來自 linux內(nèi)核下的通用 usb serial 驅(qū)動(dòng)。 Usb serial 驅(qū)動(dòng)控制插入其中的 usb 3G( ZTE MG3732)設(shè)備,提供虛擬的串口,如 ttyUSB0, ttyUSB1。 為了讓 usb serial 驅(qū)動(dòng)為 3G 模塊所使用,需要修改驅(qū)動(dòng)源碼,使內(nèi)核能夠識(shí)別設(shè)備。主要是在內(nèi)核 /driver/usb/serial/ 中,增加設(shè)備的 vid 和 pid,也就是產(chǎn)品 27 信息科學(xué)與技術(shù)學(xué)院學(xué)士學(xué)位論文 號(hào)和出廠號(hào)。代碼如下所示: { 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 模塊了。當(dāng)驅(qū)動(dòng)成功加載后,插入 3G 模塊后,在 /dev/目錄下就可以看到 ttyUSB0, ttyUSB1 等字符設(shè)備文件。 本章小結(jié) 本章對(duì) APP 層、 Framework 層進(jìn)行了簡單的分析,重點(diǎn)介紹了 RIL 層和 Kernel層的實(shí)現(xiàn)。對(duì) App 層、 Framework 層的分析是為了實(shí)現(xiàn) RIL 層,知道 RIL 層從上層接收到什么。 RIL 層主要實(shí)現(xiàn)了兩個(gè)流程,即 Request 流程和 Response 流程。 Request流程就是接收上層的事件轉(zhuǎn)化為 AT 命令傳輸?shù)接布?Response 流程就是把硬件響應(yīng)的命令再解析,然后返回給上層。 28 信息科學(xué)與技術(shù)學(xué)院學(xué)士學(xué)位論文 5 基于 Android 系統(tǒng)的 3G 模塊( MG3732)開發(fā) RIL 層的開發(fā) 為了使 RIL 層支持該 3G 模塊,首先要在 RIL 層添加對(duì)該模塊的支持。代碼如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 信息科學(xué)與技術(shù)學(xué)院學(xué)士學(xué)位論文 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 ==