AT指令框架--从机版]
一、核心思想
- 采用__attribute__((used)) attribute((section (“atcmd”)))的形式
优点:
- 可以自由变换输出通道,实现三方通讯。
- 注册AT指令,只用写到模块内部,不用耦合其他文件
二、下面就是举例使用方法:test.c
#include "atcmd_slave.h"
#if ATCMD_EN
// 在功能模块中定义一个标准函数
static int test(atcmd_pack_t *pack) {
uint8_t buff[20] = "test\r\n";
strcat((char*)buff, AT_OK);
pack->reply(buff, strlen((char*)buff));
return 0;
}
static int test2(atcmd_pack_t *pack) {
if (pack->argc != 2) return -1;
uint8_t buff[20] = "";
uint8_t num = 0, num1 = 0;
sscanf((char*)(pack->data), "%c,%c", &num, &num1);
snprintf((char*)buff, 20, "%d,%d"AT_OK, num, num1);
pack->reply(buff, strlen((char*)buff));
return 1;
}
// 注册AT指令,传入标准函数
ATCMD_INIT("AT^TEST?", test);
ATCMD_INIT("AT^TEST=", test2);
#endif
三、用串口举例
没有使用DMA和中断,仅提供思路。
uint8_t buff[255] = {
0};
uint8_t len = 0;
void uart_rx_cb(uint8_t data) {
buff[len] = data;
len++;
if (len == 1 && buff[0] != 'A')
len = 0;
else if (len == 2 && buff[1] != 'T')
len = 0;
else if (len == 3 && buff[2] != '^')
len = 0;
else if (buff[len] == '\n' && buff[len - 1] == '\r') {
atcmd_pack_t pack;
pack.reply = uart_send;
pack.data = data;
pack.len = len;
atcmd_msg_handle(&pack);
}
}
如果使用DMA和中断,直接:
void uart_rx_cb(uint8_t *data, uint16_t len) {
atcmd_pack_t pack;
pack.reply = uart_send;
pack.data = data;
pack.len = len;
atcmd_msg_handle(&pack);
}
四、代码:
/********************************************************************************
* @file atcmd_slave.c
* @author jianqiang.xue
* @Version V1.0.0
* @Date 2022-09-04
* @brief 从机版 AT指令 https://lisun.blog.csdn.net/article/details/126683930
********************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "atcmd_slave.h"
extern atcmd_info_t __atcmd_start;
extern atcmd_info_t __atcmd_end;
bool atcmd_msg_handle(atcmd_pack_t* pack) {
bool match = false;
atcmd_info_t* atcmd;
for (atcmd = &__atcmd_start; atcmd < &__atcmd_end; atcmd++) {
if (atcmd->name != (char *)0xFFFFFFFF) {