嵌入式技术论坛
直播中

张强

7年用户 1366经验值
私信 关注
[经验]

测试serialX的posix支持详解

写在前面
自 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 了。

原作者:出出啊

更多回帖

发帖
×
20
完善资料,
赚取积分