本文檔記錄設計的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; }