AT组件提供了MCU与外接通信模组间基于AT命令的基础通信能力,是物联网应用场景中不可或缺的模块之一。基于该组件,用户可以只关注AT指令的语义,无需关心AT指令的收发过程,简化外接模组的AT通信驱动的开发。下图是AliOS Things中AT组件的结构示意图。其包括:

  • AT CoreAT组件核心模块,主要包括AT配置处理、AT接收分发,AT设备管理。该模块实现AT接收、发处理、添加AT设备主流程。
  • AT API:AT组件API,主要包括发送、注册回调、数据读取、初始化、去初始化、添加设备、删除设备。该模块封装了AT核心模块的功能,简化了用户的调用方式。

API列表

名称 说明
at_init 初始化AT组件
at_deinit 去初始化AT组件
at_add_dev 根据配置添加AT设备
at_delete_dev 根据设备描述符删除AT设备
at_send_wait_reply 在用户task中,使用该接口发送数据,并等待回复
at_send_no_reply 使用该接口发送数据,但不等待回复
at_read 在回调函数里,从底层读取AT字符流
at_register_callback 注册AT接收处理回调函数
at_yield 单task情况下,从底层接收数据

使用

添加该组件

在使用at的组件或应用对应的aos.mk中添加

$(NAME)_COMPONENTS += at

在使用at的组件或应用对应的Config.in中添加

select AOS_COMP_AT if !AOS_CREATE_PROJECT

头文件

对外头文件代码位于include/utility/at,包括

at.h

使用时只需包含

#include "at/at.h"

使用示例

/* 初始化 */
    at_init();

    /**
     * 配置AT设备参数
     */
    uart_dev.port                = 1;
    uart_dev.config.baud_rate    = 9600;
    uart_dev.config.data_width   = DATA_WIDTH_8BIT;
    uart_dev.config.parity       = NO_PARITY;
    uart_dev.config.stop_bits    = STOP_BITS_1;
    uart_dev.config.flow_control = FLOW_CONTROL_DISABLED;
    uart_dev.config.mode         = MODE_TX_RX;

    at_config.type                             = AT_DEV_UART;
    at_config.port                             = uart_dev.port;
    at_config.dev_cfg                          = &uart_dev;
    at_config.send_wait_prompt                 = 0;

    /* 添加AT设备,成功后返回设备fd */
    if ((at_dev_fd = at_add_dev(&at_config)) < 0) {
        LOGE(TAG, "AT parser device add failed!\n");
        return -1;
    }

    /* 注册感兴趣前缀对应的回调处理 */
    at_register_callback(at_dev_fd, "+NSONMI:", NULL, NULL, 0,
                         m5310a_socket_data_indicator_handler, NULL);

    /* 发送AT test命令 */
    memset(cmd, 0, sizeof(cmd));
    snprintf(cmd, sizeof(cmd) - 1, "%s", "AT");
    /* 发送并等待回复 */
    at_send_wait_reply(at_dev_fd, cmd, strlen(cmd), true, NULL, 0,
                       rsp, M5310A_DEFAULT_RSP_LEN, NULL);
    if (strstr(rsp, "OK") == NULL) {
        LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
        return -1;
    }

更详细的例子请参考application/example/example_legacy/at_app

API 详情

at_init

原型

int at_init(void);

接口说明

初始化AT组件。

参数说明

返回值说明

说明
0 成功
负值 失败

接口示例

/* 初始化,先于其他API前调用 */
at_init();

at_deinit

原型

int at_deinit(void);

接口说明

去初始化AT组件。

参数说明

返回值说明

说明
0 成功
负值 失败

接口示例

/* 去初始化 */
at_deinit();

at_add_dev

原型

int at_add_dev(at_config_t *config);

接口说明

根据配置添加AT设备。

参数说明

参数 数据类型 方向 说明
config at_config_t * 输入 AT设备配置,at_config_t定义见标准宏和结构体定义

返回值说明

说明
非负值 成功,AT设备文件描述符
负值 失败

接口示例

/**
     * 配置AT设备参数
     */
    uart_dev.port                = 1;
    uart_dev.config.baud_rate    = 9600;
    uart_dev.config.data_width   = DATA_WIDTH_8BIT;
    uart_dev.config.parity       = NO_PARITY;
    uart_dev.config.stop_bits    = STOP_BITS_1;
    uart_dev.config.flow_control = FLOW_CONTROL_DISABLED;
    uart_dev.config.mode         = MODE_TX_RX;

    at_config.type                             = AT_DEV_UART;
    at_config.port                             = uart_dev.port;
    at_config.dev_cfg                          = &uart_dev;
    at_config.send_wait_prompt                 = 0;

    /* 添加AT设备,成功后返回设备fd */
    if ((at_dev_fd = at_add_dev(&at_config)) < 0) {
        LOGE(TAG, "AT parser device add failed!\n");
        return -1;
    }

at_delete_dev

原型

int at_delete_dev(int fd);

接口说明

根据设备描述符删除AT设备。

参数说明

参数 数据类型 方向 说明
fd int 输入 AT设备文件描述符

返回值说明

说明
0 成功
负值 失败

接口示例

/* 添加AT设备,成功后返回设备fd */
if ((at_dev_fd = at_add_dev(&at_config)) < 0) {
     LOGE(TAG, "AT parser device add failed!\n");
     return -1;
}

/* 删除fd对应的AT设备 */
if ((at_delete_dev(at_dev_fd)) < 0) {
     LOGE(TAG, "AT parser device delete failed!\n");
     return -1;
}

at_send_wait_reply

原型

int at_send_wait_reply(int fd, const char *cmd, int cmdlen, bool delimiter,
                       const char *data, int datalen,
                       char *replybuf, int bufsize,
                       const at_reply_config_t *atcmdconfig);

接口说明

在用户task中,使用该接口发送数据,并等待回复。

参数说明

参数 数据类型 方向 说明
fd int 输入 AT设备文件描述符
cmd const char * 输入 准备发送的命令字符串
cmdlen int 输入 命令字符串长度
delimiter bool 输入 是否添加分割符号
const char * const char * 输入 准备发送的数据字符串
datalen int 输入 数据长度
replybuf char * 输出 回复缓存指针,由调用者提供
bufsize int 输入 回复缓存大小
atcmdconfig const at_reply_config_t * 输入 回复前缀、成功后缀、失败后缀等配置

返回值说明

说明
0 成功
负值 失败

接口示例

/* 发送AT test命令 */
    memset(cmd, 0, sizeof(cmd));
    snprintf(cmd, sizeof(cmd) - 1, "%s", "AT");
    /* 发送并等待回复 */
    at_send_wait_reply(at_dev_fd, cmd, strlen(cmd), true, NULL, 0,
                       rsp, M5310A_DEFAULT_RSP_LEN, NULL);

    /* 检查是否包含期望字符 */
    if (strstr(rsp, "OK") == NULL) {
        LOGE(TAG, "%s %d failed rsp %s\r\n", __func__, __LINE__, rsp);
        return -1;
    }

at_send_no_reply

原型

int at_send_no_reply(int fd, const char *data, int datalen, bool delimiter);

接口说明

使用该接口发送数据,但不等待回复。

参数说明

参数 数据类型 方向 说明
fd int 输入 AT设备文件描述符
const char * const char * 输入 准备发送的数据字符串
datalen int 输入 数据长度

返回值说明

说明
0 成功
负值 失败

接口示例

/* 准备AT test命令 */
memset(cmd, 0, sizeof(cmd));
snprintf(cmd, sizeof(cmd) - 1, "%s", "AT");

/* 发送cmd,无等待 */
at_send_no_reply(at_dev_fd, cmd, strlen(cmd), true);

at_read

原型

int at_read(int fd, char *outbuf, int readsize);

接口说明

在回调函数里,从底层读取AT字符流。

参数说明

参数 数据类型 方向 说明
fd int 输入 AT设备文件描述符
char * char * 输出 缓存指针
readsize int 输入 读取长度

返回值说明

说明
非负 成功,读取长度
负值 失败

接口示例

while (data != ',') {
    /* 从对应fd读取数据,一般只在回调函数里调用*/
   ret = at_read(at_dev_fd, &data, 1);
   if  (ret != 1) {
       break;
   }
 
    /* 解析读出的数据*/
    if(data >= '0' && data <= '9') {
       fd = fd * 10 + (data - '0');
    }
  }

at_register_callback

原型

int at_register_callback(int fd, const char *prefix, const char *postfix, char *recvbuf,
                         int bufsize, at_recv_cb cb, void *arg);

接口说明

注册AT接收处理回调函数

参数说明

参数 数据类型 方向 说明
fd int 输入 AT设备文件描述符
const char * const char * 输入 感兴趣的前缀,必须
postfix const char * 输入 感兴趣的后缀,可选
recvbuf char * 输入 用于缓存前缀后缀之间的数据
bufsize int 输入 缓存大小
cb at_recv_cb 输入 回调处理函数
arg void * 输入 回调处理函数参数

返回值说明

说明
0 成功
负值 失败

接口示例

/* 注册多个前缀对应的回调函数 */
at_register_callback(at_dev_fd, "+NSONMI:", NULL, NULL, 0,
                         m5310a_socket_data_indicator_handler, NULL);
at_register_callback(at_dev_fd, "\r\nCONNECT OK", NULL, NULL, 0,
                         m5310a_socket_connect_indicator_handler, NULL);
at_register_callback(at_dev_fd, "+NSOCLI:", NULL, NULL, 0,
                         m5310a_socket_close_indicator_handler, NULL);

at_yield

原型

int at_yield(int fd, char *replybuf, int bufsize, const at_reply_config_t *atcmdconfig,
             int timeout_ms);

接口说明

单task情况下,从底层接收数据。

参数说明

参数 数据类型 方向 说明
fd int 输入 AT设备文件描述符
char * char * 输出 接收缓存
bufsize int 输入 缓存大小
atcmdconfig const at_reply_config_t * 输入 接收前缀、成功后缀、失败后缀配置
timeout_ms int 输入 超时时间

返回值说明

说明
0 成功
负值 失败

接口示例

/* 单task时, 调用该函数从底层缓存中收取数据并处理回调 */
at_yield(at_dev_fd, NULL, 0, NULL, 200);

配置说明

AT可配置项包括:

  • 是否定义AOS_ATCMD,默认为定义AOS_ATCMD
  • 最大AT设备数,默认是1
  • AT发送后等待超时时间,默认为是5000ms
  • AT读取超时时间,默认为1000ms
  • AT分段发送时等待提示符超时时间,默认为200ms

移植说明

AT模块需要实现AT设备操作wrapper、系统wrapper。

AT设备操作wrapper

接口 描述
int (*init)(void *dev)

初始化设备

dev:设备参数

返回值:0成功,-1失败

int (*recv)(void *dev, void *data, uint32_t expect_size, uint32_t *recv_size, uint32_t timeout)

数据接收

dev:设备参数

data:数据地址

expect_size:期望长度

recv_size:接收长度

timeout:接收超时时长

返回值:0成功,-1失败

int (*send)(void *dev, void *data, uint32_t size, uint32_t timeout)

数据发送

dev:设备参数

data:数据地址

size:长度

timeout:超时时长

返回值:>0发送长度,-1失败

int (*deinit)(void *dev)

去初始化

dev:设备参数

返回值:0成功,-1失败

系统wrapper

锁函数

函数名 说明
void *atpsr_mutex_new(void) 创建锁
void atpsr_mutex_lock(void *mutex) 上锁
void atpsr_mutex_unlock(void *mutex) 开锁
void atpsr_mutex_free(void *mutex) 删除锁

信号量函数

函数名 说明
void *atpsr_sem_new(void) 创建信号量
void atpsr_sem_signal(void *sem) 释放信号量
int atpsr_sem_wait(void *sem, uint32_t timeout_ms) 等待信号量
void atpsr_sem_free(void *sem) 删除信号量

任务函数

函数名 说明
int atpsr_task_new_ext(void *task, char *name, void (*fn)(void *), void *arg, int stack_size, int prio) 创建任务
void atpsr_sleep_ms(const unsigned int millisec) 休眠任务

内存函数

函数名 说明
void *atpsr_malloc(uint32_t size) 分配内存
void atpsr_free(void *ptr) 释放内存

标准宏和结构体说明

结构体at_config_t定义

typedef struct {
    uint8_t            port;                 // 端口号
    at_dev_type_t      type;                 // AT设备类型,例如UART
    void               *dev_cfg;             // AT设备底层参数,例如hal/uart.h中的uart_config_t
    at_reply_config_t  reply_cfg;            // AT接收前缀、后缀
    char               *send_delimiter;      // AT发送分割符
    uint32_t           timeout_ms;           // AT发送或接收超时
    uint8_t            send_wait_prompt;     // AT发送数据时是否等待提示符
    uint32_t           prompt_timeout_ms;    // AT发送数据时等待提示符超时时间
    uint8_t            send_data_no_wait;    // AT发送数据后是否等待回复
    int                recv_task_priority;   // AT接收task优先级
    int                recv_task_stacksize;  // AT接收task栈大小
} at_config_t;

结构体at_reply_config_t定义

typedef struct {
    char *reply_prefix;                 // 回复前缀
    char *reply_success_postfix;        // 成功后缀
    char *reply_fail_postfix;           // 失败后缀
} at_reply_config_t;

结构体at_dev_ops_t定义

typedef struct {
   at_dev_type_t type;
   int (*init)(void *dev);
   int (*recv)(void *dev, void *data, uint32_t expect_size,
               uint32_t *recv_size, uint32_t timeout);
   int (*send)(void *dev, void *data, uint32_t size,
               uint32_t timeout);
   int (*deinit)(void *dev);
} at_dev_ops_t;