zoukankan      html  css  js  c++  java
  • 高通与At指令:AtCop解析

    背景

    在某个新基线上移植AT指令,发现有问题,因此收集了这个系列的 文章 作为 这方面的知识补充。

    原文作者:laozhuxinlu,本文有删改。

    另外,还参考了:https://www.cnblogs.com/hengfeng/archive/2009/12/05/1617537.html

    AT指令在产线中是一类比较重要的问题, 一天没来得及解决,则会拖延生产的有关进度。

    前言

    该篇主题主要介绍的是ATCommandProcessor。

    ATCoP是什么?ATCommandProcessor,是高通AMSS(modem)software下的一套对AT命令的具体实现模块,也只有真正弄懂ATCoP,才能真正的了解AT命令有关软件的实现。

    下面,我将就:

    • AtCoP具体功能

    • AtCoP实现架构

    • AtCoP处理流程

    • At命令解析(ATCommand Parser)

    • At命令表(ATCommand Table)

    这四个方面来做具体介绍,学习完,便能结合具体的实例具体的去分析整个的AT命令实现,也只有在深入了解ATCoP的基础上,才能实现对ATCommand的修改和新增。

    AtCoP具体功能

    ATCoP,ATCommand processor,AT命令处理器。是对AT命令具体软件实现的模块,通过ATCoP,我们可以实现对AT命令的修改和新增。

    这个部分是由modem侧(BP侧)实现的。

    基本上它遵循以下过程:

    串口(sio)接收到串口发送过来的字符串--> AT Command Parser --> 产生一个重要的Token结构,它包含了命令名称,接收到的参数,以及response的buffer--> 之后AT Command ProcessorProcess 通过Token里面的信息查调用相应的AT 命令处理函数 -->处理完成后产生相应的response给TE。

    简单的来说,ATCoP接收串口(Serial Port)处传来的ATCommand,进行解析(Parse),根据解析的结果到ATCommand Tables中寻找相应的表项,若匹配,则执行对应的处理函数,处理完以后response其对应的返回数据到串口。

    目前,Qualcomm(高通)DMSS采用IS-707AT Command Set作为它的DataServices的命令集。

    下面列举出与ATCoP相关的一些主要的资源目录:

    filename Description
    Dsat.h ATCoP外部模块使用的定义,函数和数据结构
    Dsat.h ATCoP外部模块使用的定义,函数和数据结构
    Dsati.h ATCoP内部使用的定义,函数和数据结构
    Dsatprep.c 接收自串口设备的数据的预处理
    Dsatpar.c AT命令解析器,将命令行的AT命令解析到token结构中
    Dsatcmdp.c AT命令处理器,查找token结构中的包含的命令并从命令列表中调用相应的命令处理函数处理命令
    Dsatrsp.c 产生AT命令响应和格式化
    Dsatutil.c 产生AT命令处理器
    Dsatparm.c 通用AT参数类型命令过程
    Dsatarm.h ATCoP内部使用的通用AT参数类型命令处理定义,函数和数据结构
    Dsatact.c 通用ATactive type命令处理函数
    Dsatact.h 通用AT动作类型命令处理的定义、函数和数据结构,供ATCoP内部模块使用
    Dsatvend.c 通用AT指定提供商类型命令处理
    Dsatvend.h 通用AT指定提供商类型命令处理的定义、函数和数据结构,供ATCoP内部模块使用
    Dsatctab.c 通用AT命令表
    Dsatctab.h 通用AT命令表定义、函数和数据结构,供ATCoP内部模块使用
    Dsatcmif.c 通用呼叫管理接口
    Dsatcmif.h 通用呼叫管理接口定义、函数和数据结构,供ATCoP内部模块使用
    Dsatvoice.c 通用语音呼叫处理控制
    Dsatvoice.h 通用语音呼叫处理控制的定义、函数和数据结构,供ATCoP内部模块使用
    Dsatetsicall.c ETSI呼叫控制命令处理
    Dsatetsicall.h ETSI呼叫控制命令处理的定义、函数和数据结构,供ATCoP内部模块使用
    Dsatetsicmif.c ETSI命令呼叫管理接口
    Dsatetsicmif.h ETSI命令呼叫管理接口的定义、函数和数据结构,供ATCoP内部模块使用
    Dsatetsipkt.c ETSI包数据命令处理
    Dsatetsipkt.h ETSI包数据命令处理的定义、函数和数据结构,供ATCoP内部模块使用
    Dsatetsime.c ETSI移动设备命令处理
    Dsatetsime.h ETSI移动设备命令处理的定义、函数和数据结构,供ATCoP内部模块使用
    Dsatetsismsc.c ETSI短消息服务命令处理
    Dsatetsismsa.c ETSI短消息服务异步事件处理
    Dsatetsismsu.c ETSI短消息服务命令处理实体
    Dsatetsisms.h ETSI短消息服务命令处理的定义、函数和数据结构,供ATCoP内部模块使用
    Dsatetsismsi.h ETSI短消息服务命令处理的定义、函数和数据结构,供ATCoP内部模块的短消息服务单元使用
    Dsatetsictab.c ETSIAT命令表
    Dsatetsictab.h ETSIAT命令表的定义、函数和数据结构,供ATCoP内部模块使用
    Dsatetsitgt.c 顶层AT命令表,命令表指针数组,ETSI指定目标的命令表,同步事件处理表。定义ETSI目标支持的AT命令集
    Dsatgsmfax.c GSMfax命令处理
    Dsatgsmfax.h GSMfax命令处理的定义、函数和数据结构,供ATCoP内部模块使用

    数据服务任务源文件列表:

    filename Description
    Dstask.h 数据服务任务的外部或内部模块使用的定义,函数和数据结构
    Dsatsk.c 数据服务任务和顶层分发

    对修改或者新增一个AT命令主要涉及到的一些文件:

    The files of interest for adding new AT commands or modifying existing AT commands are:

    • dstask.c dstask.h dsat.h
    • dsati.h dsatutil.c dsatparm.c
    • dsatparm.h dsatact.c dsatact.h
    • dsatvend.c dsatvend.h dsatctab.c
    • dsatctab.h

    ATCoP实现架构

    首先我们来看一张图:

    ATCoP的基本架构主要有一下几个部分:

    • SIOData Preprocessor(SIO数据预处理模块)
    • ATCommand Parser(AT命令解析器)
    • ATCommand Processor(AT命令处理器)
    • ATCommand Response Generator(AT命令响应产生器)
    • ATCommand Tables and Command Processing Functionality(AT命令表及命令处理功能模块)

    1、通过串口设备(SIO)接收的AT命令数据,首先由SIO数据预处理,产生一个null-terminated命令行并由DS分发给AT命令解析器。

    2、产生的null-terminated命令行由AT命令解析器解析,解析器为每个要解析的命令产生一个token结构,并送到处理队列由AT命令处理器处理。在AT命令处理器被调用前,解析器将每个命令的token结构放入队列中。

    3、AT命令处理器完成对每个token结构进行表查找,同时将该token结构从队列中移除。如果查找到,对应的处理函数被调用处理该命令;AT命令在命令表中定义,每个命令表入口包含对应命令执行函数的指针。

    4、AT命令响应产生器将命令响应数据格式化,产生结果编码,并将响应数据发送给DTE。

    5、ATCOP每次处理一条AT命令行命令,如果任何命令行的命令产生一个错误,在错误前就会产生命令处理的响应,同时产生一个错误代码,不再对该命令进行后续处理。

    下面图同样展示的是ATCoP的实现框架,从USB接收到AT命令,到初始化创建SIO,再到命令的实际处理到返回,可详读下面这张图。

    ATCoP处理流程

    其实在ATCoP的实现架构就已经简单介绍到了ATCoP对AT命令的处理流程,在这我们将对其进行更加具体的详解。

    ATCoP处理控制流大致可以分有三个步:

    • Initial Parsing:初始化解析

    • CommandParsing:命令解析

    • Command Execution:命令执行处理(包括返回结果)

    1、InitialParsing:函数dsat_process_sio_command去掉命令行中的"AT"前缀,然后把以NULL结尾的命令行传给函数dsat_process_cmd_line来进行后续的分析和处理。dsatpar_parse_cmd_line函数完成对命令行的解析,检查每个AT命令的首字符然后根据AT命令的类型调用相应的解析函数。每个AT命令名(包括首符号,如,$QCDMG)以及相关的命令参数都被从命令行中解析出来,然后放到一个token data structure中。命令行中的每个命令都产生一个token structure,放到token排队上等待后续处理,此时一个命令行解析完成。一般添加或修改AT命令时不改动这部分代码。
    2、CommandParsing:根据命令的不同首字符,不同的解析函数解析AT命令后,把解析的信息填充到上一步产生的token data structure中,然后返回结果。如果结果是OK(意味着参数、参数个数以及特殊处理码special processing code等等都已经存好),此时token data structure已放在队列中等待AT命令处理器(ATcommand processor)后续处理。命令行中的每个命令都在队列中放一个token structure。例如,extendedor proprietary AT 命令调用的分析函数是parse_extended_cmd。
    3、每个命令产生的token structure被函数dsatcmdp_queue_token放入队列中。命令解析完成后,调用函数process_at_cmd_line处理队列中的每个token structure。从队列中取出并删除一个命令token structure后,在命令表中搜索该命令。顶层命令表(toplevel command table)在文件dsatetsitgt.c中。顶层命令表又指向文件dsatctab.c和dsatetsictab.c中的多个命令表,这些表定义了所支持的AT命令集。

    如果在表中查找到该命令,调用表中对应的处理函数执行该命令。命令执行后如果有返回数据时,返回的响应数据在函数dsat_fmt_response中格式化。每个token结构都进行这样的处理。最后调用函数dsatrsp_send_response把命令响应送到DTE。

    注:对于异步AT命令处理流程与正常AT命令略有不同,在命令预处理、命令解析过程都是一样的,在命令处理过程中(process_at_cmd_line),如果命令处理函数返回DSAT_OK,说明命令处理完成调用dsat_fmt_response函数格式化响应数据并发送,正常的命令处理流程;如果命令处理函数返回DSAT_ASYNC_CMD说明当 前 命 令 是 异 步 命 令 , 此 时 函 数process_at_cmd_line 设置 变 量dsatcmdp_processing_async_cmd= TRUE,表示当前正在处理异步命令,然后返回,不再进行后续处理,直到该命令处理完成,函数返回DSAT_OK(未必一定是DSAT_OK,当返回不是DSAT_ASYNC_CMD和DSAT_ASYNC_EVENT时,说明异步命令/事件处理完成)。当DS收到异步事件经任务分发器,再次调用dsat_process_async_cmd函数,在该函数中通过查找异步事件表async_event_table,调用相应的事件处理函数继续处理,如果事件处理函数返回值不是DSAT_ASYNC_CMD或DSAT_ASYNC_EVENT,说明异步事件处理完成,调用process_at_cmd_line继续处理命令行的命令。

    下面我们可以通过一个流程图更加直观的了解ATCoP的处理流程:

    基本遵循过程:

    SIOData Preprocessor接收串口发送过来的字符串(这里是AT Command),并向DS TASK发送信号要求其处理;DS TASK 知晓并获得控制权后,由AT Command Parser解析AT Command,将得到的结果存入相应的token结构中(包含了命令名称,接收到的参数,以及response的buffer);AT Command Processor到AT Command Tables匹配相应的表项;AT Command Response Generator根据匹配的结果调用对应的Command Processing Function进行处理;处理完成后产生相应的response给 TE。

    AT命令解析(ATCommand Parser)

    ATCommand Parser对命令行进行解析时,将解析的结果存到token中,并在下一步到Parse Table中进行匹配。

    下面就以代码流程具体展示:

    DS_AUTODETECT_SRVC_MODE模式下,串口检测到A字符,则发送DS_1ST_SIO_RX_SIG给DSTASK

    DSTASK调用dsi_mgr()进行分发处理

    ds_process_rxbuf_event()

    switch(dsi_callstate){
            caseDS_IDLE_CSTATE:
            ds_atcop_process_sio_command();
    }
    
    /*从watermark中取出data尝试建立一个命令行*/
    while(cc!=NULL)
    {
        cc = cce & 0x7F		//只使用高7位
            switch (at_state)
            {
                case HUNT:  
                    if (UPCASE (cc) == 'A')
                        //     转到FOUND_A状态
                        break;
                case FOUND_A:
                    if (UPCASE (cc) == '/')
                        //从buf取出上个AT命令来执行(ds_atcop()),执行完毕后转到HUNT状态
                        else if (UPCASE (cc) == 'T')
                            //转到CAT状态
                            else if (UPCASE (cc) != 'A')
                                //转到HUNT状态
                                break;
                case CAT:
                    if (cc != ds_atcop_s3_val) // if not EOL
                    {
                        if (cc != ds_atcop_s5_val) // if not backspace
                        {
                            if OVERFLOW
                                //转到ERROR状态
    
                                else if (cc >= 0x20 && cc <= 0x7E)
                                    //fill buffer;
                                    } // if backspace
                        else
                            // remove the most immediate character from the buffer
                    }
                    else 
                        if EOL
                            //对命令行进行处理(ds_atcop()),处理完毕后转到HUNT状态
                            break;
                case ERROR:
                    //执行相应出错处理,处理完毕后转到HUNT状态
                    break;
            }
    }
    //ds_atcop() 对命令行进行处理
    switch (UPCASE (*curr_char_ptr)){
        case '+':     /*  Extended format specified in IS-99  */
        case '$':     /*  Extended format proprietary command */
            //对命令行进行解析
            curr_char_ptr = ds_atcop_parse_ex (curr_char_ptr, &tok);
            if SUCCEED
                //根据解析的结果到parse table匹配,进行相应处理
                ds_atcop_exec_param_cmd ();
            //若匹配不到,则强制解析
            if (ds_atcop_result == DS_ATCOP_DO_HARD_PARSE)
                ds_atcop_hard_to_parse();
            break;
    }
    //If not originating or answering a call
    ds_atcop_fmt_response(); //generate a final result code
    if (ds_atcop_result == DS_ATCOP_CXT_ORIG){
        ds_atcop_discard_results();
    }
    else if (mode == DS_ATCOP_CMD){
        ds_atcop_send_results();//发送
    }
    

    其中涉及到的Token Struct数据结构:

    typedef struct 
    {
        byte working_at_line[MAX_LINE_SIZE]; // Stores command lines to be processed、Each line
        // is referenced by a line number
        byte *name;                       // The name of the AT command
        unsigned int op;                    // Syntax flags、Can be one of four valid values (NA, 
        // EQ, QU, AR) or an invalid value
        byte * arg[MAX_ARG];             // AT command arguments
        unsigned int args_found;             // Keeps track of the number of AT command 
        //arguments found
    } tokens_struct_type;
    

    AT命令表(ATCommand Table)

    AT命令的处理是由命令表驱动的,ATCOP实现的命令表是一个分级的表结构,主要分为:

    • 主表(master table)

    • 子表(sub table)

    • 命令表(command table)。

    其中主表是一个二维的数组,数组的行表示AT命令的分类,分为:

    • 基本AT命令(basic_table)

    • 寄存器AT命令(sreg_table)

    • 扩展AT命令(extended_table)

    • 厂商AT命令(vendor_table)

    四大类;数组的列表示是ETSI模式还是其它模式的AT命令。

    基本命令表

    基本命令的格式为:[]

    其中或者是单个字母(A-Z),或者是“&”字符接单个字母。

    是一个十进制数,可以是一位,也可以是多位。最前面的0会被忽略。默认为0。如果一个不带的基本命令带了,则返回TOO MANYPARAMETERS。

    寄存器命令表

    所有以字母“S”开头的命令统称为S寄存器命令,格式如下:

    S? S=

    S 寄存器命令名由字母“S”接上一个十进制数构成,这个十进制数称为寄存器序号(parameternumber)。如果寄存器序号不被识别,说明不存在该命令,返回COMMANDNOT SUPPORT。

    每个 S寄存器保存一个字符。命令名后面如果接“?”表示是READ命令,返回此S寄存器当前保存的字符的ASCII 码值,以3 位十进制数表示,位数不足的前面补0;如果接“=”表示是SET命令,将值对应的字符替换此S寄存器保存的字符。

    扩展命令和厂商命令表

    扩展命令均由“+”开头,厂商定义的命令也是由一个特殊符号开头,例如“$”,“%”等。本文中所实现的命令均为扩展命令。

    所有的扩展命令和厂商定义命令又可以分为两类:ActioncommandParameter command

    actioncommand

    action command 指完成某个具体的动作,而不仅仅是与MS 本地的参数打交道的命令,例如AT+CMGS 等。actioncommand 可以带参数也可以不带。

    Actioncommand 包含EXECUTION 命令和TEST 命令。

    (1)EXECUTION命令

    EXECUTION 命令格式如下:

    • 不带参数
    • 带 1个参数:[=]
    • 带多个参数:[=], 中间以“,”分隔表示多个参数。

    对于有默认值的参数,可以在命令中省略,此时以默认值代替。

    如果所有的参数都省略,则后面的“=”也一并略去。如果不被识别,则表示此命令不存在,返回COMMAND NOTSUPPORT。可识别的前提下,如果不能带参数的命令带了参数,或者参数个数超出定义,则返回TOOMANY PARAMETERS。

    (2)TEST命令

    TEST 命令格式:=?

    如果 MS不能识别,返回COMMAND NOT SUPPORT。如果MS可以识别,且命令是不带参数的,则返回OK。如果命令带参数,则先返回各个参数的可取值范围,最后再加上OK。

    parametercommand

    parameter command包括与MS本地的参数打交道的命令,这些参数有些会影响到atcioncommand的执行。

    parametercommand又分为SET命令、READ命令和TEST命令。

    1)SET命令

    命令格式为:带1个参数:[=]

    带多个参数:[=],表示多个参数,中间以“,”分隔。

    SET命令用于设置参数。对于有默认值的参数,可以在命令中省略,此时以默认值代替。如果所有的参数都省略,则后面的“=”也一并略去。如果不被识别,则表示此命令不存在,返回COMMAND NOTSUPPORT。可识别的前提下,如果不能带参数的命令 带了 参数 ,或者 参数 个数 超出 定义, 则返回TOO MANYPARAMETERS。

    2)READ命令

    命令格式:?

    READ 命令用于读取参数当前值。

    3)TEST命令

    命令格式:=?

    如果 MS不能识别,返回COMMAND NOTSUPPORT。如果MS可以识别,且命令是不带参数的,则返回OK。如果命令带参数,则先返回各个参数的可取值范围,最后再加上OK。

    命令表项(主表定义dsati.h)

    typedef struct dsati_cmd_struct
    {
        byte name[20];           // AT cmd 的名字,包含"+", "$" 等
        uint32 attrib;             // AT cmd 的属性
        byte special;             // AT cmd 的 special processing code
        byte compound;          // 传递的参数个数(若参数为字符串,则是它的最大长度)
        const void *val_ptr;       // 指向参数的指针
        const void *def_lim_ptr;   // 定义了参数的默认值以及取值范围
        dsat_result_enum_type (*proc_func)( dsat_mode_enum_type,
        const struct dsati_cmd_struct*,
        const tokens_struct_type*,
        dsm_item_type* );
        boolean (*abort_func)( const struct dsati_cmd_struct* );
    } dsati_cmd_type;
    

    针对不同的软件版本可能对应的dsati_cmd_type定义略有差别。

    详解:

    1、name: AT命令名,包括需要处理的+,(,&和终止的NULL。如+IPR,)QCDMG, S6,&C,Z。

    2、attitude: 32位的掩码,用来指定单个或多个命令属性。表4.1列出了AT命令的所有属性,后面给出了具有该属性的命令。

    3、special: 如果有需要,就指定处理编码,否则就是SPECIAL_NONE,指定处理编码定义在dsati.h。只是用在与外部软件的兼容性时。

    表1 AT命令属性列表

    Attribute Description Examples
    ATTRIB_ NODE AT命令没有属性 &V
    CONFIG AT命令具有一个或多个参数 S3
    FCLASS2P0 Fax Class 2.0命令,+FCLASS=2 0否则返回 错误代码,ETSI命令没有使用
    LOCAL_TEST 测试命令在本地执行。该属性应该设置在 命令中以后支持,在IS-707-A.3
    ALWAYS 该参数通常给基站,其默认值为制造商指 定的
    SIMPLE _DEC 该参数格式为前面补0的3位十进制数 &C,E
    STRING 字符型参数 +CSCA,+CSMP
    HEX 16进制格式的参数,不需要0x或是h
    EXTENDED 用于扩展语法(命令以+或是$开始),扩展 语法在ITUT V25ter中定义 +IPR$QCDMG
    READ_ONLY AT命令没有任何参数,但返回一个值 +GM,+GSN
    DOWN LOAD 参数值(如果与默认值不同)传送给基站, 以后支持 S3
    LIST AT命令的参数是数字,字母或字符串 +IPR
    MIXED__PARAM AT侖令参数是规定值的字符串或是某一范 围的数字,或是限定长度的字符串。每个 参数都根据类型单独处理 +CSCA,+CSMP
    NO_QUOTE 用于显示read命令中的字符串参数 +CSCA,$QCDNSP
    YES_QUOTE 与NO_QUOTE相反,字符串参数quote显 示。NO_QUOTE和YES QUOTE +CPBS,+CSCA
    RESTRICTED 当ME在限制服务状态时,AT命令被处理。 没有设置该属性的命令不会被处理 +CGM,+CPAS
    NO_DISPLAY Read命令的返回参数不显示 $QCPDPP
    BROKED_RANGE AT命令的数字参数没有范围限制 +CGQREQ
    NO _RESET 重启命令(Z,&F)不改变参数值 +CGSMS

    4、compound

    1)dsati_cmd_struct*是dsati_cmd_struct结构入口指针,对于包含这个命令表入口指定命令。

    2)token_struct_type*是一个定义好的token structure解析器指针,这个token结构包含处理该命令所要求的信息。

    3)dsm_item_type*是DSMbuffer的指针,存储命令响应。如果命令响应超出了一个DSMbuffer的容量,可以将多个DSMbuffer可以链接到一起。函数返回类型

    应该是表 .3列出值中的一个。

    表4.3函数返回类型表

    Value Description
    DSAT_OK OK返回表示命令执行成功
    DSAT_ERROR ERROR返回表示命令执行失败
    DSTA_NO_REP 返回表示没有命令响应从DTE发送到AT命令处理器
    DSAT_CMD_ERP_ RSP 发送指定命令错误响应,存储在DSM buffer中
    DSAT_ASYNC_CMD 表示 命令以异步方式处理, 并在随后接收来自数据服务器任务分 发的异步命令事件。
    当命令处理完成,这些异步事件被标识处理完成,这样后续的命令将会被处理。

    8、abortfunction ptr

    函数指针通过命令表入口调用定义的abort命令,函数指针值不是NULL表示命令表入口定义的命令是可以abort的。函数指针参数是:dsati_cmd_struct*是dsati_cmd_struct结构入口指针,用于指示包含该命令表入口的指定命令。函数返回类型是一个Boolen表示:如果值是TRUE,表示数据调用可以通过DsmgrAbort,否则不需要任何动作。

    9、dflm_type

    定义AT命令中数字参数的最大值和最小值参数,这里的数字参数一定是连续的取值类型。如果参数取值为{0,1,255}这种参数应该设置为list类型。Default_v为默认值,lower和upper为最小和最大取值。

    10、def_list_type

    用于定义LIST类型的参数取值范围,其中:

    • Default_v代表参数的默认值,它是指向list_v数组的指针。

    List_v是一个8-byte字符串的数组指针,代表该参数允许的所有值,数组的最后一项必须是NULL来终止参数列表。AT命令处理器完成该数组的字符串匹配,以决定参数值是否在有效的范围内。

    List_t是一个字符串指针,逐字返回测试命令的响应。

    AT命令如果含有多个参数,每个参数都关联于def_list_type结构。

    11、mixed_def_s_type和dsat_mixed_param_val_type

    Mixed_def_s_type用于存储AT命令中混合参数的默认值和可能值,混合参数类型表示AT命令的参数可以是不同类型的,其允许值范围也是个集合,如果是数值类型需要指定在某一范围内,如果是字符串类型则限定长度。如果命令有N个不同类型参数,默认的可能值范围包含一个长度为N的mixed_def_s_type数组,类型参数i是数组下标,如mixed_argus[]定义为mixed_argus[i].attrib。如果AT命令有N种不同类型参数,参数的当前值包含在长度为N的dsat_mixed_param_val_type数组中。该数组用于联系mixed_def_s_type数组Dsat_mixed_param_val_type数组下标为i的元素,在mixed_def_s_type数组对应i分量为该AT命令的默认和可能的范围值。

    其实,针对于ATCoP的学习是比较混乱的,因为本身的内容就比较混杂,如果不是对整个架构比较清楚的话,很难学得清楚,并且就后面所要展开的AT Commands的自定义实现是在这一章的基础上实现的。

    在这我主要也是就ATCoP的标准协议文档进行翻译理解,并结合网上和个人的一些总结进行整理,希望有帮助。

    在ATCoP 中添加AT指令

    参考:https://www.cnblogs.com/hengfeng/archive/2009/12/05/1617537.html

    基本流程

    ATCoP(AT Command Processor)是高通平台上对于AT命令处理的模块。基本上它遵循以下过程:

    串口(sio)接收到串口发送过来的字符串--> AT Command Parser --> 产生一个重要的Token结构,它包含了命令名称,接收到的参数,以及response的buffer--> 之后AT Command ProcessorProcess 通过Token里面的信息查调用相应的AT 命令处理函数 -->处理完成后产生相应的response给TE。

    具体代码实现

    例子1

    我们在USB MODEM上需要实现一个对PIN码校验的功能,即UIM的PIN功能开启以后,需要在PC端提示用户输入PIN码,但连续输入3次错误后需输入PUK解锁。

    我们不需要修改高通默认的处理流程,只要在command table中添加相应的命令、处理函数:

       { "+CPIN",     READ_ONLY|RESTRICTED,
         SPECIAL_NONE,  0,  NULL,  NULL,
         dsat707_exec_CPIN_cmd,      NULL },
    

    其中+CPIN就是我们定义的一个AT命令,dsat707_exec_CPIN_cmd就是对应的处理函数。

    我们设想的+CPIN功能是:

    A、查询命令: AT+CPIN? 
    
     返回: 
              READY     表示UIM没有
              UIM PIN     表示UIM开启了PIN码功能,用户插入USB MODEM后需要输PIN码
              UIM PUK    表示连续3次输入错误PIN,需要输入PUK解锁
              VERIFIED    表示PIN码输入正确
              UNBLOCKED 表示PUK输入正确,解锁成功
              BLOCKED   如果是返回这个,很不幸的告诉你,你的卡GAME OVER!
    
    B、设置命令: AT+CPIN=1234   用户输入PIN码验证
              AT+CPIN=12345678,1234 用户输入PUK以及新PIN码来解锁
    

    OK,知道了具体的需求,就可以在处理函数dsat707_exec_CPIN_cmd中实现了:

    先判读接收到的+CPIN是什么格式的,是查询命令,设置命令,还是其他。

    我们可以通过Token结构中的tok_ptr->op参数来判断,如果tok_ptr->op == (NA|QU)表示查询命令;tok_ptr->op == (NA|EQ|AR)表示设置命令。

    在查询命令中,我们只要通过获得UIM卡的PIN状态,把相应的状态以字符串的形式告诉PC端就可以了。当然可以在这里调用GSDI 的接口来查询PIN状态,但是在dsatme_init_me中已经向GSDI注册了一个回调函数:gsdi_pin_event_cb_func。 一旦GSDI检测到PIN码状态发生改变时,就会调用这个回调函数。

    所以我们可以定义一个全局变量,在回调函数中设置这个全局变量,之后在dsat707_exec_CPIN_cmd中判断这个全局变量,发送相应字符串。

    在设置命令中,我们要限制用户只能在UIM PIN和UIM PUK 这两种状态才允许执行。在这里遇到了一个很大的难题,就是我们可以容易的通过GSDI的接口来解PIN和解PUK,但是要如何告知其他的service以及UI我们已经解锁了呢?? 可以采用一种“笨”办法,就是不通过直接调用GSDI接口来解PIN,而是模拟出一连串的按键,发送给UI解锁。比如接收到AT+CPIN=1234后,我们可以连续发送1,2,3,4,SEL一共5个KEY EVENT给UI,这样就如同用户在手机上按键解锁了。

    例子2

    来电---ATCoP中对同步事件的处理

    同步事件的处理,我的理解就是ATCoP在其他task注册了一个同步事件的回调函数,一旦同步事件发生时,其他task就会调用这个回调函数来通知ATCoP调用相应的同步事件处理函数。一个典型的例子就是来电过程的处理:

    1、dsatcmif_init_cmif -> cmif_register_cb_func---向CM task注册来电,或者对方应答回调

          /* Register the CM call event callback function */
          cm_status = cm_mm_client_call_reg (
                          dsatcm_client_id,
                          cmif_call_event_cb_func,
                          CM_CLIENT_EVENT_REG,
                          CM_CALL_EVENT_INCOM,
                          CM_CALL_EVENT_CONNECT, 
                          NULL
                          );
    

    2、一旦有来电消息,cmif_call_event_cb_func构造事件的命令放入cmd buffer

           cmd_buf->hdr.cmd_id = DS_AT_CM_CALL_INFO_CMD;
            cmd_buf->cmd.call_event.event_info = *event_ptr;
            cmd_buf->cmd.call_event.event   = event;
          ds_put_cmd(cmd_buf);---->调用(void)rex_set_sigs( &ds_tcb, DS_CMD_Q_SIG );通知ds_task来处理
    

    3、在 ds_task 中调用 dsi_process_cmds()处理命令

    4、 调用dsat_process_async_cmd( cmd_ptr );

    • 查找表async_event_table event_handler_func_ptr = async_event_table[i].event_handler[operating_mode];
    • 调用相应的处理函数result_code = event_handler_func_ptr( dsatcmdp_at_state, cmd_ptr );
    • 这里调用dsatcmif_cm_call_event_handler
    • 调用来电处理函数 ,在这个函数里面会主动发送"Ring"字符串来通知PC端由来电了。
      result = dsatvoice_call_event_incom(&cmd_ptr->cmd.call_event.event_info);
    
    如果说我的文章对你有用,只不过是我站在巨人的肩膀上再继续努力罢了。
    若在页首无特别声明,本篇文章由 Schips 经过整理后发布。
    博客地址:https://www.cnblogs.com/schips/
  • 相关阅读:
    初始化mysql数据库 /usr/bin/mysql_install_db执行时报错
    CentOS7安装mysql兼容性问题
    CentOS7网络连接问题以及重启网络服务失败
    CentOS7安装nginx
    zookeeper启动时报错:Error contacting service. It is probably not running问题
    CentOS查看卸载openjdk
    使用yum命令时提示:Another app is currently holding the yum lock
    修改eclipse中文件打开默认方式
    [程序员代码面试指南]链表问题-单链表的选择排序(选择排序)
    [程序员代码面试指南]链表问题-删除无序链表中重复出现的节点
  • 原文地址:https://www.cnblogs.com/schips/p/at_command_in_qualcomm_2_atcop.html
Copyright © 2011-2022 走看看