c++实现串口功能之termios.h头文件研读<二>

概述

        termios是在Posix规范中定义的标准接口,表示终端设备(包括虚拟终端、串口等)。因为串口是一种终端设备,所以通过终端编程接口对其进行配置和控制。因此在具体讨论串口相关编程之前,需要先了解一下终端的相关知识。

        终端是指用户与计算机进行对话的接口,如键盘、显示器和串口设备等物理设备,X Window上的虚拟终端。类UNIX操作系统都有文本式虚拟终端,使用【Ctrl+Alt】+F1~F6键可以进入文本式虚拟终端,在X Window上可以打开几十个以上的图形式虚拟终端。类UNIX操作系统的虚拟终端有xterm、rxvt、zterm、eterm等,而Windows上有crt、putty等虚拟终端。

        终端有三种工作模式,分别为规范模式(canonical mode)非规范模式(non-canonical mode)原始模式(raw mode)

The setting of the ICANON canon flag in c_lflag determines
whether the terminal is operating in canonical mode (ICANON set)
or noncanonical mode (ICANON unset).  By default, ICANON is set.

c_lflag 中的 ICANON 规范标志的设置决定了终端是在规范模式(ICANON 设置)
还是非规范模式(ICANON 未设置)下运行。 默认情况下,设置了 ICANON。

规范模式(canonical mode)

Input is made available line by line.  An input line is
available when one of the line delimiters is typed (NL, EOL,
EOL2; or EOF at the start of line).  Except in the case of EOF,
the line delimiter is included in the buffer returned by read(2).

在规范模式下,输入是逐行的。当输入的是NL、EOL、EOL2或者行的开头是EOF的其中之一的时候,
输入行才会有效。除了 EOF 外,行分隔符包含在 read(2) 返回的缓冲区中。
Line editing is enabled (ERASE, KILL; and if the IEXTEN flag is
set: WERASE, REPRINT, LNEXT).  A read(2) returns at most one
line of input; if the read(2) requested fewer bytes than are
available in the current line of input, then only as many bytes
as requested are read, and the remaining characters will be
available for a future read(2).

在规范模式中,可以进行行编辑,而且一次调用read()最多只能读取一行数据。
如果read()请求读取的数据字节少于当前行可读取的字节,则read()只读取被请求的字节数,
剩下的字节下次再读。
The maximum line length is 4096 chars (including the
terminating newline character); lines longer than 4096 chars
are truncated.  After 4095 characters, input processing (e.g.,
ISIG and ECHO* processing) continues, but any input data after
4095 characters up to (but not including) any terminating
newline is discarded.  This ensures that the terminal can
always receive more input until at least one line can be read.

在规范模式下,最大行长度为 4096 个字符(包括终止换行符); 超过 4096 个字符的行
被截断。 在 4095 个字符之后,输入处理(例如,ISIG 和 ECHO* 处理)继续,但之后的任何输入数据
最多 4095 个字符(但不包括)任何终止符换行符被丢弃。 这确保了终端可以始终接收更多输入,
直到可以读取至少一行。

非规范模式(noncanonical mode)

input is available immediately (without the user having to type a line-delimiter character),
no input processing is performed, and line editing is disabled.  The read
buffer will only accept 4095 chars; this provides the necessary space 
for a newline char if the input mode is switched to canonical.

在非规范模式下,输入是即时有效,用户不需要另外输入行结束符,不能进行行编辑。读
缓冲区只接受 4095 个字符;如果再切换为规范模式的话,这样就可以为换行符提供了充足的空间
The settings of MIN (c_cc[VMIN]) and TIME (c_cc[VTIME]) determine the circumstances 
in which a read(2) completes; there are four distinct cases:

在非规范模式下,对参数MIN(c_cc[VMIN])和TIME(c_cc[VTIME])的设置决定read()函数的调用方式。
设置可以有4种不同的情况
  • MIN == 0, TIME == 0 (polling read 轮询读取)
If data is available, read(2) returns immediately, with
the lesser of the number of bytes available, or the number
of bytes requested.  If no data is available, read(2) returns 0.

如果数据可用, read() 立即返回,并用字节数或数量中的较小者请求的字节数。 如果没有数据可用,read() 返回 0。

  • MIN > 0, TIME == 0 (blocking read 阻塞读取)
 read(2) blocks until MIN bytes are available, and returns up to the number 
 of bytes requested.

read() 阻塞,直到 MIN 字节可用,并返回最多请求的字节数。

  • MIN == 0, TIME > 0 (read with timeout 超时读取)
TIME specifies the limit for a timer in tenths of a
second.  The timer is started when read(2) is called.
read(2) returns either when at least one byte of data is
available, or when the timer expires.  If the timer
expires without any input becoming available, read(2)
returns 0.  If data is already available at the time of
the call to read(2), the call behaves as though the data
was received immediately after the call.

TIME 以十分之一秒为单位指定计时器的限制。当read()被调用的时候,计时器就会启动。当至少一个字节可用或者计时器超时,read都会返回数据。如果计时器到期而没有任何输入可用,则read (2)
返回 0。如果在调用 read(2) 时数据已经可用,则调用的行为就像在调用后立即收到数据一样。

  • MIN > 0, TIME > 0 (read with interbyte timeout 字节间超时读取)
TIME specifies the limit for a timer in tenths of a second.  
Once an initial byte of input becomes available,
the timer is restarted after each further byte is received。
read(2) returns when any of the following conditions is met:

TIME 以十分之一秒为单位指定计时器的限制。一旦输入的初始字节可用,
每收到一个字节后,定时器重新启动。当满足以下任一条件时,read(2) 返回:

 * MIN bytes have been received.
   已收到 MIN 个字节。
   
 * The interbyte timer expires.
    字节间计时器到期。

 * The number of bytes requested by read(2) has been
   received.  (POSIX does not specify this termination
   condition, and on some other implementations read(2)
   does not return in this case.)
   已收到 read(2) 请求的字节数。(POSIX 没有指定这个终止条件,
   并且在其他一些实现中 read(2) 在这种情况下不会返回)

原始模式(Raw mode)

原始模式是一种特殊的非规范模式。这种模式下,所有输入数据以字节为单位处理。
调用cfmakeraw()函数可将终端设置为原始模式。

行控制(Line control)

tcsendbreak()

transmits a continuous stream of zero-valued bits for a specific duration, 
if the terminal is using asynchronous serial data transmission.  If duration 
is zero, it transmits zero-valued bits for at least 0.25 seconds, and not more than 0.5 seconds. 
 If duration is not zero, it sends zero-valued bits for -some implementation-defined length of time. 
 If the terminal is not using asynchronous serial data transmission, tcsendbreak() returns without taking any action.

如果终端使用异步串行数据传输,则在特定持续时间内传输零值位的连续流。 如果持续时间为零,则它传输零值位至少 0.25 秒,不超过 0.5 秒。 如果持续时间不为零,它会在某些实现定义的时间长度内发送零值位。 如果终端没有使用异步串行数据传输,则 tcsendbreak() 不执行任何操作就返回。

tcdrain()

 waits until all output written to the object referred to by fd has been transmitted.
 等待直到所有写入 fd 引用的对象的输出都已传输完毕。

tcflush()

discards data written to the object referred to by fd but not transmitted, 
or data received but not read, depending on the value of queue_selector:
刷新数据写入到fd的引用对象但不传输,或者只接收数据但是不读取,取决于queue_selector的值:

TCIFLUSH
      flushes data received but not read.
      刷新接收的数据但是不读取
      
TCOFLUSH
      flushes data written but not transmitted.
      刷新写入的数据但是不传输
      
TCIOFLUSH
      flushes both data received but not read, and data written but not transmitted.
      同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送

tcflow()

suspends transmission or reception of data on the object referred to by fd, 
depending on the value of action:
对于fd引用对象上的数据是暂停传输,还是暂停接收,取决于action的值:

TCOOFF 
    suspends output.
    暂停输出
    
TCOON  
    restarts suspended output.
    重新开始已经暂停的输出
    
TCIOFF 
    transmits a STOP character, which stops the terminal device from transmitting data to the system.
    发送一个 STOP 字符,停止终端设备向系统发送数据。
    
TCION  
    transmits a START character, which starts the terminal device transmitting data to the system.
    发送一个 START 字符,启动终端设备向系统发送数据。
    

行速率(Line speed)

波特率的常量值:

            B0
            B50
            B75
            B110
            B134
            B150
            B200
            B300
            B600
            B1200
            B1800
            B2400
            B4800
            B9600
            B19200
            B38400
            B57600
            B115200
            B230400
            B460800
            B500000
            B576000
            B921600
            B1000000
            B1152000
            B1500000
            B2000000
            
These constants are additionally supported on the SPARC architecture:
SPARC 体系结构还支持这些常量:
            B76800
            B153600
            B307200
            B614400

These constants are additionally supported on non-SPARC architectures:
非 SPARC 体系结构还支持这些常量:
            B2500000
            B3000000
            B3500000
            B4000000

cfgetospeed()

返回输出的波特率

cfsetospeed()

设置输出的波特率

cfgetispeed()

获取输入的波特率

cfsetispeed()

设置输入的波特率

示例

speed_t SerialPort::getBaudRate(int baudrate) {
    switch (baudrate) {
        case 0:
            return B0;
        case 50:
            return B50;
        case 75:
            return B75;
        case 110:
            return B110;
        case 134:
            return B134;
        case 150:
            return B150;
        case 200:
            return B200;
        case 300:
            return B300;
        case 600:
            return B600;
        case 1200:
            return B1200;
        case 1800:
            return B1800;
        case 2400:
            return B2400;
        case 4800:
            return B4800;
        case 9600:
            return B9600;
        case 19200:
            return B19200;
        case 38400:
            return B38400;
        case 57600:
            return B57600;
        case 115200:
            return B115200;
        case 230400:
            return B230400;
        case 460800:
            return B460800;
        case 500000:
            return B500000;
        case 576000:
            return B576000;
        case 921600:
            return B921600;
        case 1000000:
            return B1000000;
        case 1152000:
            return B1152000;
        case 1500000:
            return B1500000;
        case 2000000:
            return B2000000;
        case 2500000:
            return B2500000;
        case 3000000:
            return B3000000;
        case 3500000:
            return B3500000;
        case 4000000:
            return B4000000;
        default:
            return -1;
    }
}

int SerialPort::setSpeed(int fd, int speed) {
    speed_t b_speed;
    struct termios cfg;
    b_speed = getBaudRate(speed);
    //获取属性
    if (tcgetattr(fd, &cfg)) {
        LOGD("Get attr failed");
        close(fd);
        return FALSE;
    }
    /**
    *
    *将终端设置为原始模式
    */
    cfmakeraw(&cfg);
    //设置输入的波特率
    cfsetispeed(&cfg, b_speed);
    //设置输出波特率
    cfsetospeed(&cfg, b_speed);
    //把相关属性设置到设备
    if (tcsetattr(fd, TCSANOW, &cfg)) {
        LOGD("Set attr failed");
        close(fd);
        return FALSE;
    }

    return TRUE;
}

源码已同步gitHub:https://github.com/AinialJing/JniDemo
参考地址:https://man7.org/linux/man-pages/man3/termios.3.html

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值