文章目录

  • 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解析层的思路分析及代码实现相关推荐

  1. PTA 电话聊天狂人 思路分析及代码解析

    PTA 电话聊天狂人 思路分析及代码解析v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析 三.具体实现 ...

  2. PTA 统计工龄 思路分析及代码解析

    PTA 统计工龄 思路分析及代码解析v0.6 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析 三.具体实现 1. ...

  3. PTA 旅游规划(邻接矩阵) 思路分析及代码解析

    PTA 旅游规划 思路分析及代码解析v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析(重点) 三.具体实 ...

  4. PTA 旅游规划(邻接表) 思路分析及代码解析

    PTA 旅游规划_使用邻接表 思路分析及代码解析v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析(重点) ...

  5. PTA 树的同构 思路分析及代码解析

    PTA 树的同构 思路分析及代码解析 v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 2. 思路分析(重点) 三.具体实现 1. 弯路和bug 2. 代码框 ...

  6. PTA 哈利·波特的考试 思路分析及代码解析

    PTA 哈利·波特的考试 思路分析及代码解析v0.9.1 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析(重点) ...

  7. PTA QQ帐户的申请与登陆 思路分析及代码解析

    PTA QQ帐户的申请与登陆 思路分析及代码解析v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析 三.具 ...

  8. 2022华数杯B题论文思路分析+完整代码(水下机器人组装计划)(一二问答案接出来和标准答案一样)(问题三四逼近正确答案)(完整论文,代码可直接跑)

    写在前面:学校最近搞数学建模竞赛培训,以2022华数杯B题作为训练题目,在查资料过程中发现网上没有哪一篇论文解出了正确答案,而我们组利用Lingo软件准确的解出了正确答案,但是在第三问时,由于决策的变 ...

  9. 清华计算几何大作业思路分析和代码实现

    清华计算几何大作业思路分析和代码实现 1. 计算几何之缘 2. 前置知识 3. 作业列表 4. 作业难度分析和选取建议 4.1 初阶(新手村之旅) 4.2 高阶(大师剑之旅) 4.3 终阶(折磨之旅) ...

最新文章

  1. 演练:创建和注册自定义 HTTP 模块
  2. linux c 获取进程 可执行文件路径
  3. JavaWeb入门_模仿天猫整站Tmall_SSH实践项目
  4. 【PC工具】注意安全,建议使用:安全软件,谷歌输入法下载
  5. 国产操作系统发展离不开人才和市场
  6. 必须在构造函数基/成员初始值设定项列表中初始化
  7. 从哲学源头思考自动驾驶网络架构设计
  8. UNP Chapter 19 - 多播
  9. NSCache实现内存缓存
  10. Nginx用为缓存服务器
  11. Android 两个App间进行IPC通信
  12. 详解spring 每个jar的作用(转)
  13. JAVA数据类型和运算符2
  14. Hindex--华为Hbase二级索引
  15. 赛尔号通信数据的逆向分析与还原(思路篇)
  16. 详述 Redis 选择单线程模型的原因以及 I/O 多路复用
  17. java获取url后缀,以及判断是否带参数(?params=xxx)
  18. 【快应用】如何去掉快应用页面的menuBar
  19. 洛谷 P1413 坚果保龄球
  20. The server of Nginx(二)——Nginx基本功能配置

热门文章

  1. Ardino基础教程 24_RGB全彩LED
  2. 【Android工具】更新手机视频流媒体客户端播放器OPlayer
  3. 【任务脚本】1104更新双十一京东淘宝任务脚本,全自动程序,淘宝京东自动做任务...
  4. 【PC工具】200416最终百度网盘——最终下载方法及注意事项,代理是什么
  5. Linux 5.4 rc1发布: 正式支持Leez P710开发板(转载)
  6. 基于socket的线上聊天框
  7. FPGA篇(五)Capture导出FPGA引脚分配和端口定义
  8. 天津:第十六届西青区民俗文化旅游节开幕
  9. 主线科技完成A轮融资,蔚来资本、普洛斯隐山资本联合领投
  10. 如何利用Python网络爬虫爬取微信朋友圈动态--附代码(下)