RT-Thread AT组件源码分析(含修改、以EC20为例)

本文详细介绍了RT-Thread中AT组件的各种设置,包括调试日志输出、RAW格式通信数据打印、AT初始化选项,以及GPRS网络注册状态检查。特别关注了如何在开发和调试过程中启用和关闭特定功能以优化性能和避免影响关键功能。

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

 AT组件设置

路径:RT-Thread Settings / 组件 / 网络 / AT命令

【使能调试日志的输出】:开启后可以看到日志级别为debug的相关日志。

【使能打印通信数据的RAW格式】:开启后可以看到每次执行的 AT 指令以及返回的执行结果。下图为开启后,运行中的打印数据左侧为原始hex数据,右侧为hex数据的ASCII形式

使用建议:

建议在开发、调试、故障排查、故障复现时开启【使能打印通信数据的RAW格式】

由于远程升级过程中数据量巨大且这里是同步打印,会严重影响远程升级功能,发布正式版本、无人值守的现场调试版本必须关闭此选项

AT软件包设置

路径:RT-Thread Settings / 软件包 / IoT-物联网 / AT设备 / 移远EC20

【使能在线程中初始化】:

关闭:AT初始化将在RT-Thread的main函数前,系统初始化中进行,这种情况下AT初始化将非常耗时(初始化失败还会重试5次),从设备上电到程序正常运行(屏幕点击可操作)约需要2分钟。

开启:AT初始化需要自己创建线程进行,从设备上电到程序正常运行耗时短,但是这样会与应用程序中判断离线的逻辑存在一定的冲突。

【电源引脚、电源状态引脚】-1表示不配置,建议不使用软件包控制引脚,最好是在在应用程序中配合应用层联网逻辑控制4G模组得电断电

GPRS网络注册状态检查

AT组件中会自动创建一个网络注册状态检查线程,使用 “AT+CGREG?” 指令进行GPRS网络注册状态的检查,并根据指令返回的结果修改网卡设备的标志位。

线程的入口函数是 ec20_check_link_status_entry(packages/at_device-v2.0.4/class/ec20/at_device_ec20.c),该线程每间隔 EC20_LINK_DELAY_TIME毫秒(当前版本为30s)发送一条 AT 指令进行 GPRS 网络注册状态的检查,并根据返回的结果在函数 netdev_low_level_set_link_status() 中修改 netdev->flags。各种情况的执行结果分析如下所示

上次状态

本次状态

操作

未注册

未注册

未注册

注册

netdev->flags |= NETDEV_FLAG_LINK_UP

执行check_netdev_internet_up_work()函数测试联网

注册

未注册

netdev->flags &= ~NETDEV_FLAG_LINK_UP

netdev->flags &= ~NETDEV_FLAG_INTERNET_UP

若开启网络自动切换,则执行通过check_netdev_internet_up_work()函数切换到默认网络设备

注册

注册

使用建议:

建议关闭,这个线程仅能判断网络注册状态,无法判断TCP连接状态,应用层现有检测离线的逻辑(连续90s未收到数据、连续5帧发送失败(每帧重发3次)等)能够满足使用需求。

关闭方式:

在文件:packages / at_device-v2.0.4 / class / ec20 / at_device_ec20.c

找到函数:void ec20_init_thread_entry(void *parameter)

屏蔽行:ec20_netdev_check_link_status(device->netdev);

连接外网检查,实际使用一定要屏蔽

rt-thread/components/net/sal_socket/src/sal_socket.c 中的 check_netdev_internet_up_work() 函数会自动与 “link.rt-thread.org:8101” 创建UDP连接,进行数据收发测试,从而判断是否可以连接外网。

该函数的执行的过程大致为在 ec20 初始化线程 ec20_init_thread_entry() 中将将外网检查任务提交到 sys_work 工作队列中,系统工作队列处理线程 _workqueue_thread_entry() 会不断的检测是否有需要运行的任务,如果有则执行相应的任务。

建议关闭,这个连接外网检查通过会置网络设备状态为“成功连接至互联网”,由于这个IP的问题,使用定向卡的设备会检查失败,从而影响后续收发的逻辑

关闭方式:

在文件:rt-thread/components/net/sal_socket/src/sal_socket.c

找到函数:

static void check_netdev_internet_up_work(struct rt_work *work, void *work_data)

修改为直接置标志位为成功,如下:

static void check_netdev_internet_up_work(struct rt_work *work, void *work_data)
{
    struct netdev *netdev = (struct netdev *)work_data;
    netdev->flags |= NETDEV_FLAG_INTERNET_UP;
    return;
}

数据接收流程

解析+QIURC时,存在无法正常解析数据的情况,需要增加以下兜底方式,实测有效。

数据接收流程中的修改:

文件:packages / at_device-v2.0.4 / class / ec20 / at_socket_ec20.c

函数:

static void urc_recv_func(struct at_client *client, const char *data, rt_size_t size)

行:

sscanf(data, "+QIURC: \"recv\",%d,%d", &device_socket, &bfsz);

此行作用是解析需要接收的数据长度。

从网络接收数据时,数据会以如下格式直接输 出到 COM 口上:

+QIURC: "recv",<connectID>, <currectrecvlength><CR><LF><data>

RT-Thread中的接收逻辑:

  1. 解析<currectrecvlength>数据,获取有效数据的字节数
  2. 根据字节数来接收数据

因此,如果这个<currectrecvlength>解析出现错误,则接收不到正确的串口数据,导致应用层无法处理数据。

为此,增加了两种不同的<currectrecvlength>解析方式:

  1. 数逗号:<currectrecvlength>一定是在第二个数字的位置,即第一个逗号后
  2. 直接解析对应位置的字符:由于我们所涉及的<connectID>仅一个,不涉及2位数及以上的情况,因此可以确定

   

 sscanf(data, "+QIURC: \"recv\",%d,%d", &device_socket, &bfsz);
    if (0 == bfsz && size)
    {
        LOG_E("[xx]urc_recv_func: size is %d, data is:%s", size, data);
        LOG_E("get bfsz is 0, retry");
        char *result = NULL;
        int count = 0;
        int start_urc_len = -1;
        int urc_len = rt_strlen(data);
        for (int i = 0; i < urc_len; i++)
        {
            if (data[i] == ',')
            {
                count++;
                if (count == 2)
                {
                    start_urc_len = i;
                }
            }
        }
        if (start_urc_len != -1)
        {
            result = (char *)rt_malloc(sizeof(char) * (urc_len - start_urc_len + 2));
            rt_strncpy(result, data + start_urc_len + 1, urc_len - start_urc_len);
            result[urc_len - start_urc_len] = '\0';
            bfsz = atoi(result);
            rt_free(result);
        }
        LOG_E("[xx]urc_recv_func: (manual parsing)bfsz is %d, data is:%s", bfsz, data);
        if (bfsz == 0)
        {
            if (data[17] >= '0' && data[17] <= '9' && data[18] >= '0' && data[18] <= '9')
            {
                bfsz = (data[17] - '0') * 10 + (data[18] - '0');
                LOG_E("[ZGX]urc_recv_func: (manual parsing)bfsz is 0, second is %d", bfsz);
            }
        }
    }

 数据发送流程

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值