At Commands:從白癡到大師的修煉歷程(三)

這篇博客是起步於At Commands學習系列的第三部分,該篇主題主要介紹的是ATCommandProcessor,那麼,什麼是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命令的修改和新增。

簡單的來說,ATCoP接收串口(SerialPort)處傳來的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命令主要涉及到的一些文件:

 

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:命令執行處理(包括返回結果)

 

InitialParsing:函數dsat_process_sio_command去掉命令行中的"AT"前綴,然後把以NULL結尾的命令行傳給函數dsat_process_cmd_line來進行後續的分析和處理。dsatpar_parse_cmd_line函數完成對命令行的解析,檢查每個AT命令的首字符然後根據AT命令的類型調用相應的解析函數。每個AT命令名(包括首符號,如,$QCDMG)以及相關的命令參數都被從命令行中解析出來,然後放到一個tokendatastructure中。命令行中的每個命令都產生一個tokenstructure,放到token排隊上等待後續處理,此時一個命令行解析完成。一般添加或修改AT命令時不改動這部分代碼。

CommandParsing:根據命令的不同首字符,不同的解析函數解析AT命令後,把解析的信息填充到上一步產生的tokendatastructure中,然後返回結果。如果結果是OK(意味著參數、參數個數以及特殊處理碼specialprocessingcode等等都已經存好),此時tokendata structure已放在隊列中等待AT命令處理器(ATcommand processor)後續處理。命令行中的每個命令都在隊列中放一個tokenstructure。例如,extendedor proprietary AT 命令調用的分析函數是parse_extended_cmd。

每個命令產生的tokenstructure被函數dsatcmdp_queue_token放入隊列中。命令解析完成後,調用函數process_at_cmd_line處理隊列中的每個tokenstructure。從隊列中取出並刪除一個命令tokenstructure後,在命令表中搜索該命令。頂層命令表(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 命令。

 

 

·AT命令表分類具體介紹:

1.基本命令表

基本命令的格式為:

 

 
[]

其中

 

 
或者是單個字母(A-Z),或者是“&”字符接單個字母。

是一個十進制數,可以是一位,也可以是多位。最前面的0會被忽略。默認為0。如果一個不帶的基本命令帶瞭,則返回TOO MANYPARAMETERS。

2.寄存器命令表

所有以字母“S”開頭的命令統稱為S寄存器命令,格式如下:

S? S=

S 寄存器命令名由字母“S”接上一個十進制數構成,這個十進制數稱為寄存器序號(parameternumber)。如果寄存器序號不被識別,說明不存在該命令,返回COMMANDNOT SUPPORT。

每個 S寄存器保存一個字符。命令名後面如果接“?”表示是READ命令,返回此S 寄存器當前保存的字符的ASCII 碼值,以3 位十進制數表示,位數不足的前面補0;如果接“=”表示是SET命令,將值對應的字符替換此S 寄存器保存的字符。

3.擴展命令表和廠商提供的命令表

擴展命令均由“+”開頭,廠商定義的命令也是由一個特殊符號開頭,例如“$”,“%”等。本文中所實現的命令均為擴展命令。所有的擴展命令和廠商定義命令又可以分為兩類:Actioncommand和Parameter command。

1)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。

2)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命令屬性列表

4.compound

2)dsati_cmd_struct*是dsati_cmd_struct結構入口指針,對於包含這個命令表入口指定命令。

3)token_struct_type*是一個定義好的tokenstructure解析器指針,這個token結構包含處理該命令所要求的信息。

4)dsm_item_type*是DSMbuffer的指針,存儲命令響應。如果命令響應超出瞭一個DSMbuffer的容量,可以將多個DSMbuffer可以鏈接到一起。函數返回類型

應該是表 .3列出值中的一個。

表4.3函數返回類型表

 

 

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的標準協議文檔進行翻譯理解,並結合網上和個人的一些總結進行整理,希望有幫助。

就這一塊的理解問題應該是挺多的,歡迎大傢提出來一些探討探討!

You May Also Like