Ril與modem的互動
一 用戶端的請求處理
用戶端請求從EventLoop通過dispatch傳遞到reference-ril.c中調用onRequest介面。
處理用戶端請求:
static void onRequest (int request, void *data, size_t datalen, RIL_Token t){ switch (request) { case RIL_REQUEST_DIAL: requestDial(data, datalen, t); break; …… }}
二 AT Command發送
將用戶端請求轉化成AT命令:
static void requestDial(void *data, size_t datalen, RIL_Token t){ RIL_Dial *p_dial; char *cmd;
//轉化成AT命令 p_dial = (RIL_Dial *)data; asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
//發送AT命令 ret = at_send_command(cmd, NULL); //請求處理完成回調 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);}
發送AT Command:
static int at_send_command_full_nolock (const char *command, ATCommandType type,……){ //將資料寫入到mdoem裝置檔案節點中 err = writeline (command); //休眠等待寫入的資料被讀取 while (sp_response->finalResponse == NULL && s_readerClosed == 0) { err = pthread_cond_wait(&s_commandcond, &s_commandmutex); } return err;}
將資料寫入modem裝置節點中:
static int writeline (const char *s){ //寫入資料到裝置檔案描述符s_fd while (cur < len) { do { written = write (s_fd, s + cur, len - cur); } while (written < 0 && errno == EINTR); cur += written; }
//返回行首 do { written = write (s_fd, "\r" , 1); } while ((written < 0 && errno == EINTR) || (written == 0)); return 0;}
這樣就將資料寫入到裝置檔案描述符s_fd,將AT Command傳遞給Modem了;
在資料被讀取之前處於休眠狀態。資料寫入被讀取之後,方才返回。
那麼s_fd代表的的裝置是如何設定的,讀資料又是怎麼進行的呢。
三 Modem響應請求處理
通過AT Command將命令發給了Modem,等待Modem處理此請求,然後將結果返回來,
讀取之後進行處理,然後表示此請求Complete,並且通知 Client。
過程如下:
這個Serial Prot是什麼,Reader Loop是什麼呢。回到rild進程main函數中看看。
在rild進程的main函數中:
int main(int argc, char **argv){ //處理用戶端請求的模組reference-ril.c 調用RIL_Init funcs_inst[0] = rilInit(&s_rilEnv, argc, s_argv); ……}
reference-ril初始化函數:
RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv){ //互動的介面 s_rilenv = env; //提取modem裝置連接埠或者路徑 //此處是d 根據前面屬性系統擷取參數:rild.libargs=-d /dev/ttyS0 // getopt的使用 提取選項 while ( -1 != (opt = getopt(argc, argv, "p:d:s:c:"))) { switch (opt) { case 'd': s_device_path = optarg; break; } } //建立線程s_tid_mainloop ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL); //返回請求互動的介面 return &s_callbacks;}
s_tid_mainloop線程的執行體:
static void *mainLoop(void *param){ at_set_on_reader_closed(onATReaderClosed); at_set_on_timeout(onATTimeout); for (;;) { fd = open (s_device_path, O_RDWR); s_closed = 0; ret = at_open(fd, onUnsolicited); RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0); // Give initializeCallback a chance to dispatched, since // we don't presently have a cancellation mechanism sleep(1); waitForClose(); }}
這裡開啟了modem的裝置檔案描述符fd,傳遞給了at_open():
int at_open(int fd, ATUnsolHandler h){ //與modem裝置通訊檔案描述符 s_fd = fd;
//網路端傳來事件請求處理onUnsolicited s_unsolHandler = h; s_readerClosed = 0;
//建立線程s_tid_reader ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr); return 0;}
線程執行體readerLoop():
static void *readerLoop(void *arg){ for (;;) { //從與modem通訊裝置連接埠讀取資料 line = readline(); if (line == NULL) { break; } //處理資料 processLine(line); } onReaderClosed(); return NULL;}
來自Modem端資料處理:
static void processLine(const char *line){ if (sp_response == NULL) { //來自網路端事件 handleUnsolicited(line); } else if (isFinalResponseSuccess(line)) { //用戶端請求處理返回 sp_response->success = 1; handleFinalResponse(line); } ……}
來自網路端事件:
static void handleUnsolicited(const char *line){ // 回調介面onUnsolicited if (s_unsolHandler != NULL) { s_unsolHandler(line, NULL); }}
用戶端請求處理返回:
static void handleFinalResponse(const char *line){ //儲存modem端響應請求所傳遞的資料 sp_response->finalResponse = strdup(line);
//發送signal 喚醒等待s_commandcond的線程——Event Loop pthread_cond_signal(&s_commandcond);}
整個資料流程圖如下:
圖片來自:http://blog.csdn.net/maxleng/article/details/5576637