读取串口块不明原因

我正试图在Linux下使用termios框架来通过UART(usbserial)接口非接触式智能卡读卡器。 这个代码可以在PC上正常工作,但是当我在ARM9目标上交叉编译并试用时,它能够打开设备甚至将命令写入设备,但是读取命令无限期地被阻塞。 这里是代码片段:

int mifare_rdr_init(struct mifare_1K * ptr, char *rdr_devnode) { bzero(ptr, sizeof(struct mifare_1K)); // zero the entire structure // open serial device int fd = open(rdr_devnode, O_RDWR|O_NOCTTY ); if (fd == -1) { perror("Failed to open serial device "); return 1; } ptr->serialfd = fd; // save file descriptor ptr->serialdev.c_iflag = 0; // no i/p flags ptr->serialdev.c_oflag = 0; // o/p flags ptr->serialdev.c_cflag = ( CS8 | CREAD | B38400 ); // 8 bits, receive enable, baud for rdr ptr->serialdev.c_lflag = ( ICANON ); // CANONICAL mode, means read till newline char '\n'. // control chars // commented below line as suggested by AH below, since it's not needed in CANONICAL mode // ptr->serialdev.c_cc[VMIN] = 1; // read unblocks only after at least one received char. // flush all i/o garbage data if present tcflush(ptr->serialfd,TCIOFLUSH); int ret = 0; // apply settings ret = tcsetattr(ptr->serialfd,TCSANOW,&ptr->serialdev); if (ret == -1) { perror("tcsetattr() failed "); return 2; } return 0; } int get_mifare_rdr_version(struct mifare_1K *ptr, char *data) { // flush all i/o garbage data if present tcflush(ptr->serialfd,TCIOFLUSH); int chars_written = write(ptr->serialfd,"$1V\n",4); if( chars_written < 0 ) { perror("Failed to write serial device "); return 1; } printf("cmd sent, read version...\n"); // this prints, so I know cmd sent... int chars_read = read(ptr->serialfd,ptr->data_buf,14); if( chars_read < 0 ) { perror("Failed to read serial device "); return 2; } // copy data to user buffer printf("reading done.\n"); // this doesn't print... return 0; } 

mifare_1K结构包含串行设备,termios结构和我正在使用的各种缓冲区的文件描述符。 我提到的设备是usb-to-serial(模块:ftdi_sio)设备。 它在termios的典型模式下configuration为38400 @ 8-N-1。

标准模式是因为读取器的响应以'\ n'结尾,所以它在Canonical模式下处理得更好,因为它读取设备直到收到'\ n'(如果我错了,请纠正我)。

首先我调用init()fn,然后调用get_rdr_version()。 string“cmd sent,read version …”被打印出来,所以我知道它能写,但是不打印string“阅读完成”。 之后。

另一件事是,如果我删除读卡器,并将该端口连接到另一台PC上的gtkterm(串行端口terminal程序),我没有收到该gtkterm ??上的“$ 1V \ n”! 。 然后经过一个小小的RnD,我发现如果我重新启动阅读器连接的阅读器的系统,那么只有我得到了另一个Gtkterm的cmd“$ 1V \ n”。 如果我再次尝试而没有重新启动,那个cmd在那个Gkterm上是看不到的…一个线索,但是还是想通了。

是不是像cmd写入设备文件,但没有耗尽实际设备? 有什么办法可以解决这个问题吗?

任何帮助,深深的赞赏,因为我一直卡在这一段时间现在…. thnks。

更新:

好吧,我已经通过修改代码稍微有点了,如下所示。

 // open serial device int fd = open(rdr_devnode, O_RDWR|O_NOCTTY|O_NDELAY ); // O_NDELAY ignores the status of DCD line, all read/write calls after this will be non-blocking fcntl(fd,F_SETFL,0); // restore read/write blocking behavior if (fd == -1) { perror("Failed to open serial device "); return 1; } 

这是在我的init()函数中打开端口的代码的修改部分。 两个变化:

1)O_NDELAY被添加到open()调用中的标志中,忽略数据载体检测(DCD)行来查看另一端是否已连接并准备好进行通信。 这是最初用于调制解调器,我不需要,事实上,我没有它,因为我使用usbserial。 但是这个标志还会进一步调用read()和write()作为非阻塞。 注意,我曾经认为这将通过添加CLOCAL到termios结构的cflag来处理,我试过但没有工作。

2)fcntl(fd,F_SETFL,0)恢复进一步read()和write()调用的阻塞行为。

这个组合对我来说是完美的。 我不发表这个答案的唯一原因是,我不明白为什么它没有这个修改,因为它是相同的硬件在PC上的工作。 实际上,我可以使用minicom从ARM9目标智能卡阅读器中读取数据,但不能读取我的程序。 我将检查FT232BL文档,以查看默认情况下DCD的状态是什么。

无论如何,我在串行编程指南POSIX操作系统上find了这一点信息。 解释任何人? 当然,当我find答案的时候,我会发布答案。

干杯:)

Solutions Collecting From Web of "读取串口块不明原因"

使用Telegesis USB模块在Raspberry Pi上刚刚遇到同样的症状,我将其添加为另一个数据点。

在我的情况下,原因竟然是一个丢失的RTS标志。 Telegesis期望CRTSCTS流量控制,并且不会在没有看到RTS的情况下向Raspberry发送任何数据。 这里令人困惑的是a)相同的代码在PC上工作得很好,b)Telegesis第一次插入时,它在树莓上工作的很好,但是在随后的/ dev / ttyUSB0打开时,没有数据可见由树莓。

出于某种原因,似乎在ARM上,RTS标志在设备关闭时被清除,但不会再被设置,而在x86 / x64上,RTS标志保持设置。 这里的解决方法是简单地设置RTS标志,如果它不是已经 – 例如

 #include <sys/ioctl.h> //... int rtscts = 0; if (ioctl (fd, TIOCMGET, &rtscts) != 0) { // handle error } else if (!(rtscts & TIOCM_RTS)) { rtscts |= TIOCM_RTS; if (ioctl (fd, TIOCMSET, &rtscts) != 0) { // handle error } } 

我注意到,在你的情况下,你不使用流量控制,所以上述可能不适用。 这是你的问题,并提到minicom的工作,导致我们发现解决我们的问题,但是 – 所以谢谢你!

你可能会检查三件事情:

规范模式/非规范模式混合1

你正在混合规范模式和非规范模式的东西:

 ptr->serialdev.c_lflag = ( ICANON ); // ... ptr->serialdev.c_cc[VMIN] = 1; 

termios(3)页介绍了有关VMIN的内容:

VMIN非标准读取的最小字符数。

所以显然你的超时时间不会像你想象的那样工作。

规范模式/非规范模式混合2

另外在下面进一步说明:

这些符号下标值都是不同的,除了VTIME, VMIN 可以分别具有与VEOL, VEOF相同的值。 在非规范模式下,特殊字符含义被超时含义所取代。 有关VMIN和VTIME的说明,请参阅下面的非规范模式的说明。

所以请检查这两个平台的定义是否不同。 可能是,EOL / EOF逻辑可能被错误的设置所破坏。 EOL和EOF都会导致read返回。

非初始化的c_cc

您的代码不显示正确的初始化c_cc数组。 您既不读取现有的设置,也不提供适用于规范模式所需值的默认值。 到目前为止显示的代码甚至没有清除这些值。 因此可能会使用不可预知的值。