AT解析层的思路分析及代码实现

本文详细解读了AT解析层的接口API,包括初始化与销毁函数,以及发送等待回复与无响应命令的处理过程。核心部分展示了代码实现,涉及回调处理、接收任务和并发控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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    200

typedef 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 char
        do
        {
            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 prefix
            if(at_parse_match_obj(at.recv_buf,at.recv_counter))break;

            //match fail prefix
            if(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 prefix
            if(at.send_procees.right_prefix!=NULL)		// 必须上层有发才处理
            {
                if(strstr(at.recv_buf,at.send_procees.right_prefix)!=NULL)
                {
                    //copy recv data to reply buffer
                    if((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 init
        if(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);
    
    //clean
    at_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;

    //lock
    if(xSemaphoreTake(at.mutex_send,timeout)!=pdTRUE)return false;

    //save parameters
    memset(&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 data
        DEBUG("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 sem
        xSemaphoreTake(at.sem_send,0);
        xSemaphoreTake(at.sem_send,timeout);
        result=at.send_procees.result;
    } while (0);
    
    //unlock
    memset(&at.send_procees,0,sizeof(at.send_procees));		// 这里必须记得清空,否则很容易出bug
    xSemaphoreGive(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;

    //lock
    if(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);

    //unlock
    xSemaphoreGive(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 0X0001
  uint8_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 */
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值