分类: LINUX
2008-12-10 17:44:01
Termios是POSIX规定的标准接口,它和System V的接口termio.类似。使用数据结构termios,在termios.h中定义,该文件还包含小量的函数调用。
使用termios.h中的函数调用时,要链接合适的函数库。根据系统,可能是标准的c库或者curses库。如有必要,编译的时候需要添加:-lcurses。老系统中甚至为-lncurses。
模式有:
❑ Input
❑ Output
❑ Control
❑ Local
❑ Special
control characters
最简单的termios,X/Open允许扩充。
#include
struct termios {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_cc[NCCS];
};
初始化termios:
#include
int tcgetattr(int
fd, struct termios *termios_p);
重新配置终端接口:
#include
int tcsetattr(int
fd, int actions, const struct termios *termios_p);
❑ TCSANOW:
Changes values immediately.
❑ TCSADRAIN:
Changes values when current output is complete.
❑ TCSAFLUSH: Changes
values when current output is complete, but discards any input currently
available and not yet returned in a read
call.
注意保存终端设置相当重要,一般需要程序来保存和恢复。
更多的函数调用和模式请参考man手册或者POSIX or X/Open规范。
最重要的模式是local mode,通过合适模式,前面的程序可以不输入回车。
*
输入模式
决定输入来自于串口或者键盘。修改termios中的c_iflag,所有标识定义为宏,可以使用比特OR连接,后面的也是如此。宏定义如下:
❑ BRKINT:
Generate an interrupt when a break condition (loss of connection) is detected
on the line
❑ IGNBRK: Ignore
break conditions on the line
❑ ICRNL:
Convert a received carriage return to a newline
❑ IGNCR: Ignore
received carriage returns
❑ INLCR:
Convert received newlines to carriage returns
❑ IGNPAR: Ignore
characters with parity errors
❑ INPCK:
Perform parity checking on received characters
❑ PARMRK: Mark
parity errors
❑ ISTRIP: Strip
(set to seven bits) all incoming characters
❑ IXOFF: Enable
software flow control on input
❑ IXON: Enable
software flow control on output
默认值一般可以满足所有需求。如果BRKINT nor IGNBRK 都没有设置,break状态是NULL (0x00)字符。
*
输出模式
输出到串口或者屏幕。使用c_oflag,对用的宏:
❑ OPOST: Turn
on output processing
❑ ONLCR:
Convert any output newline to a carriage return/line feed pair
❑ OCRNL:
Convert any output carriage return to a newline
❑ ONOCR: No
carriage return output in column 0
❑ ONLRET: A
newline also does a carriage return
❑ OFILL: Send
fill characters to provide delays
❑ OFDEL:
❑ NLDLY:
Newline delay selection
❑ CRDLY:
Carriage return delay selection
❑ TABDLY: Tab
delay selection
❑ BSDLY:
Backspace delay selection
❑ VTDLY:
Vertical tab delay selection
❑ FFDLY: Form
feed delay selection
如果OPOST没有设置,其他标识都忽略。输出模式很少使用。
*
控制模式
使用c_cflag:对应的宏:
❑ CLOCAL: Ignore
any modem status lines.
❑ CREAD: Enable
the receipt of characters.
❑ CS5: Use
five bits in sent or received characters.
❑ CS6: Use
six bits in sent or received characters.
❑ CS7: Use
seven bits in sent or received characters.
❑ CS8: Use
eight bits in sent or received characters.
❑ CSTOPB: Use
two stop bits per character, rather than one.
❑ HUPCL: Hang
up modem on close.
❑ PARENB: Enable
parity generation and detection.
❑ PARODD: Use
odd parity rather than even parity.
If HUPCL
is set, when the
terminal driver detects that the last file descriptor referring to the terminal
has been closed, it
will set the modem control lines to “hang-up” the line.
控制模式多用于连接modem的串口,通常,改终端配置比修改termios更快。
*
本地模式
c_lflag用于控制终端的多种特征:
❑ ECHO: Enable
local echoing of input characters
❑ ECHOE:
Perform a Backspace, Space, Backspace combination on receiving ERASE
❑ ECHOK:
Perform erase line on the KILL character
❑ ECHONL: Echo
newline characters
❑ ICANON: Enable
canonical input processing (see the text following this list)
❑ IEXTEN: Enable
implementation-specific functions
❑ ISIG: Enable
signals
❑ NOFLSH:
Disable flush on queue
❑ TOSTOP: Send
background processes a signal on write attempts
使用最多的ECHO和ICANON。
*
特殊控制字符
c_cc数组,根据是否使用规范模式,它有2种不同的使用方法。(that is, the setting of the ICANON
flag in the c_lflag
member of termios).
Canonical模式:
❑ VEOF: EOF
character
❑ VEOL: EOL
character
❑ VERASE: ERASE
character
❑ VINTR: INTR
character
❑ VKILL: KILL
character
❑ VQUIT: QUIT
character
❑ VSUSP: SUSP
character
❑ VSTART: START
character
❑ VSTOP: STOP
character
non-canonical模式:
❑ VINTR: INTR
character
❑ VMIN: MIN
value
❑ VQUIT: QUIT
character
❑ VSUSP: SUSP
character
❑ VTIME: TIME
value
❑ VSTART: START
character
❑ VSTOP: STOP
character
-*字符
Character Description
INTR Causes the terminal driver to send a SIGINT
signal to processes
connected
to the
terminal. We discuss signals in more detail in Chapter 11.
QUIT Causes the terminal driver to send a SIGQUIT
signal to processes
connected
to the
terminal.
ERASE Causes the terminal driver to delete the last character
on the line.
KILL Causes the terminal driver to delete the entire line.
EOF Causes the terminal driver to pass all characters on the
line to the application
reading
input. If the line is empty, a read call will return zero characters
as
though a read had been attempted at the end of a file.
EOL Acts as a line terminator in addition to the more usual
newline character.
SUSP Causes the terminal driver to send a SIGSUSP
signal to processes
connected
to the
terminal. If your UNIX supports job control, the current
application
will be suspended.
STOP Acts to “flow off”; that is, prevent further output to
the terminal. It’s used
to
support XON/XOFF flow control and is usually set to the ASCII XOFF
character,
Ctrl+S.
START Restarts output after a STOP
character, often the
ASCII XON character.
-*TIME and MIN
用于non-canonical中,控制输入。
❑ MIN = 0 and TIME = 0: 立即返回
❑ MIN = 0 and TIME > 0:能阅读或者10之一秒时返回
❑ MIN > 0 and TIME = 0:读完MIN个字符再返回
❑ MIN > 0 and TIME > 0:
注意网络可能对时间产生的影响。
-*通过shell访问终端模式
查看终端:$ stty -a
$ stty
sane
终端乱序的恢复方法:
一般使用$
stty sane,如果回车不能使用,可以改用:Ctrl+J
可以用保存恢复的方法:stty -g > save_stty,而后$ stty
$(cat save_stty)。也可以使用Ctrl+J,如下:
save_stty=”$(stty -g)“
stty $save_stty
最后的方法是选用其他终端。kill HUP
-*通过命令行设置终端模式
设置立即读入字符:$
stty -icanon min 1 time 0
$
stty -echo
-*终端速度
通过函数调用来实现,输入和输出分开处理。
#include
speed_t cfgetispeed(const struct termios *);
speed_t cfgetospeed(const struct termios *);
int cfsetispeed(struct termios *, speed_t speed);
int cfsetospeed(struct termios *, speed_t speed);
针对termios,不是port。要用tcgetattr读取当前配置。使用上面的函数设置速率,再用tcsetattr写回termios。
常用值:
❑ B0: Hang
up the terminal
❑ B1200: 1200
baud
❑ B2400: 2400
baud
❑ B9600: 9600
baud
❑ B19200: 19200
baud
❑ B38400: 38400
baud
一些系统还定义了B57600, B115200, and B230400,是不可移植的。
-*附加函数
这些函数直接操作文件描述符。
#include
int tcdrain(int fd);
int tcflow(int fd, int flowtype);
int tcflush(int fd, int in_out_selector);
❑ tcdrain
causes the calling program to wait until all queued
output has been sent.
❑ tcflow
is used to suspend or restart output.
❑ tcflush
can be used to flush input, output, or both.
实例:读入password的时候禁用echo
# cat
password.c
#include
#include
#include
#define
PASSWORD_LEN 8
int
main()
{
struct termios initialrsettings,
newrsettings;
char password[PASSWORD_LEN + 1];
tcgetattr(fileno(stdin),
&initialrsettings);
newrsettings = initialrsettings;
newrsettings.c_lflag &= ~ECHO;
printf("Enter password: ");
if(tcsetattr(fileno(stdin), TCSAFLUSH,
&newrsettings) != 0) {
fprintf(stderr,"Could not set
attributes\n");
}
else {
fgets(password, PASSWORD_LEN, stdin);
tcsetattr(fileno(stdin), TCSANOW,
&initialrsettings);
fprintf(stdout, "\nYou entered
%s\n", password);
}
exit(0);
}
执行结果:
#
./password
Enter
password:
You
entered 12345
即敲即读也是另外一种处理密码的方法。
实例:需要回车的菜单
# cat
menu4.c
#include
#include
#include
#include
char
*menu[] = {
"a - add new record",
"d - delete record",
"q - quit",
NULL,
};
int
getchoice(char *greet, char *choices[], FILE *in, FILE *out);
int
main()
{
int choice = 0;
FILE *input;
FILE *output;
struct termios initial_settings,
new_settings;
if (!isatty(fileno(stdout))) {
fprintf(stderr,"You are not a
terminal, OK.\n");
}
input = fopen("/dev/tty",
"r");
output = fopen("/dev/tty",
"w");
if(!input || !output) {
fprintf(stderr, "Unable to open
/dev/tty\n");
exit(1);
}
tcgetattr(fileno(input),&initial_settings);
new_settings = initial_settings;
new_settings.c_lflag &= ~ICANON;
new_settings.c_lflag &= ~ECHO;
new_settings.c_cc[VMIN] = 1;
new_settings.c_cc[VTIME] = 0;
new_settings.c_lflag &= ~ISIG;
if(tcsetattr(fileno(input), TCSANOW,
&new_settings) != 0) {
fprintf(stderr,"could not set
attributes\n");
}
do {
choice = getchoice("Please select
an action", menu, input, output);
printf("You have chosen:
%c\n", choice);
} while (choice != 'q');
tcsetattr(fileno(input),TCSANOW,&initial_settings);
exit(0);
}
int
getchoice(char *greet, char *choices[], FILE *in, FILE *out)
{
int chosen = 0;
int selected;
char **option;
do {
fprintf(out, "Choice:
%s\n",greet);
option = choices;
while(*option) {
fprintf(out,
"%s\n",*option);
option++;
}
do {
selected = fgetc(in);
} while (selected == '\n' || selected
== '\r');
option = choices;
while(*option) {
if(selected == *option[0]) {
chosen = 1;
break;
}
option++;
}
if(!chosen) {
fprintf(out, "Incorrect
choice, select again\n");
}
} while(!chosen);
return selected;
}