高通与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寄存器保存的字符。
扩展命令和厂商命令表
扩展命令均由“+”开头,厂商定义的命令也是由一个特殊符号开头,例如“$”,“%”等。本文中所实现的命令均为扩展命令。
所有的扩展命令和厂商定义命令又可以分为两类:Actioncommand
和Parameter 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);
高通与At指令:AtCop解析的更多相关文章
- 【转】高通平台android 环境配置编译及开发经验总结
原文网址:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...
- 高通 sensor 从native到HAL
app注册传感器监听 Android Sensor Framework 的整体架构如下图所示: 前几篇sensor相关的文章介绍了sensor的hal的知识,以press_sensor实时显示气压坐标 ...
- AngularJS中的指令全面解析(转载)
说到AngularJS,我们首先想到的大概也就是双向数据绑定和指令系统了,这两者也是AngularJS中最为吸引人的地方.双向数据绑定呢,感觉没什么好说的,那么今天我们就来简单的讨论下AngularJ ...
- 高通、猎户机型Android典型bootloader分析
1.bootloader是什么? 简单地说,bootloader 就是在操作系统内核运行之前运行的一段小程序.通过这段小程序,我们可以初始化硬件设备.建立内存空间的映射图,从而将系统的软硬件环境带到一 ...
- 高通平台msm8909 LK 实现LCD 兼容
前段时间小米出现红米note2 换屏门,现在我们公司也要上演了:有两个供应商提供不同IC 的LCD panel. 软件区分的办法是读取LCD IC 的ID 寄存器,下面解析高通平台LK中LCD兼容的过 ...
- Linux加载DTS设备节点的过程(以高通8974平台为例)
DTS是Device Tree Source的缩写,用来描述设备的硬件细节.在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码, ...
- 高通安卓调试LCD几方面总结
来公司上班现在已经整整一个月了,蔽人不才,能力有限,学习进度缓慢,不过也是有一点点的收获与心得,在这里写出来与大家分享,养成良好的记录习惯也免得后忘记. 不啰嗦了,开入正题.来公司一个月左右的时间,主 ...
- 高通/苹果/联发科:手机CPU那些事
如今人们买手机,都比较关心采用了什么CPU,因为CPU直接决定了这台手机的性能,CPU之于手机就好比人的大脑,它是整台手机的控制中枢系统,也是逻辑部分的控制中心.又相当于车的发动机,发动机越强劲,车子 ...
- Android图形合成和显示系统---基于高通MSM8k MDP4平台
介绍了Android SurfaceFlinger层次以下的图形合成和显示系统,主要基于高通MSM8k MDP4x平台. 做为Android Display专题.SurfaceFlinger的详细介绍 ...
- 高通HAL层之Sensor HAL
高通的HAL层其实分为两种,一种是直接从kernel这边报数据上来的,由sensor HAL层来监听,另一种是走ADSP的模式,HAL层是通过qmi的形式进行监听的: 走ADSP架构的可以看下面的博客 ...
随机推荐
- K8s包管理工具Helm v3(19)
一.Helm概述 官网:https://v3.helm.sh/zh/docs/ https://helm.sh/ helm 官方的 chart 站点: https://hub.kubeapps.com ...
- ESP32 + IDF + LED
一.开发板 ESP32-S3-DevKitC-1 管脚布局 由于这个程序控制比较简单,就不赘述了,直接看程序. 二.程序 #include "freertos/FreeRTOS.h" ...
- ITIL4服务价值系统(SVS)与莫比乌斯环:无限服务优化的拓扑之旅
莫比乌斯环:单一而无限的象征 莫比乌斯环,这个拓扑学上的奇观,以其独特的一体两面特性,完美地映射了ITIL4服务价值系统的精髓.它象征着无限.统一和连续性,提示我们看待事物时应超越传统二元对立的视角, ...
- flex布局方案
参考:https://blog.csdn.net/weixin_39717076/article/details/82586915
- Nokia 5GC 产品概览
目录 文章目录 目录 Nokia SR OS Nokia NSP NFM-P Nokia 7750 SR-MG 5G User Plane Forwarding Mobile Gateway Non- ...
- 初识上位机(上):搭建PLC模拟仿真环境
大家好,我是Edison. 作为一个工业自动化领域的程序员,不懂点PLC和上位机,貌似有点说不过去.这里我用两篇小文带你快速进入上位机开发领域.后续,我会考虑再出一个系列文章一起玩工控上位机. 什么是 ...
- GROUP BY clause and contains nonaggregated 报错处理
1055 - Expression #16 of SELECT list is not in GROUP BY clause and contains nonaggregated column 报错处 ...
- PHP 有哪些常用的魔术变量 ?
引言 PHP 向它运行的任何脚本提供了大量的预定义常量. 魔术变量 __LINE__ 文件中的当前行号. __FILE__ 文件的完整路径和文件名. 如果用在被包含文件中,则返回被包含的文件名. __ ...
- Android 13 - Media框架(11)- MediaCodec(一)
关注公众号免费阅读全文,进入音视频开发技术分享群! MediaCodec 是 Android 平台上音视频编解码的标准接口,无论是使用软解还是硬解都要通过调用 MediaCodec来完成,是学习 An ...
- Android 12(S) MultiMedia(十二)MediaCodecList & IOmxStore
这节来了解下MediaCodecList相关代码路径: frameworks/av/media/libstagefright/MediaCodecList.cpp frameworks/av/medi ...