• RILC


    RILC

    RIL层的作用大体上就是将上层的命令转换成相应的AT指令,控制modem工作。生产modem的厂家有很多:Qualcomm, STE, Infineon... 不同的厂家都有各自的特点,当然也会有各自不同的驱动,但驱动代码的公开多少会涉及到modem厂家的技术细节,所以,Android系统开源了绝大部分代码,对于 部分驱动(Reference-RIL)  允许厂家以二进制Lib的形式成为一套完整Android系统的一部分。

      有Lib就需要有加载的概念,能够加载各种驱动说明驱动们都遵从一个统一的接口。这个接口是什么?RILC又是如何接收并处理RILJ向下传来的请求?


      

      进入hardware il ild ild.c,一切从main开始。

    复制代码
    int main(int argc, char **argv)
    {
        ... ...
    
        dlHandle = dlopen(rilLibPath, RTLD_NOW);
        if (dlHandle == NULL) {
            fprintf(stderr, "dlopen failed: %s
    ", dlerror());
            exit(-1);
        }
    
        RIL_startEventLoop();    // ril_event
    
        rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
        if (rilInit == NULL) {
            fprintf(stderr, "RIL_Init not defined or exported in %s
    ", rilLibPath);
            exit(-1);
    
        }
        ... ...
    
        funcs = rilInit(&s_rilEnv, argc, rilArgv);   // Reference-RIL 获得 LibRIL 的Interface   
    
        RIL_register(funcs);   // LibRIL 获得 Reference-RIL 的Interface   
    
    }
    复制代码

      从dlopen看到了动态加载的痕迹,加载Reference-RIL之后便启动了监听线程,也就在RIL_startEventLoop。每一次从上层传来的请求都是一个event,可见要了解该层的消息传输,关键是要了解  结构体 ril_event

      与其相关的文件是ril_event.h、ril_event.cpp,对于文件的分析还是引用ACE1985兄台的博文为好,抱拳为敬。

     

    ril_event.h

     View Code

    ril_event.c

     View Code

     

    若干ril_event构成watch_table数组,同时也被两个双向链表timer_list、pending_list串起来,不禁想起了内核链表。select对watch_table数组上的ril_event们进行监听。

    RILJ与RILC通过socket连接,前者为client,后者为server。

      server通过select监听对外开放的socket端口fd,若RILJ请求连接,则回调listenCallback(),accept()出一个s_fdCommand,加入select监听数组,这个s_fdCommand便成为了上层传入请求的通道,RILC通过这个通道接收具体的command,而后转化为AT指令。

     

    复制代码
    static struct ril_event s_commands_event;
    static struct ril_event s_wakeupfd_event;
    static struct ril_event s_listen_event;
    static struct ril_event s_wake_timeout_event;
    static struct ril_event s_debug_event;
    复制代码

      以上便是大致的思路,select+socket连接的经典模式。通道打通后,从s_fdCommand中到底会接收到什么?

    ril_event_set (&s_commands_event, s_fdCommand, 1,
            processCommandsCallback, p_rs);

      

      函数层层嵌套,终会有一个办实事的命令。

    复制代码
    static int
    processCommandBuffer(void *buffer, size_t buflen) {
        Parcel p;
        status_t status;
        int32_t request;
        int32_t token;
        RequestInfo *pRI;    //构造该结构体,尤其是其中的pCI
        int ret;
    
        p.setData((uint8_t *) buffer, buflen);    //获得有效p
    
        // status checked at end
        status = p.readInt32(&request);           //取得request值
        status = p.readInt32 (&token);
    
        if (status != NO_ERROR) {
            LOGE("invalid request block");
            return 0;
        }
    
        if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {
            LOGE("unsupported request code %d token %d", request, token);
            // FIXME this should perhaps return a response
            return 0;
        }
    
    
        pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
    
        pRI->token = token;
        pRI->pCI = &(s_commands[request]);    //确定早已待命的command号
    
        ret = pthread_mutex_lock(&s_pendingRequestsMutex);
        assert (ret == 0);
    
        pRI->p_next = s_pendingRequests;
        s_pendingRequests = pRI;
    
        ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
        assert (ret == 0);
    
    /*    sLastDispatchedToken = token; */
    
        pRI->pCI->dispatchFunction(p, pRI);    //命令,发射!
    
        return 0;
    }
    复制代码

      Ok,这个办实事的命令就是s_comands数组第request个结构体中的dispatchFunction().

      s_comands数组是个啥?

     

    复制代码
    static CommandInfo s_commands[] = {
    #include "ril_commands.h"
    };

    typedef struct {
        int requestNumber;
        void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
        int (*responseFunction) (Parcel &p, void *response, size_t responselen);
    } CommandInfo;
    复制代码

      

      Ref: http://blog.csdn.net/ace1985/article/details/7051522

     View Code

    RIL中有两种Response类型:

        一是Solicited Response(经过请求的回复),应用的场景是AP主动向BP发送一个AT指令,请求BP进行相应处理并在处理结束时回复一个AT指令通知AP执行的结果。源码中对应的文件是ril_commands.h。

        一是Unsolicited Response(未经请求的回复),应用场景是BP主动向AP发送AT指令,用于通知AP当前系统发生的与Telephony相关的事件,例如网络信号变化,有电话呼入等。源码中对应的文件是ril_unsol_commands.h。

    复制代码
    static UnsolResponseInfo s_unsolResponses[] = {
    #include "ril_unsol_commands.h"
    };
    
    typedef struct {
        int         requestNumber;
        int         (*responseFunction) (Parcel &p, void *response, size_t responselen);
        WakeType    wakeType;
    } UnsolResponseInfo;
    复制代码

      面对这上百的s_command元素们,顿觉代码的流程并非难点,难在对每一个s_command的理解。

      Ref:hardware ilinclude elephonyRil.h

     View Code

     打电话,则调用的是:

    {RIL_REQUEST_DIAL, dispatchDial, responseVoid},

    看来dispatchDial才是办实事的好同志,而dispatchDial中最终调用了s_callbacks,即之前通过 RIL_register(funcs),LibRIL 获得 Reference-RIL 的Interface 。

    s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);

    至此,终于进入了Reference-RIL。

    中场休息,做个简单的回顾:

    1. 我们构造了RequestInfo,pCI指向了对应的s_commands

    复制代码
    typedef struct RequestInfo {
        int32_t token;      //this is not RIL_Token
        CommandInfo *pCI;
        struct RequestInfo *p_next;
        char cancelled;
        char local;         // responses to local commands do not go back to command process
    } RequestInfo;
    复制代码

      2. CommandInfo中的dispatchFunction最终调用了Reference-RIL提供的接口。

    复制代码
    typedef struct {
        int requestNumber;
        void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
        int(*responseFunction) (Parcel &p, void *response, size_t responselen);
    } CommandInfo;
    复制代码

    3. RIL_RadioFunctions 便是RIL对Reference-RIL的实现要求。

    复制代码
    typedef struct {
        int version;        /* set to RIL_VERSION */
        RIL_RequestFunc onRequest;
        RIL_RadioStateRequest onStateRequest;
        RIL_Supports supports;
        RIL_Cancel onCancel;
        RIL_GetVersion getVersion;
    } RIL_RadioFunctions;
    复制代码

    4. onRequest 根据request号做出对应的处理,也就是ril_commands.h。

    复制代码
    /**
     * RIL_Request Function pointer
     *
     * @param request is one of RIL_REQUEST_*
     * @param data is pointer to data defined for that RIL_REQUEST_*
     *        data is owned by caller, and should not be modified or freed by callee
     * @param t should be used in subsequent call to RIL_onResponse
     * @param datalen the length of data
     *
     */
    typedef void (*RIL_RequestFunc) (int request, void *data,
                                        size_t datalen, RIL_Token t);
    复制代码

    RIL_RadioFunctions需要实现ril_commands.h中定义的request,当然,不一定全部支持。

       

      OK,继续 dialing...

    case RIL_REQUEST_DIAL:
           requestDial(data, datalen, t);

    终于要见到AT的影子:

    复制代码
    static void requestDial(void *data, size_t datalen, RIL_Token t)
    {
        RIL_Dial *p_dial;
        char *cmd;
        const char *clir;
        int ret;
    
        p_dial = (RIL_Dial *)data;
    
        switch (p_dial->clir) {
            case 1: clir = "I"; break;  /*invocation*/
            case 2: clir = "i"; break;  /*suppression*/
            default:
            case 0: clir = ""; break;   /*subscription default*/
        }
    
        asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
    
        ret = at_send_command(cmd, NULL);
    
        free(cmd);
    
        /* success or failure is ignored by the upper layer here.
           it will call GET_CURRENT_CALLS and determine success that way */
        RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
    }
    复制代码

      之后的事情便是将AT string通过某种通道发送给BP。至于这个通道的建立,可能是串口也可能是其他,但最终都会表现为一个文件描述符,这就是 rilInit 的事儿了。

    以上便是基于Dial的流程浏览,到这一层,重点还是对ril_commands.h, ril_unsol_commands.h的理解,"得此二物者得RIL"!

    NEXT, LET'S GO INTO BP.

     
     
    分类: Communication
  • 相关阅读:
    关系型数据库——主键&外键的
    JSON运用——PHP中使用json数据格式定义字面量对象的方法
    JSON.parse与eval的区别
    css中那些属性可以被继承
    js笔记 -- toString() 和String()
    MYSQL IFNULL函数的使用
    mysql临时表产生的执行效率问题改进(转)
    mysql中concat 和 group_concat()的用法
    转载mysql数据库配置优化
    浅谈MySql的存储引擎(转)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3169610.html
Copyright © 2020-2023  润新知