stty 串行端口奇偶校验设置不持久

Lui*_*Day 2 linux serial-port parity stty 9-bit-serial

我有一个 netcore 应用程序,它打开串行端口,并在检测到奇偶校验错误后在控制台上写入“奇偶校验错误”。它在 Windows 10 中工作正常,但无法在 Linux 下工作。

我的假设是操作系统没有将奇偶校验错误传递给 netcore。

为了检查端口设置,我运行:

stty -D /dev/ttyS0 -ignpar inpck
Run Code Online (Sandbox Code Playgroud)

然后我跑:

stty -D /dev/ttyS0 -a 
Run Code Online (Sandbox Code Playgroud)

并且设置似乎已按预期正确设置(-ignpar inpck)。

然后我运行我的 netcore 3 应用程序,但未检测到奇偶校验错误。

所以我跑

stty -D /dev/ttyS0 -a 
Run Code Online (Sandbox Code Playgroud)

用于验证设置,但这些似乎已重置(-ignpar -inpck)

如何强制我的应用程序在启用 inpck 属性的情况下运行?
有没有办法让inpck默认启用?

谢谢。

更新:netcore 3 应用程序奇偶校验错误检测在 Windows 10 中工作正常,但在 Linux 下不起作用。我的假设是:

  • A) netcore 运行时未将奇偶校验设置传递给驱动程序(不太可能)
  • B) 操作系统忽略指令。

saw*_*ust 5

stty命令只是 shell 中使用 termios API 的一种方法。
\n应用程序应使用 termios API 来根据情况的确切要求配置串行终端(而不是依赖于启动时的预期配置)。
\n如果您使用的应用程序环境不允许访问 termios API,则您可能使用了不适当的方法。

\n\n
\n

你知道有什么 Linux 应用程序可以对奇偶校验错误做出明确的反应吗?

\n
\n\n

以下 C 程序从串行终端读取行(即规范模式),并配置为检测 Mark(或 1)作为 8 位字符帧的奇偶校验位。

\n\n
#define SERIALTERMINAL      "/dev/ttyS0"\n#include <errno.h>\n#include <fcntl.h> \n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <termios.h>\n#include <unistd.h>\n\nint set_interface_attribs(int fd, int speed)\n{\n    struct termios tty;\n\n    if (tcgetattr(fd, &tty) < 0) {\n        printf("Error from tcgetattr: %s\\n", strerror(errno));\n        return -1;\n    }\n\n    cfsetospeed(&tty, (speed_t)speed);\n    cfsetispeed(&tty, (speed_t)speed);\n\n    tty.c_cflag |= CLOCAL | CREAD;\n    tty.c_cflag &= ~CSIZE;\n    tty.c_cflag |= CS8;         /* 8-bit characters */\n    tty.c_cflag |= PARENB;      /* enable parity */\n    tty.c_cflag &= ~PARODD;     /* Even parity */\n    tty.c_cflag |= CMSPAR;      /* force Even parity to SPACE */\n    tty.c_cflag &= ~CSTOPB;     /* only need 1 stop bit */\n    tty.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */\n\n    tty.c_lflag |= ICANON | ISIG;  /* canonical input */\n    tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);\n\n    tty.c_iflag &= ~IGNCR;  /* preserve carriage return */\n    tty.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL);\n    tty.c_iflag &= ~(IXON | IXOFF | IXANY);   /* no SW flowcontrol */\n    tty.c_iflag |= IGNBRK;  /* ignore breaks */\n    tty.c_iflag &= ~ISTRIP;\n    tty.c_iflag &= ~IGNPAR; /* report error */\n    tty.c_iflag |= INPCK;   /* test parity */\n    tty.c_iflag |= PARMRK;  /* verbose parity err */\n\n    tty.c_oflag &= ~OPOST;\n\n    tty.c_cc[VEOL] = 0;\n    tty.c_cc[VEOL2] = 0;\n    tty.c_cc[VEOF] = 0x04;\n\n    if (tcsetattr(fd, TCSANOW, &tty) != 0) {\n        printf("Error from tcsetattr: %s\\n", strerror(errno));\n        return -1;\n    }\n    return 0;\n}\n\n\nint main(void)\n{\n    char *portname = SERIALTERMINAL;\n    int fd;\n    int wlen;\n\n    fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);\n    if (fd < 0) {\n        printf("Error opening %s: %s\\n", portname, strerror(errno));\n        return -1;\n    }\n    /*baudrate 115200, 8 bits, Space for parity, 1 stop bit */\n    set_interface_attribs(fd, B115200);\n\n    /* simple output */\n    wlen = write(fd, "Hello!\\n", 7);\n    if (wlen != 7) {\n        printf("Error from write: %d, %d\\n", wlen, errno);\n    }\n    tcdrain(fd);    /* delay for output */\n\n\n    /* simple canonical input, read lines */\n    do {\n        unsigned char buf[81];\n        unsigned char *p;\n        int rdlen;\n\n        rdlen = read(fd, buf, sizeof(buf) - 1);\n        if (rdlen > 0) {\n            buf[rdlen] = 0;\n            printf("Read %d:", rdlen);\n            /* first display as hex numbers then ASCII */\n            for (p = buf; rdlen-- > 0; p++) {\n                printf(" 0x%x", *p);\n                if (*p < \' \')\n                    *p = \'.\';   /* replace any control chars */\n            }\n            printf("\\n    \\"%s\\"\\n\\n", buf);\n        } else if (rdlen < 0) {\n            printf("Error from read: %d: %s\\n", rdlen, strerror(errno));\n        } else {  /* rdlen == 0 */\n            printf("Nothing read. EOF?\\n");\n        }               \n        /* repeat read */\n    } while (1);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

该程序在一台内置 16550A 串口的旧 Linux (Ubuntu 14.04.2 LTS) PC 上执行。

\n\n
[    2.656593] 00:08: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A\n
Run Code Online (Sandbox Code Playgroud)\n\n

该串行端口似乎无法传输带奇偶校验的 8 位数据(11 位帧),但似乎能够读取带奇偶校验的 8 位数据。

\n\n

串行数据由具有 9 位 UART 功能的 SBC 生成。使用示波器捕获帧以确认8S1和8E1帧的长度为11位。
\n(FTDI USB 到 RS232 转换器在生成所有具有 8 位字符的奇偶校验配置时并不可靠。)

\n\n
\n\n

当发送器配置为 8 位和奇偶校验空间(与程序匹配)时,PC 程序将“ABCDEFG\\n”读取为:

\n\n
Read 8: 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0xa\n    "ABCDEFG."\n
Run Code Online (Sandbox Code Playgroud)\n\n

数据读取正确。

\n\n
\n\n

当发送器配置为 8 位和偶校验时,PC 程序将“ABCDEFG\\n”读取为:

\n\n
Read 14: 0x41 0x42 0xff 0x0 0x43 0x44 0xff 0x0 0x45 0xff 0x0 0x46 0x47 0xa\n    "AB\xef\xbf\xbd.CD\xef\xbf\xbd.E\xef\xbf\xbd.FG."\n
Run Code Online (Sandbox Code Playgroud)\n\n

读取(正确)识别出三个字符,其中将标记而不是空格作为奇偶校验位。
\n每个带有“奇偶校验错误”的字符前面都有字节0xFF 0x00(即总共三个字节)。

\n\n

请注意,当实际接收到的数据0xFF(没有奇偶校验错误)时,termios 会将该数据扩展为0xFF 0xFF. 因此请注意,当下一个数据为 时0x00,这不是错误指示。IOW读取0xFF 0xFF 0x00转换为实际数据0xFF 0x00
\n但是当实际接收到的数据存在0xFF 奇偶校验错误时,则读取返回0xFF 0x00 0xFF(即没有与错误指示相结合的扩展)。

\n