<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                下面看第二個關鍵函數RIL_Init。這個函數必須由動態庫實現,對于下面這個例子來說,它將由RefRil庫實現,這個函數定義在Reference_ril.c中: **Reference_ril.c** ~~~ pthread_t s_tid_mainloop;//看來又會創建一個線程 //動態庫必須實現的RIL_Init函數。 const RIL_RadioFunctions *RIL_Init(const structRIL_Env *env, int argc, char **argv) { intret; int fd= -1; intopt; pthread_attr_t attr; s_rilenv = env; //將外部傳入的env保存為s_rilenv。 ......//一些參數處理,不必管它 pthread_attr_init (&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); //創建一個工作線程mainLoop ret =pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL); /* s_callbacks也為一個結構體 staticconst RIL_RadioFunctions s_callbacks = { RIL_VERSION, //RIL的版本 onRequest, //下面是一些函數指針 currentState, onSupports, onCancel, getVersion }; */ return&s_callbacks; } ~~~ RefRil的RIL_Init函數比較簡單,主要有三項工作要做: - 保存Rild傳入的RIL_Env結構體。 - 創建一個叫mainLoop的工作線程。 - 返回一個RIL_RadioFunctions的結構體。 上面的RIL_Env和RIL_RadioFunctions結構體,就是Rild架構中用來隔離通用代碼和廠商相關代碼的接口。先來看RIL_RadioFunctions,這個結構體由廠商的動態庫實現,它的代碼如下: ~~~ //函數指針定義 typedef void (*RIL_RequestFunc) (int request,void *data, size_tdatalen, RIL_Token t); typedef RIL_RadioState(*RIL_RadioStateRequest)(); typedef int (*RIL_Supports)(int requestCode); typedef void (*RIL_Cancel)(RIL_Token t); typedef void (*RIL_TimedCallback) (void *param); typedef const char * (*RIL_GetVersion) (void); typedef struct { intversion; //RIL的版本 //通過這個接口可向BP提交一個請求,注意這個函數的返回值為空,這是為什么? RIL_RequestFunc onRequest; RIL_RadioStateRequest onStateRequest;//查詢BP的狀態 RIL_Supports supports; RIL_CancelonCancel; //查詢動態庫的版本,RefRil庫中該函數的實現將返回字符串”android reference-ril 1.0” RIL_GetVersion getVersion; } RIL_RadioFunctions; ~~~ 對于上面的結構體,應重點關注函數onRequest,它被Rild用來向動態庫提交一個請求,也就是說,AP向BP發送請求的接口就是它,但是這個函數卻沒有返回值,那么該請求的執行結果是怎么得到的呢? 這里不賣關子,直接告訴大家。Rild架構中最大的特點就是采用了異步請求/處理的方式。這種方式和異步I/O有異曲同工之妙。那么什么是異步請求/處理呢?它的執行流程如下: - Rild通過onRequest向動態庫提交一個請求,然后返回去做自己的事情。 - 動態庫處理這個請求,請求的處理結果通過回調接口通知。 這種異步請求/處理的流程和酒店的MorningCall服務很類似,具體相似之處如下所示: - 在前臺預約了一個Morning Call,這好比向酒店提交了一個請求。預約完后,就可以放心地做自己的事情了。 - 酒店登記了這個請求,記錄是哪個房間申請的服務,然后由酒店安排工作人員值班,這些都是酒店對這個請求的處理,作為房客則無須知道處理細節。 - 第二天早上,約好的時間一到,酒店給房客打電話,房客就知道這個請求被處理了。為了檢查一下賓館服務的效果,最好是拿表看看接到電話的時間是不是之前預約的時間。 這時,讀者對異步請求/處理機制或許有了一些直觀的感受。那么,動態庫是如何通知請求的處理結果的呢?這里用到了另外一個接口RIL_Env結構,它的定義如下所示: **Ril.h** ~~~ struct RIL_Env { //動態庫完成一個請求后,通過下面這個函數通知處理結果,其中第一個參數標明是哪個請求 //的處理結果 void(*OnRequestComplete)(RIL_Token t, RIL_Errno e, void *response,size_t responselen); //動態庫用于進行unsolicited Response通知的函數 void(*OnUnsolicitedResponse)(int unsolResponse, const void *data, size_t datalen); //給Rild提交一個超時任務 void*(*RequestTimedCallback) (RIL_TimedCallback callback, void *param,const struct timeval *relativeTime); //從Rild的超時任務隊列中移除一個任務 void(*RemoveTimedCallback) (void *callbackInfo); }; ~~~ 結合圖9-7和上面的分析可以發現,Rild在設計時將請求的應答接口和動態庫的通知接口都放在了RIL_Env結構體中。 關于Rild和動態庫的交互接口就分析到這里。相信讀者已經明白其中的原理了。下面來看RefRil庫創建的工作線程mainLoop。 1. 工作線程mainLoop的分析 RefRil庫的RIL_Init函數會創建一個工作線程mainLoop,其代碼如下所示: **Reference_Ril.c** ~~~ static void * mainLoop(void *param) { intfd; intret; ...... /* 為AT模塊設置一些回調函數,AT模塊用來和BP交互,對于RefRil庫來說,AT模塊就是對 串口設備通信的封裝,這里統稱為AT模塊。 */ at_set_on_reader_closed(onATReaderClosed); at_set_on_timeout(onATTimeout); for(;;) { fd= -1; //下面這個while循環的目的是為了得到串口設備的文件描述符,我們省略其中的一些內容 while (fd < 0) { if (s_port > 0) { fd = socket_loopback_client(s_port, SOCK_STREAM); } else if (s_device_socket) { if (!strcmp(s_device_path, "/dev/socket/qemud")) { ...... } else if (s_device_path != NULL) { fd = open (s_device_path, O_RDWR); if ( fd >= 0 && !memcmp( s_device_path,"/dev/ttyS", 9 ) ) { struct termios ios; tcgetattr( fd, &ios ); ios.c_lflag = 0; tcsetattr( fd, TCSANOW,&ios ); } } ...... } s_closed = 0; //①打開AT模塊,傳入一個回調函數onUnsolicited ret = at_open(fd, onUnsolicited); ...... //②下面這個函數向Rild提交一個超時任務,該任務的處理函數是initializeCallback RIL_requestTimedCallback(initializeCallback,NULL, &TIMEVAL_0); sleep(1); /* 如果AT模塊被關閉,則waitForClose返回,但是該線程并不會退出,而是從for循環那 開始重新執行一次。所以這個mainLoop工作線程是用來監控AT模塊的,一旦它被關閉,就 需要重新打開。也就是說不允許AT模塊被關閉。 */ waitForClose(); ...... } } ~~~ 可以看到,mainLoop的工作其實就是初始化AT模塊,并監控AT模塊,一旦AT模塊被關閉,那么mainLoop就要重新打開并初始化它。這幾項工作主要由at_open和超時任務的處理函數initializeCallback完成。 (1)at_open分析 來看at_open這個函數,其代碼如下所示: **Atchannle.c** ~~~ int at_open(int fd, ATUnsolHandler h) { //at_open的第一個參數是一個代表串口設備的文件描述符。 intret; pthread_t tid; pthread_attr_t attr; s_fd =fd; s_unsolHandler = h; s_readerClosed = 0; s_responsePrefix = NULL; s_smsPDU = NULL; sp_response = NULL; ......//和電源管理相關的操作 pthread_attr_init (&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //創建一個工作線程readerLoop,這個線程的目的就是從串口設備讀取數據 ret =pthread_create(&s_tid_reader, &attr, readerLoop, &attr); ...... return0; } ~~~ at_open函數會另外創建一個工作線程readerLoop,從名字上看,它會讀取串口設備。下面來看它的工作,代碼如下所示: **Atchannle.c** ~~~ static void *readerLoop(void *arg) { for(;;) { const char * line; line = readline(); //從串口設備讀取數據 ...... if(isSMSUnsolicited(line)) { char *line1; const char *line2; line1 = strdup(line); line2 = readline(); if (line2 == NULL) { break; } if (s_unsolHandler != NULL) { s_unsolHandler (line1, line2);//調用回調,處理SMS的通知 } free(line1); }else { //處理接收到的數據,也就是根據line中的AT指令調用不同的回調 processLine(line); } ......//電源管理相關 //這個線程退出前會調用通過at_set_on_reader_closed設置的回調函數,以通知 //AT模塊關閉 onReaderClosed(); returnNULL; } ~~~ readerLoop工作線程比較簡單,就是從串口設備中讀取數據,然后進行處理。這些數據有可能是solicited response,也有可能是unsolicited response,具體的處理函數我們在后續的實例分析中再來介紹,下面我們看第二個函數RIL_requestTimedCallback。 (2)initializeCallback的分析 在分析initializeCallback函數前,我們先看看RefRil向Rild提交超時任務的RIL_requestTimedCallback函數,它其實是一個宏,不過這個宏比較簡單,就是封裝了RIL_Env結構體中對RequestTimedCallback函數的調用,代碼如下所示: ~~~ #define RIL_requestTimedCallback(a,b,c) \ s_rilenv->RequestTimedCallback(a,b,c) //向Rild提交一個超時處理函數 ~~~ 下面我們看看Rild實現的這個RequestTimedCallback函數,代碼如下所示。 **Ril.cpp** ~~~ extern "C" void * RIL_requestTimedCallback (RIL_TimedCallbackcallback, void *param, const structtimeval *relativeTime) { returninternalRequestTimedCallback (callback, param, relativeTime); } /* 調用internalRequestTimedCallback,其實就是構造一個Ril_event事件然后加入到 timer_list,并觸發event_loop工作線程執行 */ static UserCallbackInfo * internalRequestTimedCallback( RIL_TimedCallback callback, void *param, const structtimeval *relativeTime) { structtimeval myRelativeTime; UserCallbackInfo *p_info; p_info= (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo)); p_info->p_callback = callback; p_info->userParam = param; if(relativeTime == NULL) { memset (&myRelativeTime, 0, sizeof(myRelativeTime)); } else{ memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime)); } ril_event_set(&(p_info->event), -1, false, userTimerCallback,p_info); //將該任務添加到timer_list中去 ril_timer_add(&(p_info->event), &myRelativeTime); triggerEvLoop(); //觸發eventLoop線程 returnp_info; } ~~~ 從上面的代碼可知,RIL_requestTimedCallback函數就是向eventLoop提交一個超時任務,這個任務的處理函數則為initialCallback,下面直接來看該函數的內容,如下所示。 **Reference_ril.c** ~~~ static void initializeCallback(void *param) { /* 這個函數就是通過發送一些AT指令來初始化BP中的無線通信Modem,不同的modem可能有 不同的AT指令。這里僅列出部分代碼。 */ ATResponse *p_response = NULL; interr; setRadioState (RADIO_STATE_OFF); at_handshake(); ...... err =at_send_command("AT+CREG=2", &p_response); ...... at_response_free(p_response); at_send_command("AT+CGREG=1", NULL); at_send_command("AT+CCWA=1", NULL); ...... if(isRadioOn() > 0) { setRadioState (RADIO_STATE_SIM_NOT_READY); } ...... } ~~~ 2. RIL_Init的總結 RIL_Init函數由動態庫提供,以上面RefRil庫的代碼為參考,這個函數執行完后,將完成RefRil庫的幾項重要工作,它們是: - 創建一個mainLoop工作線程,mainLoop線程的任務是初始化AT模塊,并監控AT模塊,一旦AT模塊被關閉,則會重新初始化AT模塊。 - AT模塊內部會創建一個工作線程readerLoop,該線程的作用是從串口設備中讀取信息,也就是直接和BP打交道。 - mainLoop通過向Rild提交超時任務,完成了對Modem的初始化工作。 在Rild的main函數中還剩下最后一個關鍵函數RIL_register沒有分析了,下面來看看它。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看