在Linux上记录RS232数据而无需等待换行符

5
我正在尝试使用cat将RS232数据记录到文件中:
cat /dev/ttyS0 > rs232.log

结果是我的文件中所有的内容都有,除了最后一行。

通过将输出打印到标准输出,我发现只有在输出包含换行符 ('\n') 时,cat 才会将其写入。我也用以下方法得到了相同的结论:

dd bs=1 if=/dev/ttyS0 of=rs232.log

阅读完 如何在Perl中立即打印文本而不等待换行 后,我开始思考这可能是 Linux 内核或 coreutils 包的缓冲问题。
根据 TJD 的评论,我用 C 写了自己的程序,但仍然遇到相同的问题:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* args[])
{
    char buffer;
    FILE* serial;
    serial = fopen(args[1],"r");
    while(1)
    {
        buffer = fgetc(serial);
        printf("%c",buffer);
    }
}

根据我的 C 代码结果,这似乎是与 Linux 内核相关的问题。

也许这会有所帮助,“Perl禁用输入缓冲区”:使用sysread - aqn
@aqn:我必须承认,我并不完全理解perl的用途以及它如何帮助我解决这个问题。我并没有真正理解你链接中的主题,所以我尝试了那篇文章中给出的命令,但是它们并没有起作用。此外,我也不知道每个需要使用这个命令的系统是否都安装了perl解释器。 - FSMaxB
你绝对可以用C或Python编写自己的5行程序来读取端口并立即刷新打印。 - TJD
啊!注释中不允许格式!我会在回复中放置我的答案... - aqn
在您的C程序中,使用open()、read()和write()代替fopen()、fgetc()和printf(),因为后者会缓冲输入和输出,并且在输入中没有换行符时无法正常工作。 - aqn
@aqn:所提到的缓冲不是在C标准I/O库中处理的,而是在内核tty驱动程序中处理的。 - Ben Voigt
2个回答

7
你正在打开一个TTY。当TTY处于cooked(也称为规范)模式时,它执行行处理(例如,退格会从缓冲区中删除前一个字符)。你需要将TTY切换到raw模式,以便在每个字节到达时都能接收到,而不是等待行结束。
来自man页面

规范模式和非规范模式

在c_lflag中设置ICANON规范标志决定终端是在规范模式(已设置ICANON)还是非规范模式(未设置ICANON)下运行。默认情况下,ICANON已设置。

在规范模式下:

  • 输入逐行提供。当输入行结束符之一(NL、EOL、EOL2;或在行首的EOF)被键入时,输入行可用。除EOF外,行结束符包含在read(2)返回的缓冲区中。

  • 启用行编辑(ERASE、KILL;如果设置了IEXTEN标志:WERASE、REPRINT、LNEXT)。read(2)最多返回一行输入;如果read(2)请求的字节数少于当前行输入中可用的字节数,则只读取请求的字节数,其余字符将保留供将来的read(2)使用。

在非规范模式下,输入立即可用(无需用户键入行结束符),并且禁用行编辑。

最简单的方法就是调用cfmakeraw函数。

2
感谢您的提示,运行“stty -F /dev/ttyS0 raw”后一切都按预期工作。 - FSMaxB

0

这个可以工作吗?

perl -e 'open(IN, "/dev/ttyS0") || die; while (sysread(IN, $c, 1)) { print "$c" }'

这个是有效的:

$ echo -n ccc|perl -e 'while (sysread(STDIN, $c, 1)) { print "$c" } '
ccc$

第一个与cat和dd有相同的问题,第二个在没有完成任何可见操作的情况下结束。 - FSMaxB
我必须纠正自己,第二个命令确实有效,但是一开始我没有看到我的提示行前面的ccc。使用echo进行串口通信确实有效,但似乎会自动发送“\n”。 - FSMaxB
如果第二个命令没有执行任何操作而结束(应该输出“ccc”,不带换行符,如图所示),那么可能是因为您的系统上的“echo -n”有所不同。当您执行“echo -n ccc”时,是否会得到“ccc”,而不带换行符?此外,您的shell命令提示符的显示可能会破坏“ccc<无换行符>”的输出。当您执行相同的命令但通过“od -c”进行管道传输时,您看到了什么? - aqn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接