}
我们再分析上面的第一个步骤,也就是把消息发送到Eventloop中的过程。当发送到Eventloop后,Eventloop就会调用当前Event的回调函数,现在的回调函数是processCommandsCallback: static void processCommandsCallback(int fd, short flags, void *param) { for (;;) {
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
if (ret == 0 && p_record == NULL) { break; } else if (ret < 0) { break;
} else if (ret == 0) { /* && p_record != NULL */ //把RILJ层数据通过AT发送到Modem processCommandBuffer(p_record, recordlen); } }
if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) { //命令已经发送完成,关闭当前命令的流套接字 close(s_fdCommand); s_fdCommand = -1; //删掉当前Event
ril_event_del(&s_commands_event); record_stream_free(p_rs);
//重新添加RILJ与RILC之间的Socket Event rilEventAddWakeup(&s_listen_event); onCommandsSocketClosed();
} }
上面看到,发送命令给Modem是通过processCommandBuffer实现的: static int processCommandBuffer(void *buffer, size_t buflen) { Parcel p; int32_t request; int32_t token; RequestInfo *pRI;
p.setData((uint8_t *) buffer, buflen); //得到请求码和令牌
status = p.readInt32(&request); status = p.readInt32 (&token);
pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo)); //设置当前请求的令牌 pRI->token = token;
//s_commands中针对不同的命令对应不同的处理函数 pRI->pCI = &(s_commands[request]);
//链表结构
pRI->p_next = s_pendingRequests; s_pendingRequests = pRI;
//调用reference 中的
pRI->pCI->dispatchFunction(p, pRI);
return 0; }
首先说明一个很重要的标志位:token令牌;这个令牌可以看作当前请求的ID,当我们从Modem得到数据后需要根据不同的令牌找到当初的请求命令,然后做出相应的答复。
这里还涉及到一个特殊的数组s_commands。他的作用和s_unsolResponses类似,详细说明在本文的最后一章,这里还是简单介绍一下他的作用:
s_commands是一个数组,每个RILJ发送过来的命令在s_commands中都对应一个元素,而每个元素包含3个数据:
typedef struct { int requestNumber;
void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI); int(*responseFunction) (Parcel &p, void *response, size_t responselen); } CommandInfo;
其中requestNumber表示当前命令的编号;dispatchFunction的作用是,当前命令可以通过这个接口把数据发送到reference库;responseFunction的作用是:当Modem返回数据后reference侧可以用这个函数把数据进行打包,然后传递给Event侧。
而在processCommandBuffer中要做的就是通过当前的命令号,找到对应的发送函数(dispatchFunction)和打包函数(responseFunction)。然后把这三个数据连同当前命令的令牌(当前命令的ID)构建一个在Event和reference侧通用的数据类型(RequestInfo)并把它发送给reference侧。
假如我们从RILJ得到的命令号为RIL_REQUEST_GET_SIM_STATUS(得到当前SIM卡的状态),那么对应的,就需要调用当前命令的发送函数,而在s_commands中对于这条命令的描述为: {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus}, 因此,它对应的发送函数就是dispatchVoid: @ril.cpp
static void dispatchVoid (Parcel& p, RequestInfo *pRI) { //发送数据到Modem clearPrintBuf;
//打印Log信息RLOGD(\ printRequest(pRI->token, pRI->pCI->requestNumber);
//s_callbacks是从reference注册过来的
s_callbacks.onRequest(pRI->pCI->requestNumber, NULL, 0, pRI); }
这里看到,将命令发送到reference库是通过s_callbacks的onRequest方法实现的,而且发送时会将命令号和ril_commands.h中对应的当前命令的信息一同发送。
而关于s_callbacks这个全局变量,我们在这一节的最初就讲到,当我们调用reference中的RIL_Init完成初始化时,就会得到reference返回当前链接库提供的接口函数,而s_callbacks正是来自于这些接口: @reference-ril.c
static const RIL_RadioFunctions s_callbacks = { RIL_VERSION, onRequest, currentState, onSupports, onCancel, getVersion };
因此,当上面的Eventloop将数据通过s_callbacks.onRequest发送给reference的过程就是调用reference-ril.c中的onRequest的过程。
之后,Eventloop就完成了下发命令的任务,接下来需要reference完成把命令发送给Modem的任务。
3.2、reference将Eventloop的数据发送到Modem
上面说道,s_callbacks.onRequest其实就是reference-ril.c中的onRequest,经过这次调用,就将数据由Eventloop侧传到了reference侧。 @reference-ril.c
static void onRequest (int request, void *data, size_t datalen, RIL_Token t) {
ATResponse *p_response;
RLOGD(\
//我们重点看RIL_REQUEST_GET_SIM_STATUS switch (request) {
case RIL_REQUEST_GET_SIM_STATUS: { RIL_CardStatus_v6 *p_card_status; char *p_buffer; int buffer_size;
//与Modem交互,发送命令并得到回应 int result = getCardStatus(&p_card_status); //把回应传回给Eventloop
RIL_onRequestComplete(t, result, p_buffer, buffer_size); freeCardStatus(p_card_status); break; }
case RIL_REQUEST_GET_CURRENT_CALLS: //得到当前通话
requestGetCurrentCalls(data, datalen, t); break;
case RIL_REQUEST_DIAL: //拨号
requestDial(data, datalen, t); break;
case RIL_REQUEST_HANGUP: //挂起
requestHangup(data, datalen, t); } }