【问题标题】:using termios - Cannot set parity to even, get EINVAL error使用 termios - 无法将奇偶校验设置为偶数,出现 EINVAL 错误
【发布时间】:2021-11-17 02:02:07
【问题描述】:

总结:

我目前正在使用 termios 在嵌入式 Linux 上开发一个程序。如果我不启用偶校验,我的程序可以正常工作。当我将 PARENB 设置为活动且 PARODD 为非活动时,我开始遇到问题。我的程序设计为 115200 波特的 8E1。

发生的情况是,当我第一次在启用偶校验的全新启动时运行该程序时,它会发送一条消息。发送的消息确实发送,但它不发送奇偶校验位。我第二次运行该程序时,它在 tcsetattr 函数处失败,并带有 errno == EINVAL。

我在树莓派上运行这个程序进行调试,然后将程序移植到yocto环境中。

当前环境:

树莓派:4B Debian 版本:10.10 GCC:(Raspbian 8.3.0-6+rpi1)8.3.0。

我的问题:

有没有人知道丢失了什么?我自己尝试过这样做,并尝试了我在 GitHub 上找到的 2 个人的在线示例。他们都有这个问题。

我正在运行的代码是:

// C library headers
#include <stdio.h>
#include <string.h>

// Linux headers
#include <errno.h>  // Error integer and strerror() function
#include <fcntl.h>  // Contains file controls like O_RDWR
#include <stdlib.h>
#include <sys/types.h>
#include <termios.h>  // Contains POSIX terminal control definitions
#include <unistd.h>   // write(), read(), close()

#define SERIAL_DEVICE "/dev/ttyS0"

int main() {
    struct termios serial_port_settings;
    int fd;
    int retval;
    char buf[] = "hello world \n bye\n";
    char ch;
    int i;

    //SERAIL_DEVICE is "/dev/ttyS0"
    fd = open(SERIAL_DEVICE, O_RDWR);
    if (fd < 0) {
        perror("Failed to open SERIAL_DEVICE");
        exit(1);
    }

    retval = tcgetattr(fd, &serial_port_settings);
    if (retval < 0) {
        perror("Failed to get termios structure");
        exit(2);
    }

    //setting baud rate to B115200
    retval = cfsetospeed(&serial_port_settings, B115200);
    if (retval < 0) {
        perror("Failed to set 115200 output baud rate");
        exit(3);
    }
    retval = cfsetispeed(&serial_port_settings, B115200);
    if (retval < 0) {
        perror("Failed to set 115200 input baud rate");
        exit(4);
    }

    //parity and bytes, grabbed from documentation
    serial_port_settings.c_cflag |= PARENB;   //enable parity
    serial_port_settings.c_cflag &= ~PARODD;  //disable odd parity, therefore-> even parity
    serial_port_settings.c_cflag &= ~CSTOPB; //disable 2 stop bits, therefore-> 1 stop bit
    serial_port_settings.c_cflag &= ~CSIZE;  //remove size
    serial_port_settings.c_cflag |= CS8;     //8 data bits
    serial_port_settings.c_cflag |= CLOCAL | CREAD;  //ignore modem control lines, enable reciever
    serial_port_settings.c_lflag |= ICANON; // enable canonical mode

    
    retval = tcsetattr(fd, TCSANOW, &serial_port_settings);
    /*************** ERROR HAPPENS HERE ********************/
    /* errno is set to EINVAL here */
    
    if (retval < 0) {
        perror("Failed to set serial attributes");
        exit(5);
    }
    printf("Successfully set the baud rate\n");

    retval = write(fd, buf, 18);
    if (retval < 0) {
        perror("write on SERIAL_DEVICE failed");
        exit(6);
    }

    retval = tcdrain(fd);
    if (retval < 0) {
        perror("write on SERIAL_DEVICE failed");
        exit(6);
    }

    close(fd);
    return 0;
}

【问题讨论】:

  • 只看手册页就知道ICANONc_cflag 而不是c_lflag
  • @jiveturkey 很好。我在第二次尝试中确实解决了这个问题,但忘记在这个上修复它。我刚刚用那个编辑再次尝试了我的程序。问题仍然存在。我已经编辑了我的问题来解决这个问题。
  • ICANON 在 c_lflag 成员中。你本来是对的,现在是错的。在盲目跟随 cmets 之前,请自己阅读手册页。 FWIW 我添加了必要的#include 语句,编译了您的代码,并且没有遇到错误。
  • 建议您在帖子中添加此嵌入式 Linux 板和工具链的详细信息。重新测试了修改后的版本,同样成功执行。这是在 x86 笔记本电脑上。我确实有各种各样的 SBC 要测试,但没有 RPi 或 Broadcom SoC。
  • Raspberry pi: 4B 至少在 RPI3 上有两个 UART 驱动程序,一个完整的用于蓝牙,另一个是一个非常有限的迷你 UART 驱动程序。很可能您正在使用那个迷你 UART,它不支持任何模式。我明白了,rpi 文档发生了变化,记录在这里:raspberrypi.org/documentation/computers/…

标签: c linux termios


【解决方案1】:

@sawdust 和 @KamilCuk 帮助确定了我的问题。软件不是问题。看起来 Raspberry Pi 4 上的 ttyS0 不是功能齐全的 COM 端口。因此,尝试添加奇偶校验位会失败。

上面的代码在另一台具有全功能 COM 端口的 Linux 机器上运行良好。

【讨论】:

    猜你喜欢
    • 2012-01-22
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    • 2012-12-06
    • 2011-01-13
    • 1970-01-01
    • 2020-04-20
    • 2013-06-25
    相关资源
    最近更新 更多