简言:
-
使用NB或BLE或者AT指令交互的模组时,需要一个方便灵活的AT指令框架
-
便于快速的实现功能,后期维护扩展功能
-
思路
-
使用状态机原理和二维数组存储指令数据
-
按照指令集顺序执行命令
-
分享的友情链接
https://blog.csdn.net/weixin_42192405/article/details/115765164
(另有一种AT Command 指令处理框架,本文框架与AT Command各有优劣)
AT Command使用教程全网有很多了,后续会更新AT command示例。
代码示例:
- AT状态机处理
#include "app_iot_at.h"
extern rt_mailbox_t iot_mb_at;
extern rt_mailbox_t iot_mb_ctl;
extern rt_uint8_t iot_read_buff[IOT_READ_BUFF_SIZE];
extern rt_uint8_t iot_read_len;
extern rt_uint8_t iot_send_buff[IOT_SEND_BUFF_SIZE];
extern iot_device_message_t i_dev_mess;
extern rt_timer_t iot_timer_2;
//临时测试数据
//const uint8_t temp_70[] = {"AT+MCWSEND=41,00FF2401010023435965676000121C20010B00FF0000000000C800640000330100025EBAED06F1C857\r\n"};
/*
* 清单号
*/
rt_uint8_t i_list_num =0;
/*
* 重试
*/
rt_uint8_t i_list_retry =0;
/*
* 清单选择
*/
iot_cmd_list_t *i_list_select = NULL;
/*
* 当前变量
*/
iot_dev_state_t i_cur = {0,0,0,0,0,0};
/*
* 特定清单
*/
/*
* 连接中国电信初始化
*/
iot_cmd_list_t iot_list_poweron_lwm2m[]=
{I_AT, I_AT, I_QSCLK, I_CGMI, I_CGSN, I_ATE, I_QBAND, I_CGPADDR, I_NNMI, I_NCFG, I_CSCON1, I_CSCON, I_CEREG, I_NCDPOPEN, I_CSQ, I_NMSTATUS, I_FINISH};
/*
*上传数据
*/
iot_cmd_list_t iot_list_updata_lwm2m[]=
{ I_CSQ, I_NMGS, I_FINISH};
/*
* 信号强度
*/
iot_cmd_list_t iot_list_csq[]=
{ I_CSQ, I_CCLK, I_FINISH};
/*
* 连接客户后台初始化
*/
iot_cmd_list_t iot_list_poweron_tcpip[]=
{I_AT, I_QSCLK, I_QICLOSE, I_CGMI, I_CGSN, I_ATE, I_QBAND, I_CSCON1, I_CSCON, I_CEREG, I_CGPADDR,
I_CSQ, I_CCLK, I_QENG, I_FINISH};
/*
* 上传数据
*/
iot_cmd_list_t iot_list_updata_tcpip[]=
{ I_QIOPEN, I_QICFG, I_QISEND, I_FINISH};
/*
* 列表
*/
iot_dev_state_t iot_cmds[] =
{
//指令=指令+应答+等待时间+重试次数+处理
{I_AT_NULL, "NULL", "NULL", 0, 0, NULL},
{I_AT, "AT\r\n", "OK", 1000, 3, i_default_deal},
{I_QRST, "AT+QRST=1\r\n", "+IP", 15000, 3, i_default_deal},
{I_QSCLK, "AT+QSCLK=0\r\n", "OK", 1000, 3, i_default_deal},
{I_CGMI, "AT+CGMI\r\n", "OK", 1000, 3, i_default_deal},
{I_CGSN, "AT+CGSN=1\r\n", "OK", 1000, 3, i_default_deal},
{I_ATE, "ATE0\r\n", "OK", 1000, 3, i_default_deal},
{I_QBAND, "AT+QBAND=0\r\n", "OK", 1000, 3, i_default_deal},
{I_CGPADDR, "AT+CGPADDR?\r\n", "OK", 1000, 3, i_default_deal},
{I_NNMI, "AT+NNMI=1\r\n", "OK", 1000, 3, i_default_deal},
{I_NCFG, "AT+NCFG=0,300\r\n", "OK", 1000, 3, i_default_deal},
{I_CSCON1, "AT+CSCON=1\r\n", "OK", 1000, 3, i_default_deal},
{I_CSCON, "AT+CSCON?\r\n", "OK", 1000, 3, i_default_deal},
{I_CEREG, "AT+CEREG?\r\n", "OK", 1000, 3, i_default_deal},
{I_NCDPOPEN, "AT+NCDPOPEN=\"221.229.214.202\",5683\r\n", "+QLWEVTIND: 3", 5000, 3, i_default_deal},
{I_CSQ, "AT+CSQ\r\n", "OK", 1000, 3, i_csq_deal},
{I_NMSTATUS, "AT+NMSTATUS?\r\n", "REGISTERED_AND_OBSERVED", 1000, 3, i_default_deal},
{I_NMGS, iot_send_buff, "OK", 5000, 3, i_default_deal},
{I_QIOPEN, "AT+QIOPEN=0,0,\"TCP\",\"47.94.169.135\",7191\r\n", "+QIOPEN: 0,0", 5000, 3, i_default_deal},
//{I_QIOPEN, "AT+QIOPEN=0,0,\"TCP\",\"36.137.226.30\",43588\r\n", "+QIOPEN: 0,0", 5000, 3, i_default_deal},
{I_QICFG, "AT+QICFG=\"dataformat\",1,1\r\n", "OK", 5000, 3, i_default_deal},
{I_QISEND, iot_send_buff, "OK", 5000, 3, i_default_deal},
{I_QICLOSE, "AT+QICLOSE=0\r\n", "CLOSE OK", 30000, 3, i_default_deal},
{I_CCLK, "AT+CCLK?\r\n", "+CCLK", 3000, 3, i_rtc_deal},
{I_QENG, "AT+QENG=0\r\n", "OK", 3000, 3, i_qeng_deal},
};
/*
* 重置
*/
void i_cur_reset(void)
{
i_cur.i_cur_cmd = I_AT_NULL;
i_cur.i_send = NULL;
i_cur.i_ack = NULL;
i_cur.i_wait_time = 0;
i_cur.i_try_cnt = 0;
i_cur.i_recv_deal = NULL;
i_list_num =0;
i_list_retry =0;
i_list_select = NULL;
}
/*
* 默认处理
*/
uint8_t i_default_deal(char* data, uint8_t len)
{
return 1;
}
/*
* 信号强度
*/
uint8_t i_csq_deal(char* data, uint8_t len)
{
uint8_t *data_p = data;
uint8_t csq_value = 0;
if(strstr(data_p, "+CSQ") != NULL)
{
LOG_OUT("%c\r\n", *(data_p+8));
LOG_OUT("%c\r\n", *(data_p+9));
csq_value = (*(data_p+8) - '0')*10 + (*(data_p+9) - '0');
LOG_OUT("csq_value =%d\r\n", csq_value);
i_dev_mess.csq = csq_value;
}
return 1;
}
/*
* RTC处理
*/
uint8_t i_rtc_deal(char* data, uint8_t len)
{
uint8_t *data_p = data;
uint8_t temp =0;
uint8_t year =0;
uint8_t Month =0;
uint8_t Date =0;
uint8_t Hours =0;
uint8_t Minutes =0;
uint8_t Seconds =0;
uint32_t timestamp = 0;
if(strstr(data_p, "+CCLK") != NULL)
{
year = *(data_p+12) - '0';
year = year*10 + (*(data_p+13) - '0');
LOG_OUT("year=%d\r\n", year);
year = dec_transition_hex_show(year);
Month = *(data_p+15) - '0';
Month = Month*10 + (*(data_p+16) - '0');
LOG_OUT("Month=%d\r\n", Month);
Month = dec_transition_hex_show(Month);
Date = *(data_p+18) - '0';
Date = Date*10 + (*(data_p+19) - '0');
LOG_OUT("Date=%d\r\n", Date);
Date = dec_transition_hex_show(Date);
Hours = *(data_p+21) - '0';
Hours = Hours*10 + (*(data_p+22) - '0');
LOG_OUT("Hours=%d\r\n", Hours);
Hours = dec_transition_hex_show(Hours);
Minutes = *(data_p+24) - '0';
Minutes = Minutes*10 + (*(data_p+25) - '0');
LOG_OUT("Minutes=%d\r\n", Minutes);
Minutes = dec_transition_hex_show(Minutes);
Seconds = *(data_p+27) - '0';
Seconds = Seconds*10 + (*(data_p+28) - '0');
LOG_OUT("Seconds=%d\r\n", Seconds);
Seconds = dec_transition_hex_show(Seconds);
rtc_receive_calibration(Hours, Minutes, Seconds, year, Month, Date);
app_rtc_data_read(×tamp);
i_dev_mess.collect_time[0] = (timestamp >>24) & 0xFF;
i_dev_mess.collect_time[1] = (timestamp >>16) & 0xFF;
i_dev_mess.collect_time[2] = (timestamp >>8) & 0xFF;
i_dev_mess.collect_time[3] = (timestamp ) & 0xFF;
}
return 1;
}
//+QENG: 0,3688,11,264,"09018613",-84,-8,-77,6,8,"4B03",0,21,3
//-6, -66,
//6, 66,
/*
* 参考信号强度等
*/
uint8_t i_qeng_deal(char* data, uint8_t len)
{
uint8_t *data_p = data;
uint8_t cnt =0;
uint16_t pci = 0;
uint16_t rsrp = 0;
uint16_t snr = 0;
for(uint8_t t=0; t<60; t++)
{
if( *(data_p+t) == ',')
{
cnt++;
if(cnt == 3)
{
if(*(data_p+t+4) == ',')
{
pci = (*(data_p+t+1)-'0')*100 + (*(data_p+t+2)-'0')*10 + (*(data_p+t+3)-'0');
}
else if(*(data_p+t+3) == ',')
{
pci = (*(data_p+t+1)-'0')*10 + (*(data_p+t+2)-'0');
}
else if(*(data_p+t+2) == ',')
{
pci = (*(data_p+t+1)-'0');
}
LOG_OUT("pci=%d\r\n", pci);
i_dev_mess.pci[0] = pci >>8;
i_dev_mess.pci[1] = pci &0xFF;
}
else if(cnt == 5)
{
if(*(data_p+t+1) == '-')
{
if(*(data_p+t+5) == ',')
{
rsrp = (*(data_p+t+2)-'0')*100 + (*(data_p+t+3)-'0')*10 + (*(data_p+t+4)-'0');
}
else if(*(data_p+t+4) == ',')
{
rsrp = (*(data_p+t+2)-'0')*10 + (*(data_p+t+3)-'0');
}
else if(*(data_p+t+3) == ',')
{
rsrp = (*(data_p+t+2)-'0');
}
LOG_OUT("rsrp=%d\r\n", rsrp);
if(rsrp >= 141)
{
rsrp = 0;
}
else
{
rsrp = 141 - rsrp;
}
LOG_OUT("rsrp=%d\r\n", rsrp);
i_dev_mess.rsrp[0] = rsrp >>8;
i_dev_mess.rsrp[1] = rsrp &0XFF;
}
}
else if(cnt == 8)
{
if(*(data_p+t+1) == '-')
{
if(*(data_p+t+3) == ',')
{
snr = (*(data_p+t+2)-'0');
}
else if(*(data_p+t+4) == ',')
{
snr = (*(data_p+t+2)-'0')*10 + (*(data_p+t+3)-'0');
}
LOG_OUT("snr=%d\r\n", snr);
snr |= 0x8000;
LOG_OUT("snr=%x\r\n", snr);
}
else
{
if(*(data_p+t+2) == ',')
{
snr =(*(data_p+t+1)-'0');
}
else if(*(data_p+t+3) == ',')
{
snr = (*(data_p+t+1)-'0')*10 + (*(data_p+t+2)-'0');
}
LOG_OUT("snr=%d\r\n", snr);
}
i_dev_mess.snr[0] = snr >>8;
i_dev_mess.snr[1] = snr &0XFF;
}
}
}
return 1;
}
/*
* 超时重发
*/
void iot_timeout_task_2(void *parameter)
{
LOG_OUT("iot_timeout_task_2\r\n");
rt_mb_send_wait(iot_mb_at, I_AT_TIMEOUT, 1000);
}
/*
* AT线程任务
* 操作系统使用线程邮箱等待事件触发
* 裸机使用状态标志位等待事件触发
* 避免延时,加快速度
*/
void iot_at_thread_task(void *parameter)
{
rt_thread_mdelay(100);
LOG_OUT("iot_at_thread_task OK\r\n");
rt_uint32_t at_cmd = 0;
rt_uint32_t at_ret = 0;
while (1)
{
at_ret = rt_mb_recv(iot_mb_at, &at_cmd, RT_WAITING_FOREVER);
if(at_ret == RT_EOK)
{
LOG_OUT("at_cmd=%d\r\n", at_cmd);
switch(at_cmd)
{
//空闲
case I_AT_IDLE:
{
LOG_OUT("I_AT_IDLE\r\n");
}
break;
//发送
case I_AT_SEND:
{
LOG_OUT("I_AT_SEND=");
i_cur = iot_cmds[i_list_select[i_list_num]];
i_list_retry = 0;
if( i_list_select[i_list_num] != I_FINISH)
{
rt_device_write(app_iot_dev, RT_NULL, i_cur.i_send, strlen(i_cur.i_send));
rt_timer_control(iot_timer_2, RT_TIMER_CTRL_SET_TIME, &i_cur.i_wait_time);
rt_timer_start(iot_timer_2);
LOG_OUT("%s\r\n", i_cur.i_send);
}
else
{
LOG_OUT("I_FINISH\r\n");
rt_mb_send_wait(iot_mb_at, I_AT_FINISH, 1000);
}
}
break;
//等待
case I_AT_WAIT:
{
LOG_OUT("I_AT_WAIT:");
memset(iot_read_buff, 0x00, sizeof(iot_read_buff));
while( (iot_read_len = rt_device_read(app_iot_dev, RT_NULL, iot_read_buff, RT_NULL)) > 0)
{
LOG_OUT("iot_read_len=%d\r\n", iot_read_len);
LOG_OUT("I_AT_REC=");
for(uint8_t t=0; t<iot_read_len; t++)
{
LOG_OUT("%c",iot_read_buff[t]);
}
LOG_OUT("\r\n");
if(i_cur.i_send != NULL)
{
if(strstr(iot_read_buff, i_cur.i_ack) != NULL)
{
if(i_cur.i_recv_deal(iot_read_buff, iot_read_len) == 1)
{
LOG_OUT("iot ack ok\r\n");
rt_timer_stop(iot_timer_2);
i_list_num++;
rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
}
}
else if(i_cur.i_ack == NULL)
{
LOG_OUT("null ack ok\r\n");
rt_timer_stop(iot_timer_2);
i_list_num++;
rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
}
}
else
{
LOG_OUT("URC:\r\n");
if(iot_ctl.i_module == I_LWM2M)
{
if(strstr(iot_read_buff, "+NNMI" ) != NULL)
{
i_urc_deal(iot_read_buff, iot_read_len);
}
}
else
{
if(strstr(iot_read_buff, "+QIURC: \"recv\"" ) != NULL)
{
i_urc_deal(iot_read_buff, iot_read_len);
}
else if( strstr(iot_read_buff, "+QIURC:\"closed\"" ) != NULL )
{
LOG_OUT("+QIURC: closed deal\r\n");
iot_ctl.i_send_cmd = I_CMD_UPDATA;
rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
}
}
}
}
}
break;
//超时
case I_AT_TIMEOUT:
{
LOG_OUT("I_AT_TIMEOUT:");
LOG_OUT("retry:%d < %d\r\n", i_list_retry, i_cur.i_try_cnt);
if(i_list_retry++ < i_cur.i_try_cnt)
{
rt_device_write(app_iot_dev, RT_NULL, i_cur.i_send, strlen(i_cur.i_send));
rt_timer_control(iot_timer_2, RT_TIMER_CTRL_SET_TIME, &i_cur.i_wait_time);
rt_timer_start(iot_timer_2);
LOG_OUT("%s\r\n", i_cur.i_send);
}
else
{
rt_mb_send_wait(iot_mb_at, I_AT_FAIL, 1000);
}
}
break;
//完成
case I_AT_FINISH:
{
LOG_OUT("I_AT_FINISH\r\n");
i_cur_reset();
rt_mb_send_wait(iot_mb_ctl, I_EVT_RET_SUCC, 1000);
}
break;
//失败
case I_AT_FAIL:
{
LOG_OUT("I_AT_FAIL\r\n");
i_cur_reset();
rt_mb_send_wait(iot_mb_ctl, I_EVT_RET_FAIL, 1000);
}
break;
}
}
}
}
- 定义的状态变量
#ifndef __APP_IOT_AT_H
#define __APP_IOT_AT_H
#include "app_user.h"
//AT任务事件
typedef enum
{
I_AT_IDLE = 1 << 0,
I_AT_SEND = 1 << 1,
I_AT_WAIT = 1 << 2,
I_AT_TIMEOUT = 1 << 3,
I_AT_FINISH = 1 << 4,
I_AT_FAIL = 1 << 5,
}IOT_AT_EVENT_T;
/*
* 针对某NB模组的AT指令
*/
typedef enum
{
I_AT_NULL = 0,
I_AT,
I_QRST,
I_QSCLK,
I_CGMI,
I_CGSN,
I_ATE,
I_QBAND,
I_CGPADDR,
I_NNMI,
I_NCFG,
I_CSCON1,
I_CSCON,
I_CEREG,
I_NCDPOPEN,
I_CSQ,
I_NMSTATUS,
I_NMGS,
I_QIOPEN,
I_QICFG,
I_QISEND,
I_QICLOSE,
I_CCLK,
I_QENG,
I_FINISH
}iot_cmd_list_t;
/*
* 控制
*/
typedef struct
{
iot_cmd_list_t i_cur_cmd;//当前指令
uint8_t* i_send;//发送指令
uint8_t* i_ack;//应答数据
int i_wait_time;//等待时间
int i_try_cnt;//重试次数
uint8_t (*i_recv_deal)(uint8_t* data, uint8_t len);//处理数据
}iot_dev_state_t;
uint8_t i_default_deal(char* data, uint8_t len);
uint8_t i_csq_deal(char* data, uint8_t len);
uint8_t i_rtc_deal(char* data, uint8_t len);
uint8_t i_qeng_deal(char* data, uint8_t len);
#endif
- 控制AT执行流程的事件
//空闲
case I_EVT_IDLE:
{
LOG_OUT("I_EVT_IDLE\r\n");
}
break;
//上电
case I_EVT_POWERON:
{
LOG_OUT("I_EVT_POWERON\r\n");
memset(iot_read_buff, 0x00, sizeof(iot_read_buff));
while( (iot_read_len = rt_device_read(app_iot_dev, RT_NULL, iot_read_buff, RT_NULL)) > 0)
{
LOG_OUT("iot_read_len=%d\r\n", iot_read_len);
for(uint8_t t=0; t<iot_read_len; t++)
{
LOG_OUT("%c",iot_read_buff[t]);
}
LOG_OUT("\r\n");
//IP入网
if((strstr(iot_read_buff, "+IP" ) != NULL))
{
LOG_OUT("readly iot_list_poweron\r\n");
iot_ctl.i_run_ste = I_WORK;
i_cur_reset();
if(iot_ctl.i_module == I_LWM2M)
{
i_list_select = iot_list_poweron_lwm2m;
}
else
{
i_list_select = iot_list_poweron_tcpip;
}
iot_ctl.i_send_cmd = I_CMD_POWER;
rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
}
}
}
break;
//返回成功
case I_EVT_RET_SUCC:
{
LOG_OUT("I_EVT_RET_SUCC\r\n");
LOG_OUT("send_cmd=%d\r\n", iot_ctl.i_send_cmd);
switch(iot_ctl.i_send_cmd)
{
//上电事件
case I_CMD_POWER:
{
LOG_OUT("I_CMD_POWER\r\n");
//上报标志
if(iot_ctl.i_up_flag == true)
{
iot_ctl.i_up_flag = false;
//上传数据
app_iot_up_data_update();
LOG_OUT("reday updata\r\n");
i_cur_reset();
if(iot_ctl.i_module == I_LWM2M)
{
i_list_select = iot_list_updata_lwm2m;
}
else
{
i_list_select = iot_list_updata_tcpip;
}
iot_ctl.i_send_cmd = I_CMD_UPDATA;
rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
}
else
{
LOG_OUT("bsp_iot_close\r\n");
bsp_iot_close();
}
}
break;
//结束事件
case I_CMD_UPDATA:
{
LOG_OUT("send data success\r\n");
LOG_OUT("bsp_iot_close\r\n");
bsp_iot_close();
}
break;
}
}
break;
//失败关闭
case I_EVT_RET_FAIL:
{
LOG_OUT("I_EVT_RET_FAIL\r\n");
LOG_OUT("send_cmd=%d\r\n", iot_ctl.i_send_cmd);
LOG_OUT("bsp_iot_close\r\n");
bsp_iot_close();
}
break;
- 控制流程变量
#ifndef __APP_IOT_CTL_H
#define __APP_IOT_CTL_H
#include "app_user.h"
typedef enum
{
I_POWERON = 0,
I_WORK,
I_SLEEP,
I_ALARM
}IOT_RUN_STATE_T;
typedef enum
{
I_CMD_POWER = 0,
I_CMD_UPDATA ,
}IOT_SEND_CMD_T;
typedef enum
{
I_LWM2M = 0,
I_TCP_IP,
}I_MODULE_TYPE_T;
typedef struct
{
IOT_RUN_STATE_T i_run_ste;
IOT_SEND_CMD_T i_send_cmd;
uint8_t i_up_flag;
uint8_t i_module;
}iot_control_t;
//EVT任务事件
typedef enum
{
I_EVT_IDLE = 1 << 0,//空闲
I_EVT_POWERON = 1 << 1,//电源上电事件
I_EVT_RET_SUCC = 1 << 2,//返回成功事件
I_EVT_RET_FAIL = 1 << 3,//返回失败事件
I_EVT_UPDATA_SUCC = 1 << 4,//上传成功事件
I_EVT_UPDATA_FAIL = 1 << 5,//上传失败事件
I_EVT_RTC_UPDATA = 1 << 6,//RTC触发事件
I_EVT_SENSOR_REC = 1 << 7,//传感器反馈结果事件
I_EVT_SENSOR_SEND = 1 << 8,//传感器控制参数事件
}IOT_EVT_EVENT_T;
extern iot_control_t iot_ctl;
void iot_parameter_init(void);
#endif