【问题标题】:Serial communication crash串行通信崩溃
【发布时间】:2016-07-20 11:03:50
【问题描述】:

我正在使用无线电模块 XBee pro 并记录了一些无线电数据。

我使用 FTDI 串行转 USB 转换器,因此模块出现在 /dev/ttyUSB0 下。

我已经写了这段代码:

void TsToCoord::serialConfig()
{
    // Open Serial Port
    cout << "Opening serial port..." << endl;
    fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);

    if (fd < 0 )
    {
        cout << "Error " << errno << " opening /dev/ttyUSB0: " << strerror(errno) << endl;
    }
    else
    {
        //Configure Serial Port
        cout << "Configuring serial port..." << endl;
        struct termios tty;
        memset (&tty, 0, sizeof tty);

        if (tcgetattr (fd, &tty) != 0)
        {
            cout << "Error " << errno << " from tcgetattr: " << strerror (errno) << endl;
        }

        cfsetispeed(&tty, B57600);
        cfsetospeed(&tty, B57600);

        tty.c_cflag &= ~PARENB;
        tty.c_cflag &= ~CSTOPB;
        tty.c_cflag &= ~CSIZE;
        tty.c_cflag |= CS8;
        tty.c_cflag &= ~CRTSCTS;
        tty.c_lflag = 0;
        tty.c_oflag = 0;
        tty.c_cc[VMIN] = 1;
        tty.c_cc[VTIME] = 50;

        tty.c_cflag |= CREAD | CLOCAL;

        cfmakeraw(&tty);

        tcflush(fd, TCIFLUSH);

        if (tcsetattr(fd, TCSANOW, &tty) != 0) 
        {
            cout << "Error " << errno << " from tcsetattr" << endl;
        }
    }
}


void TsToCoord::listenPort()
{
    // Creation of a buffer to store data from radio module
    fill_n(buff, 2048, '\0');
    this-> ind = 0;

    while(true)
    {
        char mes[1024];
        fill_n(mes, 1024, '0');
        //cout << "Blocking read" << endl;
        int rd = read(fd, &mes, sizeof(mes));

        if (rd > 0)
        {
            //cout << "Storing in buffer" << endl;
            storeInBuff(mes, rd);
            fill_n(mes, 1024, '0');

            struct pollfd fds;
            fds.fd = fd;
            fds.events = POLLIN | POLLPRI;
            int slct = 1;

/*
            int slct = 1;
            fd_set rdfds;
            FD_ZERO(&rdfds);
            FD_SET(fd, &rdfds);
            struct timeval to;
            to.tv_sec = 0;
            to.tv_usec = 100000;
*/
            //fd_set rdfdsCopy = rdfds;
            //cout << "Entering second while loop" << endl;
            while (slct > 0)
            {
                //cout << "Call to select" << endl;
                //slct = select((fd+1), &rdfdsCopy, NULL, NULL, &to);
                slct = poll(&fds, 1, 100);
                if (slct > 0)
                {
                    //cout << "Next call to read, would not block" << endl;
                    rd = read(fd, &mes, sizeof(mes));
                    storeInBuff(mes, rd);
                    //rdfdsCopy = rdfds;
                }
            }
            findFrame(0);
            ind = 0;
            fill_n(buff, 2048, '\0');
        }
    }
}

我的问题是,当它启动时,它运行良好。但在 20 分钟后,它不再工作了。 CPU 使用率达到 100%,因此读取调用似乎不再阻塞。就像文件描述符不再链接到设备一样......

由于我完全不知道原因和错误,并且由于在崩溃之前需要随机的时间,我不能只是取消它并在我的终端中查看输出...

所以我想问一下:

  • 是不是代码中没有发现大错误。
  • 导致它崩溃的原因是什么?我想到了另一个尝试使用同一设备的软件,但似乎并非如此。我也不认为是波特率问题。

我添加了一个检查无线电被拔掉的情况,所以程序不能退出它自己的。我很确定这不是问题,因为模块在崩溃发生后一直处于 /dev/ttyUSB0 之下。

我使用 Debian 3.2.57-3 i686。

在我的无线电模块中使用其他软件时,我没有遇到任何问题。

我在另一台类似的计算机上使用此代码似乎没有问题...

感谢您的阅读,抱歉英语不太好。

编辑:更准确地说我想从这篇文章和这个程序中得到什么: 在某些时候,程序无法阻止读取,并且每次对读取的调用都不会阻塞并且不会读取任何内容,因此程序不会执行它创建的操作:记录来自无线电模块的数据。我只是想避免它,因为没有它它可以很好地工作,并且可能会对硬件造成伤害。

【问题讨论】:

  • @Olaf 就像我说的那样,程序在某些时候无法阻止读取,并且每个对读取的调用都不会阻塞并且不读取任何内容,因此程序不会执行它创建的操作for :记录来自无线电模块的数据。我只是想避免它,因为没有它它可以很好地工作,并且可能会对硬件造成伤害。
  • @Kyll:OP 没有表现出提供所需的东西。所以他至少可以自己找到链接。 (无论如何,链接都会与关闭消息一起显示;我根本不需要发表评论(对于这个问题,这很明显),所以请把它当作礼貌,不要告诉我我应该做什么与否!
  • @Kyll 谢谢。我剪掉了代码,所以只出现了与串行相关的东西。我一直认为其他地方可能还有其他明显的错误,所以我把所有的代码都放了。由于我没有发现有这个问题的人(一开始工作然后随机崩溃),我认为其中有一个更奇特的错误。我发帖只是为了测试不好。
  • @rmilville 感谢您的编辑和关注!我撤回了我的近距离投票。希望您能找到解决问题的方法。解决后,请务必再次编辑您的帖子,以最大限度地提高其对未来读者的可见度和实用性(甚至发布自我回答,描述您如何解决此问题)。
  • 一个正常工作的数字计算机系统非常很少发生随机崩溃。

标签: c++ linux serial-port embedded


【解决方案1】:

快速查看您的代码 - 如果您在读取时遇到 EOF 或错误(即 read() 返回零或 -1),您将永远循环。我可以看到您处于原始模式,但我在 FTDI 驱动程序和固件中看到了可能导致这种情况发生的各种错误,这不是您正在处理的情况。

【讨论】:

  • 谢谢。我将添加一个关于 read 返回的测试。问题是如果 read 返回 0 或 -1,为什么所有下一个调用也会返回 0 或 -1?由于我希望这个东西作为守护程序运行,如果每次读取调用都使所有其他调用失败,我将不得不重新启动守护程序。问题是我有时必须每 5 秒记录一次数据,每 30 分钟重启一次是不可接受的,因为重启时间很长。固件/ftdi 驱动程序会导致这么多错误吗?
  • 一旦你得到 0 或 -1,这可能就是你将继续得到的。一旦你得到 EOF,就不会有新的数据到达。当出现错误时,它不会消失。你需要弄清楚发生了什么并解决这个问题。在您的代码中,您可能能够关闭并重新打开设备。另外 -- 重启慢的没有充分的理由,应该是毫秒。
  • 我就是这样做的,关闭fd,重新打开设备对应的文件。好吧,对于重新启动,如果我用 kill command et restart 杀死并用“service ----- start”启动它会很快,但是用“service ---- restart”它会慢得要命。由于我添加了一个测试,我希望我不需要重新启动守护进程。
  • 这里有多个问题。当出现问题时,您的代码会进入循环;在这种情况下,它不会关闭 fd。这是您的代码中的一个错误。一些 FTDI 设备不能正确处理 ~CRTSCTS;可能是读取被阻塞;设备驱动程序错误。您可以通过更换电缆将 RTS 连接到 CTS 并连接 DTR、DSR 和 CD 来进行测试,然后查看是否仍有问题。当设备驱动程序问题未返回时,kill 上的“永远采取”是一致的。
  • 对不起,我没有正确解释自己。当我说我添加了一个针对 EOF 或错误的测试时,那不是在帖子中而是在我的计算机上再次测试。如果一切正常,我会说的。我对rs232连接不太了解,所以我会搜索你指向我的东西谢谢。
【解决方案2】:

所以我遵循了@janm 的提示。我已经删除了这一行:

tty.c_cflag &= ~CRTSCTS;

做了一个这样的测试:

rd = read(fd, &mes, sizeof(mes));
if (rd > 0)
{
     doSomeStuff();
}
else
{
     close(fd);
     serialConfig();
     listenPort();
 }

也许当读取失败时我会丢失一些数据,但至少程序不能关闭并且不必手动重新启动。

【讨论】:

  • 你需要找到根本原因,这意味着你需要检查rd &lt; 0,然后报告errno的值。 E,G 见stackoverflow.com/questions/6947413/… 我看不出删除tty.c_cflag &amp;= ~CRTSCTS 可以如何改进/修复任何事情。 FWIW 我有几个 FTDI 适配器。
猜你喜欢
  • 2017-11-29
  • 1970-01-01
  • 2021-06-29
  • 1970-01-01
  • 2020-06-17
  • 2013-08-02
  • 1970-01-01
  • 2014-08-24
  • 2016-04-19
相关资源
最近更新 更多