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 */
}