# AT device #
中文页 | 英文页
AT device 软件包是由 RT-Thread AT 组件针对不同 AT 设备的移植文件和示例代码组成,目前支持的 AT 设备有:ESP8266、ESP32、M26、MC20、RW007、MW31、SIM800C、W60X 、SIM76XX、A9/A9G、BC26 、AIR720、ME3616、M6315、BC28、EC200X、M5311、L610系列设备等,目前上述设备都完成对 AT socket
功能的移植,及设备通过 AT 命令实现标准 socket 编程接口,完成 socket 通讯的功能,具体功能介绍可参考 《RT-Thread 编程指南》AT 命令章节 。
名称 | 说明 |
---|---|
src | AT device 实现源码目录 |
inc | AT device 头文件目录 |
sample | 不同设备示例文件目录 |
class | 不同设备针对 AT 组件的移植适配目录 |
class/esp8266 | ESP8266 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/esp32 | ESP32 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/rw007 | RW007 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/sim800c | SIM800C 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/sim76xx | SIM76XX 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/m26 | M26/MC20 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/ec20 | EC20 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/mw31 | MW31 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/w60x | W60X 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/a9g | A9G 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/bc26 | bc26 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/air720 | air720 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/me3616 | me3616 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/m6315 | m6315 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/bc28 | bc28 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/ec200x | EC200T、EC200S 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/n21 | N21 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/n58 | N58 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/m5311 | M5311 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/l610 | L610 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
class/ml305 | ML305 设备针对 AT 组件的移植目录,实现 AT Socket 功能 |
详见 LICENSE
文件。
AT device 软件包是对 AT 组件和 AT socket 功能的移植,需开启 AT 组件库和 AT socket 功能来获取 AT device 软件包。
版本号说明
AT device 软件包目前已经发布多个版本,各个版本之间选项配置方式和其对应的系统版本有所不同,下面主要列出当前可使用的软件包版本信息:
上述 版本判断在 menuconfig 中自动完成,at_device 软件包选择版本时会根据当前系统环境给出最佳版本支持,这里版本介绍作为运行环境参考。
针对不同的版本号,在 ENV 中的选项配置也有所不同,主要分为如下几部分:
V1.X.X 版本配置选项介绍
开启 AT device 软件包,该版本只支持同时开启一种 AT 设备, 配置选项具体如下所示:
RT-Thread online packages --->
IoT - internet of things --->
-*- AT DEVICE: RT-Thread AT component porting or samples for different device
[ ] Enable at device init by thread
AT socket device modules (Not selected, please select) --->
Version (V1.6.0) --->
V2.X.X (latest) 版本配置选项介绍
开启 AT device 软件包,该版本支持同时开启多种 AT 设备配置选项具体如下所示:
RT-Thread online packages --->
IoT - internet of things --->
-*- AT DEVICE: RT-Thread AT component porting or samples for different device
[*] Quectel M26/MC20 --->
[*] Enable initialize by thread
[*] Enable sample
(-1) Power pin
(-1) Power status pin
(uart3) AT client device name
(512) The maximum length of receive line buffer
[ ] Quectel EC20 --->
[ ] Espressif ESP32 --->
[*] Espressif ESP8266 --->
[*] Enable initialize by thread
[*] Enable sample
(realthread) WIFI ssid
(12345678) WIFI password
(uart2) AT client device name
(512) The maximum length of receive line buffer
[ ] Realthread RW007 --->
[ ] SIMCom SIM800C --->
[ ] SIMCom SIM76XX --->
[ ] Notion MW31 --->
[ ] WinnerMicro W60X --->
[ ] AiThink A9/A9G --->
[ ] Quectel BC26 --->
[ ] Luat air720 --->
[ ] GOSUNCN ME3616 --->
[ ] ChinaMobile M6315 --->
[ ] Quectel BC28 --->
[ ] Quectel ec200x --->
[ ] Neoway N21 --->
[ ] Neoway N58 --->
[ ] ChinaMobile M5311 --->
[ ] ChinaMobile ML305 --->
Version (latest) --->
上面配置选项以 2G 模块和 WIFI 模块选项为例,介绍了V2.X.X
版本 AT device 软件包配置方式,如下几点值得注意:
V2.X.X
版本支持同时开启多个 AT 设备,可以在 FinSH 中通过 ifocnfig
命令查看开启的设备信息;V2.X.X
版本设备需要注册之后才可使用,目前在 samples 目录文件中完成设备注册,用户也可以在应用层自定义设备注册。Power pin
和 Power status pin
等引脚选项根据具体设备硬件连接情况配置,如果不使用硬件上电功能,可以配置为 -1
;AT client device name
应该都不相同。AT 组件相关配置选项介绍
选中 AT device 软件包并开启相关设备支持之后,会默认选中 AT 组件的客户端功能,下面是 AT 组件配置选项,
RT-Thread Components --->
Network --->
AT commands --->
[ ] Enable debug log output
[ ] Enable AT commands server
-*- Enable AT commands client
(1) The maximum number of supported clients
-*- Enable BSD Socket API support by AT commnads
[*] Enable CLI(Command-Line Interface) for AT commands
[ ] Enable print RAW format AT command communication data
(128) The maximum lenght of AT Commonds buffe
其中和 AT device 软件包相关的配置选项:
latest
版本支持多个选中多个 AT 设备接入实现 AT Socket 功能,V1.X.X
版本只支持单个 AT 设备接入。latest
版本;at_sample_xxx.c
中说明,部分功能需要增加AT_CMD_MAX_LEN
、RT_SERIAL_RB_BUFSZ
设定值大小。…\src\at_device.c
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-05-08 chenyong first version
*/
#include <stdlib.h>
#include <string.h>
#include <at_device.h>
#define DBG_TAG "at.dev"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
/* The global list of at device */
static rt_slist_t at_device_list = RT_SLIST_OBJECT_INIT(at_device_list);
/* The global list of at device class */
static rt_slist_t at_device_class_list = RT_SLIST_OBJECT_INIT(at_device_class_list);
/**
* This function will get the first initialized AT device.
*
* @return the AT device structure pointer
*/
struct at_device *at_device_get_first_initialized(void)
{
rt_base_t level;
rt_slist_t *node = RT_NULL;
struct at_device *device = RT_NULL;
level = rt_hw_interrupt_disable();
rt_slist_for_each(node, &at_device_list)
{
device = rt_slist_entry(node, struct at_device, list);
if (device && device->is_init == RT_TRUE)
{
rt_hw_interrupt_enable(level);
return device;
}
}
rt_hw_interrupt_enable(level);
return RT_NULL;
}
/**
* This function will get AT device by device name.
*
* @param type the name type
* @param name the device name or the client name
*
* @return the AT device structure pointer
*/
struct at_device *at_device_get_by_name(int type, const char *name)
{
rt_base_t level;
rt_slist_t *node = RT_NULL;
struct at_device *device = RT_NULL;
RT_ASSERT(name);
level = rt_hw_interrupt_disable();
rt_slist_for_each(node, &at_device_list)
{
device = rt_slist_entry(node, struct at_device, list);
if (device)
{
if (((type == AT_DEVICE_NAMETYPE_DEVICE) || (type == AT_DEVICE_NAMETYPE_NETDEV)) &&
(rt_strncmp(device->name, name, rt_strlen(name)) == 0))
{
rt_hw_interrupt_enable(level);
return device;
}
else if ((type == AT_DEVICE_NAMETYPE_CLIENT) &&
(rt_strncmp(device->client->device->parent.name, name, rt_strlen(name)) == 0))
{
rt_hw_interrupt_enable(level);
return device;
}
}
}
rt_hw_interrupt_enable(level);
return RT_NULL;
}
#ifdef AT_USING_SOCKET
/**
* This function will get AT device by ip address.
*
* @param ip_addr input ip address
* network
* @return != NULL: network interface device object
* NULL: get failed
*/
struct at_device *at_device_get_by_ipaddr(ip_addr_t *ip_addr)
{
rt_base_t level;
rt_slist_t *node = RT_NULL;
struct at_device *device = RT_NULL;
level = rt_hw_interrupt_disable();
rt_slist_for_each(node, &at_device_list)
{
device = rt_slist_entry(node, struct at_device, list);
if (device && ip_addr_cmp(ip_addr, &(device->netdev->ip_addr)))
{
rt_hw_interrupt_enable(level);
return device;
}
}
rt_hw_interrupt_enable(level);
return RT_NULL;
}
#endif /* AT_USING_SOCKET */
/**
* This function will perform a variety of control functions on AT devices.
*
* @param device the pointer of AT device structure
* @param cmd the command sent to AT device
* @param arg the argument of command
*
* @return = 0: perform successfully
* < 0: perform failed
*/
int at_device_control(struct at_device *device, int cmd, void *arg)
{
if (device->class->device_ops->control)
{
return device->class->device_ops->control(device, cmd, arg);
}
else
{
LOG_W("AT device(%s) not support control operations.", device->name);
return RT_EOK;
}
}
/**
* This function registers an AT device class with specified device class ID.
*
* @param class the pointer of AT device class structure
* @param class_id AT device class ID
*
* @return 0: register successfully
*/
int at_device_class_register(struct at_device_class *class, uint16_t class_id)
{
rt_base_t level;
RT_ASSERT(class);
/* Fill AT device class */
class->class_id = class_id;
/* Initialize current AT device class single list */
rt_slist_init(&(class->list));
level = rt_hw_interrupt_disable();
/* Add current AT device class to list */
rt_slist_append(&at_device_class_list, &(class->list));
rt_hw_interrupt_enable(level);
return RT_EOK;
}
/* Get AT device class by client ID */
static struct at_device_class *at_device_class_get(uint16_t class_id)
{
rt_base_t level;
rt_slist_t *node = RT_NULL;
struct at_device_class *class = RT_NULL;
level = rt_hw_interrupt_disable();
/* Get AT device class by class ID */
rt_slist_for_each(node, &at_device_class_list)
{
class = rt_slist_entry(node, struct at_device_class, list);
if (class && class->class_id == class_id)
{
rt_hw_interrupt_enable(level);
return class;
}
}
rt_hw_interrupt_enable(level);
return RT_NULL;
}
/**
* This function registers an AT device with specified device name and AT client name.
*
* @param device the pointer of AT device structure
* @param device_name AT device name
* @param at_client_name AT device client name
* @param class_id AT device class ID
* @param user_data user-specific data
*
* @return = 0: register successfully
* < 0: register failed
*/
int at_device_register(struct at_device *device, const char *device_name,
const char *at_client_name, uint16_t class_id, void *user_data)
{
rt_base_t level;
int result = 0;
static int device_counts = 0;
char name[RT_NAME_MAX] = {0};
struct at_device_class *class = RT_NULL;
RT_ASSERT(device);
RT_ASSERT(device_name);
RT_ASSERT(at_client_name);
class = at_device_class_get(class_id);
if (class == RT_NULL)
{
LOG_E("get AT device class(%d) failed.", class_id);
result = -RT_ERROR;
goto __exit;
}
/* Fill AT device object*/
#ifdef AT_USING_SOCKET
device->sockets = (struct at_socket *) rt_calloc(class->socket_num, sizeof(struct at_socket));
if (device->sockets == RT_NULL)
{
LOG_E("no memory for AT Socket number(%d) create.", class->socket_num);
result = -RT_ENOMEM;
goto __exit;
}
/* create AT device socket event */
rt_snprintf(name, RT_NAME_MAX, "at_se%d", device_counts++);
device->socket_event = rt_event_create(name, RT_IPC_FLAG_FIFO);
if (device->socket_event == RT_NULL)
{
LOG_E("no memory for AT device(%s) socket event create.", device_name);
result = -RT_ENOMEM;
goto __exit;
}
#endif /* AT_USING_SOCKET */
rt_memcpy(device->name, device_name, rt_strlen(device_name));
device->class = class;
device->user_data = user_data;
/* Initialize current AT device single list */
rt_slist_init(&(device->list));
level = rt_hw_interrupt_disable();
/* Add current AT device to device list */
rt_slist_append(&at_device_list, &(device->list));
rt_hw_interrupt_enable(level);
/* Initialize AT device */
result = class->device_ops->init(device);
if (result < 0)
{
goto __exit;
}
__exit:
if (result < 0)
{
device->is_init = RT_FALSE;
}
else
{
device->is_init = RT_TRUE;
}
return result;
}