【正文】
errno == EIN。 } while (count 0 amp。 p_read = s_URCBuffer。 *s_URCBufferCur = 39。 } } while (p_eol == NULL) { if (0 == MAX_AT_RESPONSE (p_read s_URCBuffer)) { LOGE(ERROR: Input line exceeded buffer\ n)。 29 信息科學與技術(shù)學院學士學位論文 p_read = s_URCBuffer + len。 len = strlen(s_URCBufferCur)。 p_eol = findNextEOL(s_URCBufferCur)。\n39。\r39。 p_read = s_URCBuffer。 *s_URCBufferCur = 39。\039。 char *ret。 char *p_read = NULL。代碼如ril/referenceril/ 中: LOCAL_CFLAGS += DZTE_MG3732 MG3732 模塊 Response 的數(shù)據(jù)與普通的模塊有所區(qū)別,所以獲取 Response 信息的 代 碼 有 所 不 同 。 Response 流程就是把硬件響應(yīng)的命令再解析,然后返回給上層。 RIL 層主要實現(xiàn)了兩個流程,即 Request 流程和 Response 流程。 本章小結(jié) 本章對 APP 層、 Framework 層進行了簡單的分析,重點介紹了 RIL 層和 Kernel層的實現(xiàn)。代碼如下所示: { 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 模塊了。 為了讓 usb serial 驅(qū)動為 3G 模塊所使用,需要修改驅(qū)動源碼,使內(nèi)核能夠識別設(shè)備。 Kernel 層 此處主要是對 usb serial driver 的加載,這里使用的 usb serial driver 是來自 linux內(nèi)核下的通用 usb serial 驅(qū)動。 (l)。 JAVA 方面 ,在 中: s = new LocalSocket()。 send_at_mand 是同步的,命令發(fā)送后, send_at_mand 將等待在命令處理完成。 Rild 層初始化時獲取 提供的函數(shù)列表結(jié)構(gòu)體。 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)。 如 果 有 AT 響 應(yīng) , 通 過 訪 問pRIpCIresponseFunction 來完成具體 response 的解析,并寫入 Parcel。 RIL_onRequestComplete 和 RIL_onUnsolicitedResponse 很相似,功能也一致。 pp_outResponse 25 信息科學與技術(shù)學院學士學位論文 參數(shù)將 sp_response 返回給調(diào)用 at_send_mand_full_nolock 的函數(shù)。 handleFinalResponse 會設(shè)置 s_mandcond 這一 object ,也就是at_send_mand_full_nolock 等待的對象。具體響應(yīng)只起一個獲取響應(yīng)信息到臨時結(jié)果、等待具體分析的作用。 這幾個類型的解析都很相似,通過一定的判斷(如比較 AT 頭標記等),如果是對應(yīng)的響應(yīng),就通過 addIntermediate 掛到一個臨時結(jié)果。有 NO_RESULT、 NUMERIC、SINGLELINE、 MULTILINE 幾種,供不同的 AT 使用。比如 pollSIMState, onPDPContextListChanged 等回調(diào), 不用返回上層, 內(nèi)部處理就可以。 第二, RIL_requestTimedCallback:通過 event 機制實現(xiàn)的 timer 機制,回調(diào)對應(yīng)的內(nèi)部處理函數(shù)。最終通過 sendResponse 將其傳遞回原進程。 第一, RIL_onUnsolicitedResponse: solicite 的信息直接返回給上層。此處不再詳述。 ① onUnsolicite(主動上報響應(yīng)) static void onUnsolicited (const char *s, const char *sms_pdu);短信的 AT 設(shè)計難度較高。send sms pdu //收到 符號,發(fā)送 sms 數(shù)據(jù)再繼續(xù)等待響應(yīng) switch s_type具體響應(yīng) //命令有具體的響應(yīng)信息需要對應(yīng)分析 需要關(guān)注的是 handleUnsolicited 自動上報功能以及 switch s_type 具體響應(yīng)信息。除 sms 特例外,所有的 line 都要經(jīng)過 processLine,該處理流程如下: no cmdhandleUnsolicited //主動上報 isFinalResponseSuccesshandleFinalResponse //成功 ,標準響應(yīng) isFinalResponseErrorhandleFinalResponse //失敗,標準響應(yīng) get 39。這里是因為要即時處理這條短信消息(兩行、標志+ pdu),而不能拆開處理。 所有的行,首先經(jīng)過 sms 的自動上報篩選。 response 信息的獲取,是初始化分析中提到的 readerLoop 中,由 readline 函數(shù)以“行”為單位接收上來。因為這里完成命令寫出到硬件設(shè)備的操作,接下來就是等待硬件響應(yīng),也就是response 過程。其實質(zhì)都是 at_send_mand_full 方法,執(zhí)行 write 之后便等待硬件那邊給過來的響應(yīng),于是進入 response 階段。 23 信息科學與技術(shù)學院學士學位論文 查看 writeline 方法, written = write (s_fd, s + cur, len cur)。大致的流程為: onrequestrequestDialat_send_mandat_send_mand_fullat_send_command_full_nolock。 而s_callbacks 是前文提到說的 RIL_RadioFunctions 結(jié)構(gòu)的指針, RIL_RadioFunction 中有個重要的域是 onRequest,詳情可參照 文件中 onrequest 方法的實現(xiàn)。 dispatchDial 方法中,里面核心代碼如下: (pRIpCIrequestNumber, amp。 在該方法中,首先通過 accept()接收上層的 socket,然后通過 record_stream_new()建立一個 record_stream,并聯(lián)系上 s_fdCommand,到目前為止 s_fdCommand 已經(jīng)有了上層數(shù)據(jù),于是調(diào)用 processCommandsCallback(int fd, short flags, void *param) 方法, processCommandsCallback 會保證收到一個完整的 request(由 recordStream 決定),并調(diào)用 processCommandBuffer 方法,這是命令的下發(fā)流程。 前面提到 RILSender 將請求呼叫的字節(jié)流傳給了 rild 的 socket。比如 at_csq 類型,需要at_send_mand_singleline,而發(fā)送短信,因為有 prompt 提示符“ ”,傳送數(shù)據(jù)、結(jié)束符等一系列操作,需要專門用 at_send_mand_sms 來實現(xiàn)。 requestDial 中將命令和參數(shù)轉(zhuǎn)換成對應(yīng)的 AT 命令,調(diào)用公共 send mand 接口 at_send_mand。 request 請求在這里轉(zhuǎn)入底層的 libreferenceril 處理, handler 是 中的 進行一個簡單的 switch 分發(fā)。利用(pRIpCIrequestNumber, xxx, len, pRI) 完成 這一 操作。其實有很多種類的dispatch function, 比如 dispatchVoid, dispatchStrings, dispatchSIM_IO 等等 , 這些函數(shù)的區(qū)別在于解析傳入 的參數(shù)形式, void 就是不帶參數(shù)的, Strings 是以 string[]做參數(shù) ,又如 Dial 等,有自己的參數(shù)解析方式,以此類推。 ( 3) Request 流程 對 Dial 而言, CommandInfo 包含了所有的 AT 命令。s_listen_event)。s_listen_event, s_fdListen, false,listenCallback, NULL)。然后將這兩個 socket 接口使用任務(wù)一中實現(xiàn)的機制進行注冊(僅列出 s_fdListen)。 Rild 通過 RIL_register 注冊這一指針。 } RIL_RadioFunctions。 RIL_Cancel onCancel。 RIL_RadioStateRequest onStateRequest。 typedef struct { int version。 ③ 任務(wù)三:由 RIL_Init 的返回值 funcs = rilInit(amp。 這里可以看到,主要完成一些參數(shù)配置,以及網(wǎng)絡(luò)狀態(tài)的檢查等。TIMEVAL_0) ,跑到initializeCallback 中,執(zhí)行一些以 AT 命 令為主的 Modem 初始化命令。 SMS(短信)的收發(fā) if(isSMSUnsolicited(line))判斷也在 readerLoop 中。這個循環(huán)啟動以后,基本的 AT 響應(yīng)機制就已經(jīng)建立了起來。attr),入口點為 readerLoop。s_tid_reader, amp。在注冊一些基礎(chǔ)回調(diào)( timeout、 readerclose)后, mainLoop 首先打開硬件設(shè)備文件,建立起與硬件的通信, s_device_path 和 s_port 是前面獲取的設(shè)備路徑參數(shù),將其打開(兩者可以同時打開并擁有 各自的 reader,這里也很容易添加雙卡雙待等支持)。attr, mainLoop, NULL)繼續(xù)初始化,即 mainLoop。 ② 任務(wù)二:這個任務(wù)的入口是 RIL_Init, 首先通過參數(shù)獲取(p/d/s)硬件接口的設(shè)備文件或 模擬硬件接口的 socket. 接下來便新創(chuàng)建一個線程pthread_create(amp。目的是為了可以在一些情況下能夠 內(nèi)部喚醒 ril_event_loop 的多路復用阻塞,比如一些帶 timeout 的命令到期的時候。rfds, n)和 firePending()(后面會詳細分析這些流程)。這樣 ril_event_loop 能通過一個多路復用 I/O 的機制( select)來等待這些 fd。 具體流程是: ril_event_init 完成后,通過 ril_event_set 來配置一個新 ril_event,并通過 ril_event_add 加入到隊列之中(實際通常用 rilEventAddWakeup 來添加)。 //回調(diào)時參數(shù) }。 ril_event_cb func。例如對于串口數(shù)據(jù)事件, fd 就是相關(guān)串口的設(shè)備句柄 bool persist。// 前一個消息 int fd。 // 通過多路復用 I/O 機制循環(huán)調(diào)用消息隊列 19 信息科學與技術(shù)學院學士學位論文 struct ril_event { struct ril_event *next。 // 增加時間計時器 void ril_event_del(struct ril_event * ev)。// 設(shè)