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。
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 个字符(但不包括)任何终止符换行符被丢弃。 这确保了终端可以始终接收更多输入,
直到可以读取至少一行。
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种不同的情况
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。
read(2) blocks until MIN bytes are available, and returns up to the number
of bytes requested.
read() 阻塞,直到 MIN 字节可用,并返回最多请求的字节数。
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) 时数据已经可用,则调用的行为就像在调用后立即收到数据一样。
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) 在这种情况下不会返回)
原始模式是一种特殊的非规范模式。这种模式下,所有输入数据以字节为单位处理。
调用cfmakeraw()函数可将终端设置为原始模式。
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() 不执行任何操作就返回。
waits until all output written to the object referred to by fd has been transmitted.
等待直到所有写入 fd 引用的对象的输出都已传输完毕。
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.
同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送
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 字符,启动终端设备向系统发送数据。
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
返回输出的波特率
设置输出的波特率
获取输入的波特率
设置输入的波特率
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