此次本人重新使用了 AT 组件,阅读了其源代码,并深入阅读了 at_socket 及 at_device 的源代码,恶痛绝,特此写下该系列的吐槽文章。
首先我先展示下我的最终效果,我使用的 MCU为GD32,模组为EC600S-CN。
我将每个插座都作为一个设备:
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 />
编程方法如下:
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.
");
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!
");
goto _tcp_pass_start;
使用 posix 操作每个 socket 进行。
最终测试结果:
使用 4 个 socket 连接服务器,这里我使用了内网接口。
通过服务器给 4 个 socket 发送 1000K 的数据。
1.at_client 的 end sign
设置 end sign 就是需要到结束符的时候通知应用啊,at_client 中检测到 end sign 作为一行,然后就不是一个通知,怎么用?
我们看下 at_device 中对于它的使用:
模组中间突然给你上报URC,你也满足条件了,就开始发送,结果就是出结果问题。
我的改进方案:
增加结束符号的通知。
2.at_client_obj_recv的问题
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,很有问题。
我的优化方案:
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;
}
原作者:飞蝇
|