zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    jmeter压测:failed (99: Cannot assign requested address) while connecting to upstream,问题解决
    linux主机设置免密登录
    linux环境 jdk+mysql+redis安装初始化步骤
    互联网系统设计原则
    LINUX运维常用命令
    性能测试岗位常见面试题
    查看电脑已连接过的WIFI密码
    Jenkins安装后,安装插件失败。报错SunCertPathBuilderException
    【java】javac命令在win10不可用,提示javac不是内部或外部命令,也不是可运行的程序【解决方法】
    .NET跨平台实践:.NetCore、.Net5/6 Linux守护进程设计
  • 原文地址:https://www.cnblogs.com/bastard/p/2755193.html
Copyright © 2011-2022 走看看