AT指令框架(C語言)


本文檔記錄設計的AT指令框架,使用時只需要簡單增加修改指令和執行指令函數

一、指令結構

typedef enum{
    AT_CMD_TEST = 0,     /* 測試指令 */
    AT_CMD_NAME,         /* 設置名稱 */
    AT_CMD_DISA,         /* 斷開當前連接 */
    AT_CMD_TX_POWER,     /* 設置發送功率 */
    AT_CMD_ADV_INTERVAL, /* 設置廣播間隔 */
    AT_CMD_CON_INTERVAL, /* 設置連接間隔 */
    AT_CMD_ADV_ONOFF,    /* 設置打開、關閉廣播 */
    AT_GET_VER,          /* 獲取版本號 */
    AT_GET_CON_STATE,    /* 獲取連接狀態 */
    AT_CMD_UART_CFG,     /* 配置UART參數 */
    
    AT_END
}AT_Cmd;

typedef unsigned char (*pFunc)(unsigned char *ptr, unsigned char len);

typedef struct {
    AT_Cmd cmd;          /* 指令序號 */
    unsigned char *str;  /* 指令內容 */
    pFunc  cb;           /* 指令執行 */
}AT_cmd_func;

/* AT指令表 */
const AT_cmd_func at_cmd_func[] = {
    {AT_CMD_TEST,         "AT",                at_cmd_test},
    {AT_CMD_NAME,         "AT+NAME=",          at_cmd_name},
    {AT_CMD_DISA,         "AT+DISC",           NULL},
    {AT_CMD_TX_POWER,     "AT+TX=",            NULL},
    {AT_CMD_ADV_INTERVAL, "AT+ADV_INTERVAL=",  NULL},
    {AT_CMD_CON_INTERVAL, "AT+CON_INTERVAL=",  NULL},
    {AT_CMD_ADV_ONOFF,    "AT_ADV=",           NULL},
    {AT_GET_VER,          "AT+VERSION=",       NULL},
    {AT_GET_CON_STATE,    "AT+STATE",          NULL},
    {AT_CMD_UART_CFG,     "AT+UART_CFG=",      NULL},
    {AT_END,              NULL,                NULL}
};

指令執行函數

/* 指令執行函數 */
unsigned char at_cmd_test(unsigned char *p, unsigned char len){
    
    AT_DEBUG_INFO("AT+OK\r\n");
    return 0;
}

unsigned char at_cmd_name(unsigned char *p, unsigned char len){
    
    if(*p == '?'){
        
        AT_DEBUG_INFO("AT+OK BLE-NAME\r\n");
    }else{
    
        AT_DEBUG_INFO("AT+OK\r\n");
    }
    return 0;
}

 

二、指令解析 

/* 查找指令表中對應的指令 */
unsigned char AT_cmd_search(unsigned char *p, unsigned char len){
    
    unsigned char ret = 0;
    unsigned char *pstr;
    unsigned char i, n;
    
    for(i=1; at_cmd_func[i].cmd != AT_END; i++){    
        
        n = mstrlen(at_cmd_func[i].str);
        if(!mstrncmp(p, at_cmd_func[i].str, n)){
            ret = i;
            break;
        }        
    }
    
    return ret;
}

/* AT指令解析 */
unsigned char at_cmd_parse(unsigned char *p, unsigned char len){
    
    unsigned char ret = AT_SUCCESS;
    unsigned char index = 0;
    
    if(len < 4) return AT_ERR; /* 不符合指令最小長度 */
    
    if((p[0] == 'A') && (p[1] == 'T') && (p[len-2] == 0x0D) && (p[len-1] == 0x0A)){
        if(len == 4){  /* 測試指令 */
        
            if(at_cmd_func[AT_CMD_TEST].cb != NULL)  
                at_cmd_func[AT_CMD_TEST].cb(NULL, 0);  /* 執行測試指令 */
        }else if(p[2] == '+'){ /* 執行指令解析 */
            
            index = AT_cmd_search(p, len); /* 查找匹配的執行指令,0-已匹配,!0-未匹配 */
            if(index){
                if(at_cmd_func[index].cb != NULL){  /* 判斷指令對應執行函數是否存在 */
                    unsigned char n;
                    n = mstrlen(at_cmd_func[index].str);
                    ret = at_cmd_func[index].cb(p+n, len-n); /* 執行對應的指令函數, p+n:將指令參數傳輸執行函數,len-n-2:指令參數有效長度 */
                }else
                    ret = AT_ERR_FUN_UNUSED; /* 沒有可執行函數 */
            }else{
                ret = AT_ERR_UNINVAIL; /* 未找到匹配的指令 */
            }
        }
    }else{/* 格式不匹配 */
        
        return AT_ERR;
    }
    
    return ret;
}

 

三、指令測試

/* 測試 */
int main(void){

    unsigned char ret;
    unsigned char i, n, m;
    #define CMD_NUM_MAX (5)    
    char *test_cmd[CMD_NUM_MAX]={
        "AT\r\n",
        "AT+NAME=BLE-TEST\r\n",
        "AT+NAME=?\r\n",
        "AT+DISC\r\n",
        "AT+NBME=?\r\n",
    };
    
    for(i=0; i<CMD_NUM_MAX; i++){
        m = mstrlen(test_cmd[i]);
        ret = at_cmd_parse(test_cmd[i], m);
        if(ret)
            AT_DEBUG_INFO("AT ERR! = %d\r\n", ret);
    }
    
    return 0;
}

結果如下

 

指令解析后返回數據定義

#define AT_SUCCESS         (0) /* 指令正常 */
#define AT_ERR             (1) /* 指令異常 */
#define AT_ERR_UNINVAIL    (2) /* 沒有對應指令 */
#define AT_ERR_FUN_UNUSED  (3) /* 沒有可執行函數 */

/* 返回值參數內容如上, p-指向解析的指令,len-解析指令長度 */
unsigned char at_cmd_parse(unsigned char *p, unsigned char len);

 

 

注意:上面代碼中使用了2個類C庫函數 mstrlen, mstrncmp (與C庫中strlen, strncmp功能一致),主要是為了移植是脫離平台,編譯時使用代碼占用空間盡量少

unsigned int mstrlen(const char *s){
    
    const char *ss = s;
    
    while (*ss)
        ss++;
    
    return ss - s;
}

int mstrncmp(const char *s1, const char *s2, int n){
    
    const unsigned char *c1 = (const unsigned char *)s1;
    const unsigned char *c2 = (const unsigned char *)s2;
    unsigned char ch;
    int d = 0;

    while (n--) {
        d = (int)(ch = *c1++) - (int)*c2++;
        if (d || !ch)
            break;
    }

    return d;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM