Communication - 03.RILC

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

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

 


  

  进入hardware\ril\rild\rild.c,一切从main开始。

int main(int argc, char **argv)
{
    ... ...

    dlHandle = dlopen(rilLibPath, RTLD_NOW);
    if (dlHandle == NULL) {
        fprintf(stderr, "dlopen failed: %s\n", 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\n", 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

// 每次监视的最大的文件描述符句柄数,可以根据需要自行修改
#define MAX_FD_EVENTS 8

// ril_event的回调函数
typedef void (*ril_event_cb)(int fd, short events, void *userdata);

struct ril_event {
    // 用于将ril_event串成双向链表的前向指针和后向指针
    struct ril_event *next;
    struct ril_event *prev;
    
    //ril事件相关的文件描述符句柄(可以是文件、管道、Socket等)
    int fd;
    
    //这个事件在监控列表中的索引
    int index;
    
    //当一个事件处理完后(即从watch_table移到pending_list中等待处理),
    //persist参数决定这个事件是否一直存在于监控列表watch_table[]中
    bool persist;
    
    //事件的超时时间
    struct timeval timeout;
    
    //回调函数及其传入的参数
    ril_event_cb func;
    void *param;
};

//以下是ril事件相关的一些操作函数
// 初始化内部数据结构
void ril_event_init();

// 初始化一个ril事件
void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param);

// 将事件添加到监控列表watch_table[]中
void ril_event_add(struct ril_event * ev);

// 增加一个timer事件到timer_list链表中
void ril_timer_add(struct ril_event * ev, struct timeval * tv);

// 将指定的事件从监控列表watch_table[]中移除
void ril_event_del(struct ril_event * ev);

// 事件循环
void ril_event_loop();
View Code

ril_event.c

#define LOG_TAG "RILC"

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <utils/Log.h>
#include <ril_event.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>

#include <pthread.h>

// 使用互斥量mutex进行线程同步,可参见《Linux程序设计》相关章节
static pthread_mutex_t listMutex;
#define MUTEX_ACQUIRE() pthread_mutex_lock(&listMutex)
#define MUTEX_RELEASE() pthread_mutex_unlock(&listMutex)
#define MUTEX_INIT() pthread_mutex_init(&listMutex, NULL)
#define MUTEX_DESTROY() pthread_mutex_destroy(&listMutex)

// 两个timeval类型的值相加
#ifndef timeradd
#define timeradd(tvp, uvp, vvp)                        \
    do {                                \
        (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;        \
        (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
        if ((vvp)->tv_usec >= 1000000) {            \
            (vvp)->tv_sec++;                \
            (vvp)->tv_usec -= 1000000;            \
        }                            \
    } while (0)
#endif

// 两个timeval类型的值进行比较
#ifndef timercmp
#define timercmp(a, b, op)               \
        ((a)->tv_sec == (b)->tv_sec      \
        ? (a)->tv_usec op (b)->tv_usec   \
        : (a)->tv_sec op (b)->tv_sec)
#endif

// 两个timeval类型的值相减
#ifndef timersub
#define timersub(a, b, res)                           \
    do {                                              \
        (res)->tv_sec = (a)->tv_sec - (b)->tv_sec;    \
        (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
        if ((res)->tv_usec < 0) {                     \
            (res)->tv_usec += 1000000;                \
            (res)->tv_sec -= 1;                       \
        }                                             \
    } while(0);
#endi

// 保存Rild中所有设备文件句柄,便于使用select函数完成事件的监听
static fd_set readFds;
// 记录readFds中最大fd值+1
static int nfds = 0;

// 为了统一管理ril事件,Android提供如下三个队列:
// 监控事件列表,需要检测的事件都需要先存入该列表中
static struct ril_event * watch_table[MAX_FD_EVENTS];

// timer事件队列,事件超时后即移入pending_list队列中
static struct ril_event timer_list;

// 待处理的事件队列,即事件已经触发,后续需要调用事件的回调函数
static struct ril_event pending_list;

#define DEBUG 0

#if DEBUG
#define dlog(x...) LOGD( x )
static void dump_event(struct ril_event * ev)
{
    dlog("~~~~ Event %x ~~~~", (unsigned int)ev);
    dlog("     next    = %x", (unsigned int)ev->next);
    dlog("     prev    = %x", (unsigned int)ev->prev);
    dlog("     fd      = %d", ev->fd);
    dlog("     pers    = %d", ev->persist);
    dlog("     timeout = %ds + %dus", (int)ev->timeout.tv_sec, (int)ev->timeout.tv_usec);
    dlog("     func    = %x", (unsigned int)ev->func);
    dlog("     param   = %x", (unsigned int)ev->param);
    dlog("~~~~~~~~~~~~~~~~~~");
}
#else
#define dlog(x...) do {} while(0)
#define dump_event(x) do {} while(0)
#endif

// 获取此刻timeval值
static void getNow(struct timeval * tv)
{
#ifdef HAVE_POSIX_CLOCKS
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    tv->tv_sec = ts.tv_sec;
    tv->tv_usec = ts.tv_nsec/1000;
#else
    gettimeofday(tv, NULL);
#endif
}

// 初始化指定的ril_event链表
static void init_list(struct ril_event * list)
{
    memset(list, 0, sizeof(struct ril_event));
    list->next = list;
    list->prev = list;
    list->fd = -1;
}

// 增加一个ril_event事件到ril_event队列头
static void addToList(struct ril_event * ev, struct ril_event * list)
{
    ev->next = list;
    ev->prev = list->prev;
    ev->prev->next = ev;
    list->prev = ev;
    dump_event(ev);
}

// 从ril_event队列中移除指定的ril_event
static void removeFromList(struct ril_event * ev)
{
    dlog("~~~~ Removing event ~~~~");
    dump_event(ev);

    ev->next->prev = ev->prev;
    ev->prev->next = ev->next;
    ev->next = NULL;
    ev->prev = NULL;
}

// 从watch_table[]中移除指定索引的事件
static void removeWatch(struct ril_event * ev, int index)
{
    // 索引index对应的事件置为空,同时事件ev的索引设为无效值-1
    watch_table[index] = NULL;
    ev->index = -1;

    // 将该事件对应的文件描述符句柄从readFds中清除
    FD_CLR(ev->fd, &readFds);

    if (ev->fd+1 == nfds) {
        int n = 0;

        for (int i = 0; i < MAX_FD_EVENTS; i++) {
            struct ril_event * rev = watch_table[i];

            if ((rev != NULL) && (rev->fd > n)) {
                n = rev->fd;
            }
        }
        nfds = n + 1;
        dlog("~~~~ nfds = %d ~~~~", nfds);
    }
}

// 遍历timer_list队列中的事件,当事件超时时间到时
// 将事件移除,并添加到pending_list队列中
static void processTimeouts()
{
    dlog("~~~~ +processTimeouts ~~~~");
    MUTEX_ACQUIRE();
    struct timeval now;
    struct ril_event * tev = timer_list.next;
    struct ril_event * next;

    getNow(&now);
    // walk list, see if now >= ev->timeout for any events

    dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
    while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
        // Timer expired
        dlog("~~~~ firing timer ~~~~");
        next = tev->next;
        removeFromList(tev);
        addToList(tev, &pending_list);
        tev = next;
    }
    MUTEX_RELEASE();
    dlog("~~~~ -processTimeouts ~~~~");
}

// 遍历监控列表watch_table[]中的事件,并将有数据可读的事件
// 添加到pending_list链表中,同时如果事件的persist不为true
// 则将该事件从watch_table[]中移除
static void processReadReadies(fd_set * rfds, int n)
{
    dlog("~~~~ +processReadReadies (%d) ~~~~", n);
    MUTEX_ACQUIRE();

    for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
        struct ril_event * rev = watch_table[i];
        if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
            addToList(rev, &pending_list);
            if (rev->persist == false) {
                removeWatch(rev, i);
            }
            n--;
        }
    }

    MUTEX_RELEASE();
    dlog("~~~~ -processReadReadies (%d) ~~~~", n);
}

// 依次调用待处理队列pending_list中的事件的回调函数
static void firePending()
{
    dlog("~~~~ +firePending ~~~~");
    struct ril_event * ev = pending_list.next;
    while (ev != &pending_list) {
        struct ril_event * next = ev->next;
        removeFromList(ev);
        ev->func(ev->fd, 0, ev->param);
        ev = next;
    }
    dlog("~~~~ -firePending ~~~~");
}


// 计算timer_list链表中下一个事件的新的超时时间
static int calcNextTimeout(struct timeval * tv)
{
    struct ril_event * tev = timer_list.next;
    struct timeval now;

    getNow(&now);

    // Sorted list, so calc based on first node
    if (tev == &timer_list) {
        // no pending timers
        return -1;
    }

    dlog("~~~~ now = %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
    dlog("~~~~ next = %ds + %dus ~~~~",
            (int)tev->timeout.tv_sec, (int)tev->timeout.tv_usec);
    if (timercmp(&tev->timeout, &now, >)) {
        timersub(&tev->timeout, &now, tv);
    } else {
        // timer already expired.
        tv->tv_sec = tv->tv_usec = 0;
    }
    return 0;
}

// 初始化内部数据结构(互斥量、FD集合、三个事件队列)
void ril_event_init()
{
    MUTEX_INIT();

    FD_ZERO(&readFds);
    init_list(&timer_list);
    init_list(&pending_list);
    memset(watch_table, 0, sizeof(watch_table));
}

// 初始化一个ril事件
void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param)
{
    dlog("~~~~ ril_event_set %x ~~~~", (unsigned int)ev);
    memset(ev, 0, sizeof(struct ril_event));
    ev->fd = fd;
    ev->index = -1;
    ev->persist = persist;
    ev->func = func;
    ev->param = param;
    
    //linux的文件上锁函数,给文件描述符fd上非阻塞的文件锁
    fcntl(fd, F_SETFL, O_NONBLOCK);
}

// 将事件添加到监控列表watch_table[]中
void ril_event_add(struct ril_event * ev)
{
    dlog("~~~~ +ril_event_add ~~~~");
    MUTEX_ACQUIRE();
    for (int i = 0; i < MAX_FD_EVENTS; i++) {
        if (watch_table[i] == NULL) {
            watch_table[i] = ev;
            ev->index = i;
            dlog("~~~~ added at %d ~~~~", i);
            dump_event(ev);
            FD_SET(ev->fd, &readFds);
            if (ev->fd >= nfds) nfds = ev->fd+1;
            dlog("~~~~ nfds = %d ~~~~", nfds);
            break;
        }
    }
    MUTEX_RELEASE();
    dlog("~~~~ -ril_event_add ~~~~");
}

// 增加一个timer事件到timer_list链表中
void ril_timer_add(struct ril_event * ev, struct timeval * tv)
{
    dlog("~~~~ +ril_timer_add ~~~~");
    MUTEX_ACQUIRE();

    struct ril_event * list;
    if (tv != NULL) {
        // add to timer list
        list = timer_list.next;
        ev->fd = -1; // make sure fd is invalid

        struct timeval now;
        getNow(&now);
        timeradd(&now, tv, &ev->timeout);

        // 根据timeout值从小到大在链表中排序
        while (timercmp(&list->timeout, &ev->timeout, < )
                && (list != &timer_list)) {
            list = list->next;
        }
        // 循环结束后,list指向链表中第一个timeout值大于ev的事件
    // 将新加入的事件ev加到list此刻指向的事件前面
        addToList(ev, list);
    }

    MUTEX_RELEASE();
    dlog("~~~~ -ril_timer_add ~~~~");
}

// 将事件从watch_table[]中移除
void ril_event_del(struct ril_event * ev)
{
    dlog("~~~~ +ril_event_del ~~~~");
    MUTEX_ACQUIRE();

    if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) {
        MUTEX_RELEASE();
        return;
    }

    removeWatch(ev, ev->index);

    MUTEX_RELEASE();
    dlog("~~~~ -ril_event_del ~~~~");
}

#if DEBUG
// 打印监控列表中可用的事件
static void printReadies(fd_set * rfds)
{
    for (int i = 0; (i < MAX_FD_EVENTS); i++) {
        struct ril_event * rev = watch_table[i];
        if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
          dlog("DON: fd=%d is ready", rev->fd);
        }
    }
}
#else
#define printReadies(rfds) do {} while(0)
#endif

void ril_event_loop()
{
    int n;
    fd_set rfds;
    struct timeval tv;
    struct timeval * ptv;

    for (;;) {
        // make local copy of read fd_set
        memcpy(&rfds, &readFds, sizeof(fd_set));
    // 根据timer_list来计算select函数的等待时间
    // timer_list之前已按事件的超时时间排好序了
        if (-1 == calcNextTimeout(&tv)) {
            // no pending timers; block indefinitely
            dlog("~~~~ no timers; blocking indefinitely ~~~~");
            ptv = NULL;
        } else {
            dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
            ptv = &tv;
        }
        printReadies(&rfds);
    // 使用select函数实现多路IO复用
        n = select(nfds, &rfds, NULL, NULL, ptv);
        printReadies(&rfds);
        dlog("~~~~ %d events fired ~~~~", n);
        if (n < 0) {
            if (errno == EINTR) continue;

            LOGE("ril_event: select error (%d)", errno);
            // bail?
            return;
        }

        // Check for timeouts
        processTimeouts();
        // Check for read-ready
        processReadReadies(&rfds, n);
        // Fire away
        firePending();
    }
}
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

  1     {0, NULL, NULL},                   //none
  2     {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus},
  3     {RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts},
  4     {RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts},
  5     {RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts},
  6     {RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts},
  7     {RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts},
  8     {RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts},
  9     {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, dispatchStrings, responseInts},
 10     {RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
 11     {RIL_REQUEST_DIAL, dispatchDial, responseVoid},
 12     {RIL_REQUEST_GET_IMSI, dispatchVoid, responseString},
 13     {RIL_REQUEST_HANGUP, dispatchInts, responseVoid},
 14     {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, dispatchVoid, responseVoid},
 15     {RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, dispatchVoid, responseVoid},
 16     {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, dispatchVoid, responseVoid},
 17     {RIL_REQUEST_CONFERENCE, dispatchVoid, responseVoid},
 18     {RIL_REQUEST_UDUB, dispatchVoid, responseVoid},
 19     {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, dispatchVoid, responseInts},
 20     {RIL_REQUEST_SIGNAL_STRENGTH, dispatchVoid, responseRilSignalStrength},
 21     {RIL_REQUEST_VOICE_REGISTRATION_STATE, dispatchVoid, responseStrings},
 22     {RIL_REQUEST_DATA_REGISTRATION_STATE, dispatchVoid, responseStrings},
 23     {RIL_REQUEST_OPERATOR, dispatchVoid, responseStrings},
 24     {RIL_REQUEST_RADIO_POWER, dispatchInts, responseVoid},
 25     {RIL_REQUEST_DTMF, dispatchString, responseVoid},
 26     {RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},
 27     {RIL_REQUEST_SEND_SMS_EXPECT_MORE, dispatchStrings, responseSMS},
 28     {RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall},
 29     {RIL_REQUEST_SIM_IO, dispatchSIM_IO, responseSIM_IO},
 30     {RIL_REQUEST_SEND_USSD, dispatchString, responseVoid},
 31     {RIL_REQUEST_CANCEL_USSD, dispatchVoid, responseVoid},
 32     {RIL_REQUEST_GET_CLIR, dispatchVoid, responseInts},
 33     {RIL_REQUEST_SET_CLIR, dispatchInts, responseVoid},
 34     {RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, dispatchCallForward, responseCallForwards},
 35     {RIL_REQUEST_SET_CALL_FORWARD, dispatchCallForward, responseVoid},
 36     {RIL_REQUEST_QUERY_CALL_WAITING, dispatchInts, responseInts},
 37     {RIL_REQUEST_SET_CALL_WAITING, dispatchInts, responseVoid},
 38     {RIL_REQUEST_SMS_ACKNOWLEDGE, dispatchInts, responseVoid},
 39     {RIL_REQUEST_GET_IMEI, dispatchVoid, responseString},
 40     {RIL_REQUEST_GET_IMEISV, dispatchVoid, responseString},
 41     {RIL_REQUEST_ANSWER,dispatchVoid, responseVoid},
 42     {RIL_REQUEST_DEACTIVATE_DATA_CALL, dispatchStrings, responseVoid},
 43     {RIL_REQUEST_QUERY_FACILITY_LOCK, dispatchStrings, responseInts},
 44     {RIL_REQUEST_SET_FACILITY_LOCK, dispatchStrings, responseInts},
 45     {RIL_REQUEST_CHANGE_BARRING_PASSWORD, dispatchStrings, responseVoid},
 46     {RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, dispatchVoid, responseInts},
 47     {RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, dispatchVoid, responseVoid},
 48     {RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, dispatchString, responseVoid},
 49     {RIL_REQUEST_QUERY_AVAILABLE_NETWORKS , dispatchVoid, responseStrings},
 50     {RIL_REQUEST_DTMF_START, dispatchString, responseVoid},
 51     {RIL_REQUEST_DTMF_STOP, dispatchVoid, responseVoid},
 52     {RIL_REQUEST_BASEBAND_VERSION, dispatchVoid, responseString},
 53     {RIL_REQUEST_SEPARATE_CONNECTION, dispatchInts, responseVoid},
 54     {RIL_REQUEST_SET_MUTE, dispatchInts, responseVoid},
 55     {RIL_REQUEST_GET_MUTE, dispatchVoid, responseInts},
 56     {RIL_REQUEST_QUERY_CLIP, dispatchVoid, responseInts},
 57     {RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, dispatchVoid, responseInts},
 58     {RIL_REQUEST_DATA_CALL_LIST, dispatchVoid, responseDataCallList},
 59     {RIL_REQUEST_RESET_RADIO, dispatchVoid, responseVoid},
 60     {RIL_REQUEST_OEM_HOOK_RAW, dispatchRaw, responseRaw},
 61     {RIL_REQUEST_OEM_HOOK_STRINGS, dispatchStrings, responseStrings},
 62     {RIL_REQUEST_SCREEN_STATE, dispatchInts, responseVoid},
 63     {RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, dispatchInts, responseVoid},
 64     {RIL_REQUEST_WRITE_SMS_TO_SIM, dispatchSmsWrite, responseInts},
 65     {RIL_REQUEST_DELETE_SMS_ON_SIM, dispatchInts, responseVoid},
 66     {RIL_REQUEST_SET_BAND_MODE, dispatchInts, responseVoid},
 67     {RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, dispatchVoid, responseInts},
 68     {RIL_REQUEST_STK_GET_PROFILE, dispatchVoid, responseString},
 69     {RIL_REQUEST_STK_SET_PROFILE, dispatchString, responseVoid},
 70     {RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, dispatchString, responseString},
 71     {RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, dispatchString, responseVoid},
 72     {RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, dispatchInts, responseVoid},
 73     {RIL_REQUEST_EXPLICIT_CALL_TRANSFER, dispatchVoid, responseVoid},
 74     {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, dispatchInts, responseVoid},
 75     {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, dispatchVoid, responseInts},
 76     {RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, dispatchVoid, responseCellList},
 77     {RIL_REQUEST_SET_LOCATION_UPDATES, dispatchInts, responseVoid},
 78     {RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, dispatchInts, responseVoid},
 79     {RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, dispatchInts, responseVoid},
 80     {RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, dispatchVoid, responseInts},
 81     {RIL_REQUEST_SET_TTY_MODE, dispatchInts, responseVoid},
 82     {RIL_REQUEST_QUERY_TTY_MODE, dispatchVoid, responseInts},
 83     {RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, dispatchInts, responseVoid},
 84     {RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, dispatchVoid, responseInts},
 85     {RIL_REQUEST_CDMA_FLASH, dispatchString, responseVoid},
 86     {RIL_REQUEST_CDMA_BURST_DTMF, dispatchStrings, responseVoid},
 87     {RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY, dispatchString, responseVoid},
 88     {RIL_REQUEST_CDMA_SEND_SMS, dispatchCdmaSms, responseSMS},
 89     {RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, dispatchCdmaSmsAck, responseVoid},
 90     {RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseGsmBrSmsCnf},
 91     {RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, dispatchGsmBrSmsCnf, responseVoid},
 92     {RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid},
 93     {RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseCdmaBrSmsCnf},
 94     {RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG, dispatchCdmaBrSmsCnf, responseVoid},
 95     {RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid},
 96     {RIL_REQUEST_CDMA_SUBSCRIPTION, dispatchVoid, responseStrings},
 97     {RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, dispatchRilCdmaSmsWriteArgs, responseInts},
 98     {RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, dispatchInts, responseVoid},
 99     {RIL_REQUEST_DEVICE_IDENTITY, dispatchVoid, responseStrings},
100     {RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, dispatchVoid, responseVoid},
101     {RIL_REQUEST_GET_SMSC_ADDRESS, dispatchVoid, responseString},
102     {RIL_REQUEST_SET_SMSC_ADDRESS, dispatchString, responseVoid},
103     {RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, dispatchInts, responseVoid},
104     {RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, dispatchVoid, responseVoid},
105     {RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, dispatchVoid, responseInts},
106     {RIL_REQUEST_ISIM_AUTHENTICATION, dispatchString, responseString}
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\ril\include\telephony\Ril.h

 1     {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
 2     {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
 3     {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
 4     {RIL_UNSOL_RESPONSE_NEW_SMS, responseString, WAKE_PARTIAL},
 5     {RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, responseString, WAKE_PARTIAL},
 6     {RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, responseInts, WAKE_PARTIAL},
 7     {RIL_UNSOL_ON_USSD, responseStrings, WAKE_PARTIAL},
 8     {RIL_UNSOL_ON_USSD_REQUEST, responseVoid, DONT_WAKE},
 9     {RIL_UNSOL_NITZ_TIME_RECEIVED, responseString, WAKE_PARTIAL},
10     {RIL_UNSOL_SIGNAL_STRENGTH, responseRilSignalStrength, DONT_WAKE},
11     {RIL_UNSOL_DATA_CALL_LIST_CHANGED, responseDataCallList, WAKE_PARTIAL},
12     {RIL_UNSOL_SUPP_SVC_NOTIFICATION, responseSsn, WAKE_PARTIAL},
13     {RIL_UNSOL_STK_SESSION_END, responseVoid, WAKE_PARTIAL},
14     {RIL_UNSOL_STK_PROACTIVE_COMMAND, responseString, WAKE_PARTIAL},
15     {RIL_UNSOL_STK_EVENT_NOTIFY, responseString, WAKE_PARTIAL},
16     {RIL_UNSOL_STK_CALL_SETUP, responseInts, WAKE_PARTIAL},
17     {RIL_UNSOL_SIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL},
18     {RIL_UNSOL_SIM_REFRESH, responseInts, WAKE_PARTIAL},
19     {RIL_UNSOL_CALL_RING, responseCallRing, WAKE_PARTIAL},
20     {RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, responseVoid, WAKE_PARTIAL},
21     {RIL_UNSOL_RESPONSE_CDMA_NEW_SMS, responseCdmaSms, WAKE_PARTIAL},
22     {RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, responseRaw, WAKE_PARTIAL},
23     {RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL},
24     {RIL_UNSOL_RESTRICTED_STATE_CHANGED, responseInts, WAKE_PARTIAL},
25     {RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL},
26     {RIL_UNSOL_CDMA_CALL_WAITING, responseCdmaCallWaiting, WAKE_PARTIAL},
27     {RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, responseInts, WAKE_PARTIAL},
28     {RIL_UNSOL_CDMA_INFO_REC, responseCdmaInformationRecords, WAKE_PARTIAL},
29     {RIL_UNSOL_OEM_HOOK_RAW, responseRaw, WAKE_PARTIAL},
30     {RIL_UNSOL_RINGBACK_TONE, responseInts, WAKE_PARTIAL},
31     {RIL_UNSOL_RESEND_INCALL_MUTE, responseVoid, WAKE_PARTIAL},
32     {RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, responseInts, WAKE_PARTIAL},
33     {RIL_UNSOL_CDMA_PRL_CHANGED, responseInts, WAKE_PARTIAL},
34     {RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL},
35     {RIL_UNSOL_RIL_CONNECTED, responseInts, WAKE_PARTIAL}
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.

 


 

 

进入BP,简略一聊。先不谈从AP发来的AT指令做何处理,这是电信的范畴,涉及到众多协议以及核心网的概念,先就BP本身RF的一些基本功能聊些简单的话题。

RF (Radio Frequency),就是中学物理所讲的无线电波,这样说来也不觉有什么陌生,其实就是如此。

射频(RF)是Radio Frequency的缩写,表示可以辐射到空间的电磁频率,频率范围从300KHz~30GHz之间。(>10KHZ,高频电流)

在电子学理论中,电流流过导体,导体周围会形成磁场;交变电流通过导体,导体周围会形成交变的电磁场,称为电磁波。
在电磁波频率低于100khz时,电磁波会被地表吸收,不能形成有效的传输,但电磁波频率高于100khz时,电磁波可以在空气中传播,并经大气层外缘的电离层反射,形成远距离传输能力,我们把具有远距离传输能力的高频电磁波称为射频

我们的最终目的就是:用一定的功率发射出一定频率的无线电波

疑问来了,一定的频率到底是多少? 

<工作频段>
中国陆地公用蜂窝数字移动通信网GSM通信系统采用900MHz频段:
890~915(移动台发、基站收)
935~960(基站发、移动台收)
双工间隔为45MHz,工作带宽为25 MHz,载频间隔为200 kHz。即25×1000/200-1=124个频点。
随着业务的发展,可视需要向下扩展,或向1.8GHz频段的GSM1800过渡,即1800MHz频段: 1710~1785(移动台发、基站收) 1805~1880(基站发、移动台收) 双工间隔为95MHz,工作带宽为75 MHz,载频间隔为200 kHz。即75×1000/2000-1=374个频点。
<频道间隔> 相邻两频道间隔为200kHz。 每个频道采用时分多址接入(TDMA)方式,分为8个时隙,即8个信道(全速率)。每信道占用带宽200 kHz/8=25 kHz。 将来GSM采用半速率话音编码后,每个频道可容纳16个半速率信道。

 以上便是基于GSM的例子。频率越高,穿透性是强,但是衰减很大,覆盖不了多远。CDMA使用的800MHz频段和GSM使用的900MHz频段是公认的通话“黄金频段”。

 

RF的东西研究的深,则深不见底;若只考虑到应用,就目前的就业市场和国情对大部分人而言则比较现实。好运!

(补充:本人已跳出火坑^_^)

posted @ 2013-07-03 10:48  郝壹贰叁  阅读(5582)  评论(0编辑  收藏  举报