Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
AT
at_device
痛斥 AT 之 AT 组件
发布于 2021-06-26 09:34:46 浏览:3133
订阅该版
最近本人重新使用了一下 AT 组件,阅读了其源码,并拓展阅读了一下 at_socket 及 at_device 的源码,深恶痛绝,特此写下该系列的吐槽文章。 首先我先展示下我的最终效果,我使用的 MCU 为 GD32,模组为 EC600S-CN。 我将每个 socket 都作为一个 device: ``` msh />list_device device type ref count ---------------- -------------------- ---------- norflash0 Block Device 0 spi20 SPI Device 0 rtc RTC 0 EC600S_skt11 Miscellaneous Device 0 EC600S_skt10 Miscellaneous Device 0 EC600S_skt9 Miscellaneous Device 0 EC600S_skt8 Miscellaneous Device 0 EC600S_skt7 Miscellaneous Device 0 EC600S_skt6 Miscellaneous Device 0 EC600S_skt5 Miscellaneous Device 0 EC600S_skt4 Miscellaneous Device 0 EC600S_skt3 Miscellaneous Device 1 EC600S_skt2 Miscellaneous Device 1 EC600S_skt1 Miscellaneous Device 1 EC600S_skt0 Miscellaneous Device 1 EC600S Miscellaneous Device 1 spi2 SPI Bus 0 i2c1 I2C Bus 0 wdt Miscellaneous Device 0 acon Character Device 2 usart5 Character Device 0 usart2 Character Device 1 usart1 Character Device 1 pin Miscellaneous Device 0 msh />lis list_fd list_thread list_sem list_event list_mutex list_mailbox list_msgqueue list_timer list_device msh />list_fd fd type ref magic path -- ------ --- ----- ------ 3 device 1 fdfd /acon 4 device 1 fdfd /usart2 5 device 1 fdfd /EC600S_skt0 6 device 1 fdfd /EC600S_skt1 7 device 1 fdfd /EC600S_skt2 8 device 1 fdfd /EC600S_skt3 msh /> ``` 编程方法如下: ```C rt_device_t ec600s_dev = rt_device_find(EC600S_DEVICE_NAME); rt_device_t empty_socket; rt_device_control(ec600s_dev, RT_EC600S_CTRL_ALLOC_SOCKET, &empty_socket); char port[30] = ""; strcat(port, "/dev/"); strcat(port, empty_socket->parent.name); int s = open(port, O_RDWR); struct ec600s_socket_configure config; config.type = EC600S_SOCKET_TCP; config.server = "119.23.105.150"; config.port = 6008; int rc; fd_set rset, wset, errset; struct timeval select_timeout; _tcp_pass_start: rc = ioctl(s, RT_EC600S_SOCKET_CTRL_CONNECT, &config); if(rc != 0) goto _tcp_pass_restart; select_timeout.tv_sec = 150; select_timeout.tv_usec = 0; FD_ZERO(&wset); FD_SET(s, &wset); rc = select(s + 1, RT_NULL, &wset, RT_NULL, &select_timeout); if(rc <= 0) goto _tcp_pass_restart; rt_kprintf("TCP server connect success.\r\n"); select_timeout.tv_sec = 1; select_timeout.tv_usec = 0; restart_flag = 0; while(1) { if(restart_flag) break; FD_ZERO(&rset); FD_ZERO(&errset); FD_SET(s, &rset); FD_SET(s, &errset); rc = select(s + 1, &rset, RT_NULL, &errset, &select_timeout); if(rc < 0) break; if(rc > 0) { if(FD_ISSET(s, &errset)) break; if(FD_ISSET(s, &rset)) { int recv_len = tcp_receive(s, recv_buf, sizeof(recv_buf), 300, 300); if(recv_len <= 0) break; LOG_I("recv len:%d", recv_len); if(write(s, recv_buf, recv_len) != recv_len) break; } } } _tcp_pass_restart: ioctl(s, RT_EC600S_SOCKET_CTRL_CLOSE, RT_NULL); rt_thread_mdelay(1000); rt_kprintf("restart!\r\n"); goto _tcp_pass_start; ``` 使用 posix 接口对每个 socket 进行操作。 最终测试结果: ![image.png](https://oss-club.rt-thread.org/uploads/20210626/c4f111413214ead099f17eb80c424382.png) 使用 4 个 socket 连接服务器,这里我使用了内网穿透。 通过服务器给 4 个 socket 同时发送 1000K 的数据。 1.at_client 的 end sign 设置 end sign 就是需要到结束符的时候通知应用啊,at_client 中检测到 end sign 就作为一行,然后呢也没个通知,怎么用? 我们来看下 at_device 中对于其的使用: ![image.png](https://oss-club.rt-thread.org/uploads/20210626/402d9215dce847bb2fc26ea4290fe253.png) 创建 resp 的时候指定行数为 2,设置 end sign 为 > ,这出问题概率不要太高。模组中间突然给你上报一条 URC ,你也认为满足条件了,然后就开始发送数据,结果就是出问题。 我的改进方案: ![image.png](https://oss-club.rt-thread.org/uploads/20210626/6884ab74cefd1b90bfbf04fd265d7f19.png) 增加 end sign 的通知。 2.at_client_obj_recv 的问题 ```C rt_size_t at_client_obj_recv(at_client_t client, char *buf, rt_size_t size, rt_int32_t timeout) { rt_size_t read_idx = 0; rt_err_t result = RT_EOK; char ch; RT_ASSERT(buf); if (client == RT_NULL) { LOG_E("input AT Client object is NULL, please create or get AT Client object!"); return 0; } while (1) { if (read_idx < size) { result = at_client_getchar(client, &ch, timeout); if (result != RT_EOK) { LOG_E("AT Client receive failed, uart device get data error(%d)", result); return 0; } buf[read_idx++] = ch; } else { break; } } #ifdef AT_PRINT_RAW_CMD at_print_raw_cmd("urc_recv", buf, size); #endif return read_idx; } ``` 你这一个字节一个字节获取,得多占用时间啊。而且一旦读取过程中有一个字节没获取到就返回 0 ,很有问题。 我的优化方案: ```C rt_size_t at_client_obj_recv(at_client_t client, char *buf, rt_size_t size, rt_int32_t timeout) { rt_size_t len = 0; RT_ASSERT(buf); if (client == RT_NULL) { LOG_E("input AT Client object is NULL, please create or get AT Client object!"); return 0; } while(1) { rt_sem_control(client->rx_notice, RT_IPC_CMD_RESET, RT_NULL); rt_size_t read_len = rt_device_read(client->device, 0, buf + len, size); if(read_len > 0) { len += read_len; size -= read_len; if(size == 0) break; continue; } if(rt_sem_take(client->rx_notice, rt_tick_from_millisecond(timeout)) != RT_EOK) break; } #ifdef AT_PRINT_RAW_CMD at_print_raw_cmd("urc_recv", buf, len); #endif return len; } ```
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
Cfly
这家伙很懒,什么也没写!
文章
14
回答
24
被采纳
3
关注TA
发私信
相关文章
1
rt-thread 2g/3g/4g通信模块的教程有吗?
2
基于AT指令,用esp8266如何连接mqtt?
3
AT组件使用问题
4
官方AT客户端应用笔记的几个小tip
5
RTT的SAL能够判断使用LWIP或者AT?
6
rt_therad AT组件移植不成功(结贴)
7
AT组件在哪个版本的?
8
AT组件 连接 Onenet 连接失败
9
esp8266 AT指令 MQTT连接问题
10
AT组件使用问题之模块主动上报【已解决】
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部