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

stty serial port settings for parity not persistent

我有一个打开串行端口的 netcore 应用程序,一旦检测到奇偶校验错误就会在控制台上写入 "parity error"。它在 Windows 10 中工作正常,但无法在 Linux.

下工作

我的假设是 OS 没有将奇偶校验错误传递给 netcore。

检查端口设置我运行:

stty -D /dev/ttyS0 -ignpar inpck

然后我运行:

stty -D /dev/ttyS0 -a 

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

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

所以我运行

stty -D /dev/ttyS0 -a 

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

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

谢谢。

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

stty 命令只是 shell 中使用 termios API.
的一种方法 应用程序应使用 termios API 将串行终端配置为符合具体情况的要求(而不是依赖启动时的预期配置)。
如果您使用的应用程序环境不允许访问 termios API,那么您可能使用了不合适的方法。

Do you know any linux app that could explicitly react somehow to a parity error?

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

#define SERIALTERMINAL      "/dev/ttyS0"
#include <errno.h>
#include <fcntl.h> 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

int set_interface_attribs(int fd, int speed)
{
    struct termios tty;

    if (tcgetattr(fd, &tty) < 0) {
        printf("Error from tcgetattr: %s\n", strerror(errno));
        return -1;
    }

    cfsetospeed(&tty, (speed_t)speed);
    cfsetispeed(&tty, (speed_t)speed);

    tty.c_cflag |= CLOCAL | CREAD;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;         /* 8-bit characters */
    tty.c_cflag |= PARENB;      /* enable parity */
    tty.c_cflag &= ~PARODD;     /* Even parity */
    tty.c_cflag |= CMSPAR;      /* force Even parity to SPACE */
    tty.c_cflag &= ~CSTOPB;     /* only need 1 stop bit */
    tty.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */

    tty.c_lflag |= ICANON | ISIG;  /* canonical input */
    tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);

    tty.c_iflag &= ~IGNCR;  /* preserve carriage return */
    tty.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL);
    tty.c_iflag &= ~(IXON | IXOFF | IXANY);   /* no SW flowcontrol */
    tty.c_iflag |= IGNBRK;  /* ignore breaks */
    tty.c_iflag &= ~ISTRIP;
    tty.c_iflag &= ~IGNPAR; /* report error */
    tty.c_iflag |= INPCK;   /* test parity */
    tty.c_iflag |= PARMRK;  /* verbose parity err */

    tty.c_oflag &= ~OPOST;

    tty.c_cc[VEOL] = 0;
    tty.c_cc[VEOL2] = 0;
    tty.c_cc[VEOF] = 0x04;

    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        printf("Error from tcsetattr: %s\n", strerror(errno));
        return -1;
    }
    return 0;
}


int main(void)
{
    char *portname = SERIALTERMINAL;
    int fd;
    int wlen;

    fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
    if (fd < 0) {
        printf("Error opening %s: %s\n", portname, strerror(errno));
        return -1;
    }
    /*baudrate 115200, 8 bits, Space for parity, 1 stop bit */
    set_interface_attribs(fd, B115200);

    /* simple output */
    wlen = write(fd, "Hello!\n", 7);
    if (wlen != 7) {
        printf("Error from write: %d, %d\n", wlen, errno);
    }
    tcdrain(fd);    /* delay for output */


    /* simple canonical input, read lines */
    do {
        unsigned char buf[81];
        unsigned char *p;
        int rdlen;

        rdlen = read(fd, buf, sizeof(buf) - 1);
        if (rdlen > 0) {
            buf[rdlen] = 0;
            printf("Read %d:", rdlen);
            /* first display as hex numbers then ASCII */
            for (p = buf; rdlen-- > 0; p++) {
                printf(" 0x%x", *p);
                if (*p < ' ')
                    *p = '.';   /* replace any control chars */
            }
            printf("\n    \"%s\"\n\n", buf);
        } else if (rdlen < 0) {
            printf("Error from read: %d: %s\n", rdlen, strerror(errno));
        } else {  /* rdlen == 0 */
            printf("Nothing read. EOF?\n");
        }               
        /* repeat read */
    } while (1);
}

该程序是在具有内置 16550A 串行端口的旧 Linux (Ubuntu 14.04.2 LTS) PC 上执行的。

[    2.656593] 00:08: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A

此串口似乎不能传输带奇偶校验的 8 位数据(11 位帧),但似乎能够读取带奇偶校验的 8 位数据。

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


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

Read 8: 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0xa
    "ABCDEFG."

数据读取正确。


当发送方配置为 8 位和偶校验时,PC 程序读取 "ABCDEFG\n" 为:

Read 14: 0x41 0x42 0xff 0x0 0x43 0x44 0xff 0x0 0x45 0xff 0x0 0x46 0x47 0xa
    "AB�.CD�.E�.FG."

读取(正确)识别了三个具有 Mark 而不是 Space 作为奇偶校验位的字符。
每个带有 "parity error" 的字符前面都有 0xFF 0x00 字节(即总共三个字节)。

请注意,当实际接收到的数据为 0xFF(没有奇偶校验错误)时,termios 会将数据扩展为 0xFF 0xFF 的两个字节。所以请注意,当下一个数据是 0x00 时,这不是错误指示。 IOW 读数 0xFF 0xFF 0x00 转换为实际数据 0xFF 0x00.
但是当实际收到的数据是0xFF有奇偶校验错误时,再读取returns0xFF 0x00 0xFF(即没有扩展结合错误指示).