分类: C/C++
2008-03-11 09:19:40
Advanced Serial Programming
本章主要谈论使用ioctl(2)和select(2)系统调用的高级串口编程技术。
串行端口 IOCTLs
在第二章,配置串口中我们使用了 tcgetattr 和 tcsetattr 函数来做串口的设置。在UNIX 下,这些函数都是使用 ioctl(2) 系统调用来完成他们的任务的。ioctl 系统调用有如下三个参数:
int ioctl(int fd, int request, ...);
参数 fd 指定了串行端口的文件描述符。
参数 request 是一个定义在
表10 - IOCTL 的串口调用
Request |
Description |
POSIX Function |
TCGETS |
Gets the current serial port settings. 读取当前的串口属性 |
tcgetattr |
TCSETS |
Sets the serial port settings immediately 设置串口属性并立即生效 |
tcsetattr(fd, TCSANOW, &options) |
TCSETSF |
Sets the serial port settings after flushing the input and output buffers. 设置串口属性,等到输入输出缓冲区都清空了再生效 |
tcsetattr(fd, TCSAFLUSH, &options) |
TCSETSW |
Sets the serial port settings after allowing the input and output buffers to drain/empty. 设置串口属性,等到允许清空输入输出缓冲区了或数据传完后设置生效 |
tcsetattr(fd, TCSADRAIN, &options) |
TCSBRK |
Sends a break for the given time. 在指定时间后发送break |
tcsendbreak, tcdrain |
TCXONC |
Controls software flow control. 软件流控 |
tcflow |
TCFLSH |
Flushes the input and/or output queue. 将输入输出队列全部发出 |
tcflush |
TIOCMGET |
Returns the state of the "MODEM" bits. 返回 “MODEM” 位的状态 |
None |
TIOCMSET |
Sets the state of the "MODEM" bits. 设置“MODEM”位的状态 |
None |
FIONREAD |
Returns the number of bytes in the input buffer. 返回输入缓冲区内的字节数 |
None |
Getting the Control Signals
The TIOCMGET ioctl gets the current "MODEM" status bits, which consist of all of the RS-232 signal lines except RXD and TXD, listed in Table 11.
To get the status bits, call ioctl with a pointer to an integer to hold the bits, as shown in Listing 5.
获得控制信号
TIOCMGET - ioctl 获得当前“MODEM”的状态位,其中包括了除 RXD 和 TXD 之外,所有的RS-232 信号线,见列表 11。
为了获得状态位,使用一个包含比特位的整数的指针来调用 ioctl,见清单5。
Listing 5 - Getting the MODEM status bits.
清单 5 - 读取 DODEM 的状态位.
#include
#include
int fd;
int status;
ioctl(fd, TIOCMGET, &status);
Table 11 - Control Signal Constants
表 11 - 控制信号常量
Constant |
Description |
TIOCM_LE |
DSR (data set ready/line enable) |
TIOCM_DTR |
DTR (data terminal ready) |
TIOCM_RTS |
RTS (request to send) |
TIOCM_ST |
Secondary TXD (transmit) |
TIOCM_SR |
Secondary RXD (receive) |
TIOCM_CTS |
CTS (clear to send) |
TIOCM_CAR |
DCD (data carrier detect) |
TIOCM_CD |
Synonym for TIOCM_CAR |
TIOCM_RNG |
RNG (ring) |
TIOCM_RI |
Synonym for TIOCM_RNG |
TIOCM_DSR |
DSR (data set ready) |
Setting the Control Signals
The TIOCMSET ioctl sets the "MODEM" status bits defined above. To drop the DTR signal you can use the code in Listing 6.
设置控制信号
TIOCMSET - ioctl 设置“MODEM”上述定义的状态位。可以使用 清单6 的来给DTR信号置低。
Listing 6 - Dropping DTR with the TIOCMSET ioctl.
清单 6 - 使用 TIOCMSET ioctl 置低 DTR 信号
#include
#include
int fd; int status;
ioctl(fd, TIOCMGET, &status);
status &= ~TIOCM_DTR;
ioctl(fd, TIOCMSET, &status);
The bits that can be set depend on the operating system, driver, and modes in use. Consult your operating system documentation for more information.
能进行设置的比特位有操作系统,理r4ZlBt件HI$s,^
Getting the Number of Bytes Available
The FIONREAD ioctl gets the number of bytes in the serial port input buffer. As with TIOCMGET you pass in a pointer to an integer to hold the number of bytes, as shown in Listing 7.
获取可供读取的字节数
FIONREAD - ioctl 读取串行端口输入缓冲区中的字节数。与 TIOCMGET 一起传递一个包含字节数的整数的指针,
Listing 7 - Getting the number of bytes in the input buffer.
清单7 - 读取串行端口输入缓冲区中的字节数
#include
#include
int fd;
int bytes;
ioctl(fd, FIONREAD, &bytes);
This can be useful when polling a serial port for data, as your program can determine the number of bytes in the input buffer before attempting a read.
在查询串口是否有数据到来的时候这一段是很有用的,可以让在准备读取之前用来确定输入缓冲区里面的可读字节数。
Selecting Input from a Serial Port
While simple applications can poll or wait on data coming from the serial port, most applications are not simple and need to handle input from multiple sources.
UNIX provides this capability through the select(2) system call. This system call allows your program to check for input, output, or error conditions on one or more file descriptors. The file descriptors can point to serial ports, regular files, other devices, pipes, or sockets. You can poll to check for pending input, wait for input indefinitely, or timeout after a specific amount of time, making the select system call extremely flexible.
Most GUI Toolkits provide an interface to select; we will discuss the X Intrinsics ("Xt") library later in this chapter.
从串行端口选择输入
虽然简单的程序可以通过poll串口或者等待串口数据到来读取串口,
atA无dTYL$管OS*f
The SELECT System Call
The select system call accepts 5 arguments:
int select(int max_fd, fd_set *input, fd_set *output, fd_set *error, struct timeval *timeout);
The max_fd argument specifies the highest numbered file descriptor in the input, output, and error sets. The input, output, and error arguments specify sets of file descriptors for pending input, output, or error conditions; specify NULL to disable monitoring for the corresponding condition. These sets are initialized using three macros:
FD_ZERO(fd_set);
FD_SET(fd, fd_set);
FD_CLR(fd, fd_set);
The FD_ZERO macro clears the set entirely. The FD_SET and FD_CLR macros add and remove a file descriptor from the set, respectively.
The timeout argument specifies a timeout value which consists of seconds (timeout.tv_sec) and microseconds (timeout.tv_usec). To poll one or more file descriptors, set the seconds and microseconds to zero. To wait indefinitely specify NULL for the timeout pointer.
The select system call returns the number of file descriptors that have a pending condition, or -1 if there was an error.
SELECT 系统调用
Select 系统调用可以接受 5 个参数:
int select(int max_fd, fd_set *input, fd_set *output, fd_set *error, struct timeval *timeout);
参数 max_fd 定义了所有用到的文件描述符(input, output, error集合)中的最大值。
参数 input, output, error 定义了待处理的输入,输出,错误情况;置 NULL 则代表不去监查相应的条件。这几个集合用三个宏来进行初始化
FD_ZERO(fd_set);
FD_SET(fd, fd_set);
FD_CLR(fd, fd_set);
宏 FD_ZERO 清空整个集合; FD_SET 和 FD_CLR 分别从集合中、删除文件描述符。
参数 timeout 定义了一个由秒(timeout.tv_sec)和毫秒(timeout.tv_usec)组成的一个超时值。要查询一个或多个文件描述符,把秒和毫秒置为 0 。要无限等待的话就把 timeout 指针置 NULL 。
select 系统调用返回那个有待处理条件的文件描述符的值,或者,如果有错误发生的话就返回 -1。
Using the SELECT System Call
Suppose we are reading data from a serial port and a socket. We want to check for input from either file descriptor, but want to notify the user if no data is seen within 10 seconds. To do this we''''ll need to use the select system call, as shown in Listing 8.
使用 select 系统调用
假设我们正在从一个串口和一个socket 读取数据。我们想确认来自各文件描述符的输入,又希望如果10秒钟内都没有数据的话通知用户。要完成这些工作,我们可以像 清单8 这样使用select系统调用:
Listing 8 - Using SELECT to process input from more than one source.
清单8 - 使用select 处理来自多个源的输入
#include
#include
#include
#include
int n;
int socket;
int fd;
int max_fd;
fd_set input;
struct timeval timeout; /* Initialize the input set 初始化输入集合*/
FD_ZERO(input);
FD_SET(fd, input);
FD_SET(socket, input);
max_fd = (socket > fd ? socket : fd) + 1; /* Initialize the timeout structure 初始化 timeout 结构*/
timeout.tv_sec = 10;
timeout.tv_usec = 0;
/* Do the select */
n = select(max_fd, &input, NULL, NULL, &timeout);
/* See if there was an error 看看是否有错误发生*/
if (n < 0)
perror("select failed");
else if (n == 0)
puts("TIMEOUT");
else { /* We have input 有输入进来了*/
if (FD_ISSET(fd, input))
process_fd();
if (FD_ISSET(socket, input))
process_socket();
}
You''''ll notice that we first check the return value of the select system call. Values of 0 and -1 yield the appropriate warning and error messages. Values greater than 0 mean that we have data pending on one or more file descriptors.
To determine which file descriptor(s) have pending input, we use the FD_ISSET macro to test the input set for each file descriptor. If the file descriptor flag is set then the condition exists (input pending in this case) and we need to do something.
你会发现,我们首先检查select系统调用的返回值。如果是 0 和 -1 则表示相应的警告和错误信息。大于 0 的值代表我们在一个或多个文件描述符上有待处理的数据。
要知道是哪个文件描述符有待处理的输入,我们要使用 FDISSET 宏来测试每个文件描述符的输入集合。如果文件描述符标志被设置了,则符合条件(这时候就有待处理的输入了)我们需要进行一些操作。
Using SELECT with the X Intrinsics Library
The X Intrinsics library provides an interface to the select system call via the XtAppAddInput(3x) and XtAppRemoveInput(3x) functions:
int XtAppAddInput(XtAppContext context, int fd, int mask, XtInputProc proc, XtPointer data);
void XtAppRemoveInput(XtAppContext context, int input);
The select system call is used internally to implement timeouts, work procedures, and check for input from the X server. These functions can be used with any Xt-based toolkit including Xaw, Lesstif, and Motif.
The proc argument to XtAppAddInput specifies the function to call when the selected condition (e.g. input available) exists on the file descriptor. In the previous example you could specify the process_fd or process_socket functions.
Because Xt limits your access to the select system call, you''''ll need to implement timeouts through another mechanism, probably via XtAppAddTimeout(3x).
在X Intrinsics library 中使用select
X Intrinsics library 提供了一个接口,
IL'oj提t提&d8x垠K3教