AT解析层的思路分析及代码实现
文章目录
- 1 AT解析层的思路分析
- 1.1 AT解析层的接口API分析
- 1.2 AT解析层代码流程
- 2 AT解析层代码实现
- 2.1 代码实现
1 AT解析层的思路分析
1.1 AT解析层的接口API分析
如下:
对应到头文件内容如下:
#define AT_DELIMITER "\r\n"
#define AT_END_CHAR '\n'typedef void (*at_recv_cb)(char *pdata,uint16_t data_len,void *arg);bool at_parse_init(void);
bool at_parse_deinit(void);
bool at_send_wait_reply(const char *cmd,bool delimiter,char *right_prefix,char *fail_prefix,char *reply_buf, uint16_t *reply_size,uint32_t timeout);bool at_send_no_reply(const char *data, uint16_t datalen, bool delimiter,uint32_t timeout);bool at_register_callback(const char *prefix, at_recv_cb cb, void *arg);
1.2 AT解析层代码流程
2 AT解析层代码实现
2.1 代码实现
at_parse.c:
#include <stdbool.h>
#include <string.h>
#include "at_parse.h"
#include "at_uart_hal.h"
#include "app_debug.h"#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"#define MAX_OBJ_COUNT 10
#define MAX_RECV_BUF_LEN 200typedef struct
{char *prefix;at_recv_cb callback;void *arg;
}at_obj_t;typedef struct
{char *cmd;char *right_prefix;char *fail_prefix;char *reply_buf;uint16_t *reply_len;bool result;
}at_send_process_t;typedef struct
{TaskHandle_t task_recv;SemaphoreHandle_t sem_send;SemaphoreHandle_t mutex_send;at_send_process_t send_procees;at_obj_t obj[MAX_OBJ_COUNT];char recv_buf[MAX_RECV_BUF_LEN];uint16_t recv_counter;
}at_parse_t;static bool is_inited=false;
static at_parse_t at;static bool at_parse_match_obj(char *pdata,uint16_t datalen)
{for(uint8_t i=0;i<MAX_OBJ_COUNT;i++){if(strstr(pdata,at.obj[i].prefix)!=NULL){at.obj[i].callback(pdata,datalen,at.obj[i].arg);return true;}}return false;
}static void at_parse_recv_task(void *param)
{char ch;memset(at.recv_buf,0,MAX_RECV_BUF_LEN);at.recv_counter=0;while(1){if(at_uart_receive(&ch,1,1000)==0){continue;}at.recv_buf[at.recv_counter++]=ch;if(ch!=AT_END_CHAR){if(at.recv_counter>=MAX_RECV_BUF_LEN){memset(at.recv_buf,0,MAX_RECV_BUF_LEN);at.recv_counter=0; DEBUG("recv buf is full"); }continue;}//received at end chardo{if(at.recv_counter<=2)break;at.recv_counter-=2;at.recv_buf[at.recv_counter]='\0';DEBUG("at recv:%d,%s",at.recv_counter,at.recv_buf);//match obj prefixif(at_parse_match_obj(at.recv_buf,at.recv_counter))break;//match fail prefixif(at.send_procees.fail_prefix!=NULL) // 必须上层有发才处理{if(strstr(at.recv_buf,at.send_procees.fail_prefix)!=NULL){at.send_procees.result=false;xSemaphoreGive(at.sem_send);break;}}//match right prefixif(at.send_procees.right_prefix!=NULL) // 必须上层有发才处理{if(strstr(at.recv_buf,at.send_procees.right_prefix)!=NULL){//copy recv data to reply bufferif((at.send_procees.reply_buf!=NULL)&&(at.send_procees.reply_len!=NULL)){if(*at.send_procees.reply_len>at.recv_counter){memcpy(at.send_procees.reply_buf,at.recv_buf,at.recv_counter);*at.send_procees.reply_len=at.recv_counter;} else{DEBUG("reply buffer is too small");}}at.send_procees.result=true;xSemaphoreGive(at.sem_send);break;}}} while (0);memset(at.recv_buf,0,MAX_RECV_BUF_LEN);at.recv_counter=0; }
}bool at_parse_init(void)
{if(is_inited)return true;DEBUG("at parse init");memset(&at,0,sizeof(at));do{if(at_uart_init()==false)break;//freertos resource initif(xTaskCreate(at_parse_recv_task,"at_parse_recv",128,NULL,3,&at.task_recv)!=pdTRUE)break;at.sem_send=xSemaphoreCreateBinary();if(at.sem_send==NULL)break;at.mutex_send=xSemaphoreCreateMutex(); if(at.mutex_send==NULL)break;is_inited=true;return true;} while (0);//cleanat_parse_deinit();return false;}
bool at_parse_deinit(void)
{is_inited=false;DEBUG("at parse deinit");at_uart_deinit();if(at.task_recv!=NULL){vTaskDelete(at.task_recv);}if(at.sem_send!=NULL){vSemaphoreDelete(at.sem_send);}if(at.mutex_send!=NULL){vSemaphoreDelete(at.mutex_send);}vTaskDelay(100);memset(&at,0,sizeof(at));return true;
}
bool at_send_wait_reply(const char *cmd,bool delimiter,char *right_prefix,char *fail_prefix,char *reply_buf, uint16_t *reply_size,uint32_t timeout)
{bool result=false;if(is_inited==false)return false;if(cmd==NULL)return false;if(right_prefix==NULL)return false;//lockif(xSemaphoreTake(at.mutex_send,timeout)!=pdTRUE)return false;//save parametersmemset(&at.send_procees,0,sizeof(at.send_procees));at.send_procees.cmd=(char *)cmd;at.send_procees.right_prefix=right_prefix;at.send_procees.fail_prefix=fail_prefix;at.send_procees.reply_buf=reply_buf;at.send_procees.reply_len=reply_size;do{//send dataDEBUG("at cmd:%s",cmd);if(at_uart_send(cmd,strlen(cmd),timeout)!=strlen(cmd))break;if(delimiter){if(at_uart_send(AT_DELIMITER,strlen(AT_DELIMITER),timeout)!=strlen(AT_DELIMITER))break; }//wait semxSemaphoreTake(at.sem_send,0);xSemaphoreTake(at.sem_send,timeout);result=at.send_procees.result;} while (0);//unlockmemset(&at.send_procees,0,sizeof(at.send_procees)); // 这里必须记得清空,否则很容易出bugxSemaphoreGive(at.mutex_send);return result;
}bool at_send_no_reply(const char *data, uint16_t datalen, bool delimiter,uint32_t timeout)
{bool result=false;if(is_inited==false)return false;if(data==NULL)return false;if(datalen==0)return false;//lockif(xSemaphoreTake(at.mutex_send,timeout)!=pdTRUE)return false;do{if(at_uart_send(data,datalen,timeout)!=datalen)break;if(delimiter){if(at_uart_send(AT_DELIMITER,strlen(AT_DELIMITER),timeout)!=strlen(AT_DELIMITER))break; }result=true;} while (0);//unlockxSemaphoreGive(at.mutex_send);return result;
}bool at_register_callback(const char *prefix, at_recv_cb cb, void *arg)
{for(uint8_t i=0;i<MAX_OBJ_COUNT;i++){if(strcmp(prefix,at.obj[i].prefix)==0){DEBUG("This prefix has been registered");return false;}}for(uint8_t i=0;i<MAX_OBJ_COUNT;i++){if(at.obj[i].prefix==NULL){memset(&at.obj[i],0,sizeof(at_obj_t));at.obj[i].prefix=(char *)prefix;at.obj[i].callback=cb;at.obj[i].arg=arg;return true;}}return false;
}
测试代码如下:
/* USER CODE BEGIN Header_StartDefaultTask */
/*** @brief Function implementing the defaultTask thread.* @param argument: Not used* @retval None*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{/* USER CODE BEGIN StartDefaultTask *//* Infinite loop */float temp,humi;uint8_t write_buf[]="1234567890";uint8_t read_buf[20];uint16_t read_len;#define TEST_NAME 0X0001uint8_t buf[5];char reply_buf[30];uint16_t reply_len;debug_init();led_init();key_init();led_blink(2,5);sht30_init();at_parse_init();at_register_callback("+MQTT",test_callback,NULL);for(;;){memset(reply_buf,0,30);reply_len=30;if(at_send_wait_reply("AT+CSQ",true,"+CSQ","ERROR",reply_buf,&reply_len,1000)){DEBUG("-----recv %d,%s------",reply_len,reply_buf);}//at_send_no_reply("AT",2,true,1000);//at_uart_send("12345\r\n",7,1000);// storage_write(TEST_NAME,sizeof(write_buf),write_buf);// memset(read_buf,0,20);// read_len=20;// if(storage_read(TEST_NAME,&read_len,read_buf))// {// DEBUG("------%s-----",read_buf);// }// if(sht30_get_temp_humi(&temp,&humi))// {// DEBUG("temp=%f,humi=%f",temp,humi);// }osDelay(1000);}/* USER CODE END StartDefaultTask */
}
AT解析层的思路分析及代码实现相关推荐
- PTA 电话聊天狂人 思路分析及代码解析
PTA 电话聊天狂人 思路分析及代码解析v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析 三.具体实现 ...
- PTA 统计工龄 思路分析及代码解析
PTA 统计工龄 思路分析及代码解析v0.6 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析 三.具体实现 1. ...
- PTA 旅游规划(邻接矩阵) 思路分析及代码解析
PTA 旅游规划 思路分析及代码解析v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析(重点) 三.具体实 ...
- PTA 旅游规划(邻接表) 思路分析及代码解析
PTA 旅游规划_使用邻接表 思路分析及代码解析v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析(重点) ...
- PTA 树的同构 思路分析及代码解析
PTA 树的同构 思路分析及代码解析 v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 2. 思路分析(重点) 三.具体实现 1. 弯路和bug 2. 代码框 ...
- PTA 哈利·波特的考试 思路分析及代码解析
PTA 哈利·波特的考试 思路分析及代码解析v0.9.1 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析(重点) ...
- PTA QQ帐户的申请与登陆 思路分析及代码解析
PTA QQ帐户的申请与登陆 思路分析及代码解析v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析 三.具 ...
- 2022华数杯B题论文思路分析+完整代码(水下机器人组装计划)(一二问答案接出来和标准答案一样)(问题三四逼近正确答案)(完整论文,代码可直接跑)
写在前面:学校最近搞数学建模竞赛培训,以2022华数杯B题作为训练题目,在查资料过程中发现网上没有哪一篇论文解出了正确答案,而我们组利用Lingo软件准确的解出了正确答案,但是在第三问时,由于决策的变 ...
- 清华计算几何大作业思路分析和代码实现
清华计算几何大作业思路分析和代码实现 1. 计算几何之缘 2. 前置知识 3. 作业列表 4. 作业难度分析和选取建议 4.1 初阶(新手村之旅) 4.2 高阶(大师剑之旅) 4.3 终阶(折磨之旅) ...
最新文章
- 演练:创建和注册自定义 HTTP 模块
- linux c 获取进程 可执行文件路径
- JavaWeb入门_模仿天猫整站Tmall_SSH实践项目
- 【PC工具】注意安全,建议使用:安全软件,谷歌输入法下载
- 国产操作系统发展离不开人才和市场
- 必须在构造函数基/成员初始值设定项列表中初始化
- 从哲学源头思考自动驾驶网络架构设计
- UNP Chapter 19 - 多播
- NSCache实现内存缓存
- Nginx用为缓存服务器
- Android 两个App间进行IPC通信
- 详解spring 每个jar的作用(转)
- JAVA数据类型和运算符2
- Hindex--华为Hbase二级索引
- 赛尔号通信数据的逆向分析与还原(思路篇)
- 详述 Redis 选择单线程模型的原因以及 I/O 多路复用
- java获取url后缀,以及判断是否带参数(?params=xxx)
- 【快应用】如何去掉快应用页面的menuBar
- 洛谷 P1413 坚果保龄球
- The server of Nginx(二)——Nginx基本功能配置
热门文章
- Ardino基础教程 24_RGB全彩LED
- 【Android工具】更新手机视频流媒体客户端播放器OPlayer
- 【任务脚本】1104更新双十一京东淘宝任务脚本,全自动程序,淘宝京东自动做任务...
- 【PC工具】200416最终百度网盘——最终下载方法及注意事项,代理是什么
- Linux 5.4 rc1发布: 正式支持Leez P710开发板(转载)
- 基于socket的线上聊天框
- FPGA篇(五)Capture导出FPGA引脚分配和端口定义
- 天津:第十六届西青区民俗文化旅游节开幕
- 主线科技完成A轮融资,蔚来资本、普洛斯隐山资本联合领投
- 如何利用Python网络爬虫爬取微信朋友圈动态--附代码(下)