写在前面
自 serialX 诞生,至今一年整,笔者竟没有测试过 stdio 和 termios 。因为这部分在 v1 时已经做的很完美了。
上一篇文章,笔者使用 serialX 驱动移植了 freemodbus 并做了简单测试。然后想进一步测试一下 libmodbus ,libmodbus 的使用是要比 freemodbus 复杂很多的。笔者原想着直接添加 libmodbus 样例程序跑起来看看有什么问题,然后发现困难重重,于是退而求其次,先测试 serialX 的 posix 接口。
测试环境
开发板: NK-980IOT V1.0 的开发板
rt-thread 版本:4.1.1
IDE:keil + env
启用 posix
首先,启用 DFS:”RT-Thread Components” -> “DFS: device virtual file system” 。进入子菜单,选择
“Using posix-like functions, open/read/write/close”
“ Using devfs for device objects”
其它项可以取消选择。
然后进入 “RT-Thread Components” -> “C/C++ and POSIX layer” -> “POSIX (Portable Operating System Interface) layer” 子菜单项,选择
“Enable POSIX file system and I/O”
“Enable I/O Multiplexing select() “
“Enable Terminal I/O “
其它项可以取消选择。
测试
我们继续使用 rt-thread 驱动篇 之 serialX 全网公测 提供的测试方案,但是把里面的读写 API 改一改,rt_device_open 改成 open,rt_device_read 改成 read,rt_device_write 改成 write,rt_device_close 改成 close。
我们知道, open/read/write/close 分别对应调用 dfs_file_(open/read/write/close) 进而调用 struct dfs_file_ops 结构体中定义的 open/read/write/close 接口。在串口驱动框架里就是 serial_fops_(open/read/write/close) 等几个函数。
serial_fops_open
需要说明的是,我们只能选择“中断”或者“DMA”中的一种模式了。另外,除了 O_RDONLY O_WRONLY O_RDWR 三种读写标志,还可以支持 O_NONBLOCK ,它等于 RT_DEVICE_OFLAG_NONBLOCKING。
serial_fops_read
原来的实现有如下一个 while 循环,这个循环的本意是:非阻塞模式下,如果没有 read 到数据返回 -EAGAIN 错误值,告知应用层无数据并可以再次读;阻塞模式下,如果没有 read 到数据将等待工作队列而挂起线程。
do
{
size = rt_device_read(device, -1, buf, count);
if (size <= 0)
{
if (fd->flags & O_NONBLOCK)
{
size = -EAGAIN;
break;
}
rt_wqueue_wait(&(device->wait_queue), 0, RT_WAITING_FOREVER);
}
}while (size <= 0);
这和原来 serialX 的阻塞模式概念是一致的,如此一来,我们发现阻塞模式时 rt_device_read 先阻塞了,并不会走到 if 条件语句块内。
flush 概念
大家一定知道,flush 支持是 serialX 独有的,v1 v2 没有这个。当我们开启 posix 之后,发现 dfs 实现了一个函数 fsync ,同时还有一个 dfs_file_flush 函数,以及 struct dfs_file_ops 也定义了 flush 接口。只是在之前的版本里这个都没有实现。于是,我们对 “serialX.c” 做如下修改
找到 const static struct dfs_file_ops _serial_fops = 变量定义代码行,将 RT_NULL, /* flush / 修改为 serial_fops_flush, / flush */ 。然后在上面添加 serial_fops_flush 函数实现:
static int serial_fops_flush(struct dfs_fd *fd)
{
rt_device_t device;
device = (rt_device_t)fd->data;
return rt_device_flush(device);
}
瞧,serialX 的 flush 和 dfs 的 flush 以及 posix 的 fsync 衔接起来了。
select io 复用
之前设计的测试方案里,只有回环测试改动比较大。这里我们使用 select 这个高级的用法,监听是否有数据。
用这种方式,我们可以同时监听多个串口设备了。或者说,一个线程“同时”读多个串口设备。
termios
开启了 posix ,串口设备修改波特率、数据位等需要使用 termios。这部分的问题留待下一篇 libmodbus 部分详说。
总结
启用了 posix 后我们发现,posix 是在原来的设备驱动框架基础上套的一层壳。增加了函数调用跳转次数。如果没有必要的理由,还是不启用 posix 了。
原作者:出出啊
更多回帖