Ril分析三——客户端请求和响应处理与modem交互
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