C++串口读取问题: does ioctl(FIONREAD) set a wrong value?

标签 c++ unix serial-port ioctl

我遇到了一个非常奇怪的问题,但我无法解决。我想使用 C++ 在 Mac Os X 上读取(仅读取)微 Controller 通过 USB 作为串行端口(FTDI)收集和发送的数据。一个完整数据序列的大小始终恰好是 10 个字节。但是我使用以下代码来读取数据:

导入的库:

#include <iostream>
#include <fstream>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>

代码:

void init(){
    serial = open(port.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); // 0_RDONLY ?
    struct termios options;
    //set opt to 115200-8n1
    cfsetspeed(&options, B115200);
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    tcsetattr(serial, TCSANOW, &options);
    if (serial < 0){
        //Error
    }else{
        //run loop
    }
}

void serial_loop(){
    long bytes_read;
    int bytes_available;
    unsigned char msg[10];
    while(1){
        do{
            usleep(1000);
            ioctl(serial, FIONREAD, &bytes_available);

        }while(bytes_available < 10); //wait for the sequence to complete

        bytes_read = read(serial, msg, 10);

        //do some parsing here
    }
}

该代码几天前有效,但现在不再有效。根据终端 -> screen 命令,数据完美到达计算机。我检查了端口文件名,它仍然正确,并且端口也已成功打开。 我将问题范围缩小到 ioctl 命令 FIONREAD ,它没有将正确的数字写入 bytes_available-var (不再)。 它确实有效,而且我相信,我没有更改代码中的任何内容。

您是否发现任何可能导致此问题的问题? 我的代码中有危险的段落吗? 谢谢你的帮助,我真的被困在这里了......

编辑: 感谢反馈,我能够让它再次运行。这是当前代码:

int serial;
void init(){
    serial = open(port.c_str(), O_RDWR | O_NOCTTY); //removed 0_NONBLOCK
    struct termios options;
    //set opt to 115200-8n1
    cfsetspeed(&options, B115200);
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //Non-canonical
    options.c_cc[VMIN]     = 1; //block read until at least 1 byte was recieved
    options.c_lflag = 0;

    tcsetattr(serial, TCSANOW, &options);
    if (serial < 0){
        //Error
    }else{
        //run loop
    }
}

void serial_loop(){
    int datalength = 10;
    long bytes_read = 0;
    int bytes_in_msg = 0;
    unsigned char buf[datalength];
    unsigned char msg[datalength];
    do{
        bytes_read = read(serial, buf, datalength-bytes_in_msg);
        usleep(1000);
        if (bytes_read>0){
            memcpy(&msg[bytes_in_msg], &buf, bytes_read);
        }
        bytes_in_msg += bytes_read;
    }while(bytes_in_msg < datalength);

    //do some parsing here
    }
}

这可行,但是还有什么可能有问题的吗?

感谢您的支持!

最佳答案

This code worked a few days ago but now it isn't anymore.

变化无常的程序行为通常表明初始化不正确或不完整。
您的 termios 初始化仅配置波特率和字符帧,其他一切都由机会决定。
请参阅Setting Terminal Modes ProperlySerial Programming Guide for POSIX Operating Systems .


您修改后的代码仍然没有正确解决此问题。
该代码永远不会通过调用 tcgetattr() 函数来初始化 termios 结构 options
有关示例代码,请参阅我对 How to open, read, and write from serial port in C? 的回答


options.c_lflag = 0;

这不被认为是分配 termios 元素的正确方法。


options.c_cc[VMIN]     = 1;

非规范模式需要定义 VMIN 和 VTIME 条目。
您的代码使用 VTIME 位置处存在的任何垃圾值。
请参阅Linux Blocking vs. non Blocking Serial Read .


FIONREAD which doesn't write the correct number to the bytes_available-var (anymore).

负面描述,即没有发生的事情,不如对发生的事情的描述那么有帮助或具体。
那么你会得到什么样的值呢?
为什么你认为这是“错误”?

更重要的是,您为什么不检查每个系统调用的返回值,尤其是您认为给您带来问题的这个 ioctl()

很可能是 ioctl() 失败,没有更新您的 bytes_available 变量,并返回了错误代码。
您的代码不是首先检查是否有良好的返回,而是无条件地使用返回的参数。


批评您的代码的另一个答案具有误导性。可以禁用流量控制。您的代码已损坏,因为它没有进行正确的初始化,也没有检查错误返回,而不是因为通信链接“死锁”


在修改后的代码中:

    bytes_read = read(serial, buf, datalength-bytes_in_msg);
    usleep(1000);

阻塞读取之前和/或之后的 sleep 或延迟是多余的。

关于C++串口读取问题: does ioctl(FIONREAD) set a wrong value?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39229361/

相关文章:

c++ - std::vector 初始化类成员

java - 如何将字符串转换为十六进制和将十六进制转换为字符串?

c++ - 声明多维数组时出现堆栈溢出异常

c++ - std::function 无法推断模板实例中的重载类型

perl - 使用awk或cut或perl选择特定的列

c - 我不知道C中的 'glibc detected'

linux - 在远程使用 ssh 命令列出选定文件时需要帮助

c - 可靠地以56K逐字节读取linux中的串行数据

python - 如何将变量从 NodeJs 插入到 python 脚本中?

c++ - 提升 : having an array of ints and some special int how to find nearest to yours in array?