在《Linux串列埠程式設計》程式設計一文中介紹了串列埠應用中常用的基本操作,如:串列埠開啟關閉、串列埠設定、資料收發等。本篇文章主要基於常規串列埠操作進行了擴充,主要介紹如下操作:
與上一篇文章類似,為方便使用者使用我們將以上串列埠操作均封裝成了獨立的函數,可以極大的節約開發時間。
/**
* libtty_setcustombaudrate - set baud rate of tty device
* @fd: device handle
* @speed: baud rate to set
*
* The function return 0 if success, or -1 if fail.
*/
static int libtty_setcustombaudrate(int fd, int baudrate)
{
struct termios2 tio;
if (ioctl(fd, TCGETS2, &tio)) {
perror("TCGETS2");
return -1;
}
tio.c_cflag &= ~CBAUD;
tio.c_cflag |= BOTHER;
tio.c_ispeed = baudrate;
tio.c_ospeed = baudrate;
if (ioctl(fd, TCSETS2, &tio)) {
perror("TCSETS2");
return -1;
}
if (ioctl(fd, TCGETS2, &tio)) {
perror("TCGETS2");
return -1;
}
return 0;
}
Note:
直接使用write函數完成串列埠資料的傳送時,在該函數返回時實際上只是把write緩衝區的資料拷貝至tty核心層的緩衝區中,當緩衝區滿時write才會阻塞,此過程中串列埠驅動並未執行真正的傳送動作。在有些場景下,我們希望等待串列埠傳送物理上真正完成了再執行後續的操作。那麼此時需要使用的函數為:
/**
* tcdrain() waits until all output written to the object referred to by fd has been
* transmitted.
*/
int tcdrain(int fd);
使用select函數實現的I/O多路轉接模型,在select操作期間,I/O可以進行其他操作。在對多個裝置同時使用的應用場景中應用較為普遍。比如多個串列埠裝置,或者網路通訊中處理多個使用者端。select可以具體設定每個檔案描述符的條件、等待時間等,這樣在函數返回時可以知道具體哪個裝置已經準備好讀寫。
/**
* libtty_selectread - read data from uart
* @fd: device handle
* @buffer: pointer to read buffer
* @count: read length
*
* The function return actual read length if success, 0 if timeout, -1 if fail.
*/
static int libtty_selectread(int fd, char *buffer, int count)
{
int ret;
fd_set rd;
struct timeval tv;
FD_ZERO(&rd);
FD_SET(fd, &rd);
tv.tv_sec = 5;
tv.tv_usec = 0;
ret = select(fd + 1, &rd, NULL, NULL, &tv);
if (ret == -1) {
perror("select(): ");
}
else if (ret)
return read(fd, buffer, count);
else {
printf("select timeout.\n");
}
return ret;
}
VTIME和VMIN常規情況下,設定為0。但是很多應用場景我們需要將二者結合起來共同控制對串列埠的讀取行為,引數組合說明如下:
部分使用RS485的應用場景或者針對特定的串列埠硬體,需要通過串列埠應用程式主動呼叫RS485功能開啟的相關API。用法如下:
/**
* libtty_rs485set - rs485 set
* @fd: file descriptor of tty device
* @enable: 0 on disable, other on enable
*
* The function return 0 if success, others if fail.
*/
int libtty_rs485set(int fd, char enable)
{
struct serial_rs485 rs485conf;
if (enable)
rs485conf.flags |= SER_RS485_ENABLED;
else
rs485conf.flags &= ~SER_RS485_ENABLED;
return ioctl(fd, TIOCSRS485, &rs485conf);
}
同步等待串列埠Modem訊號變化是指,應用程式可以呼叫介面函數進入等待,直到程式中設定的Modem輸入訊號DCD/RI/CTS/DCD的訊號變化才退出等待。常用於裝置狀態與特定儀器的操作同步場景。
/**
* libtty_tiocmwait - wiat for modem signal to changed
* @fd: file descriptor of tty device
*
* The function return 0 if success, others if fail.
*/
static int libtty_tiocmwait(int fd)
{
unsigned long modembits = TIOCM_DSR | TIOCM_CTS | TIOCM_CD | TIOCM_RI;
return ioctl(fd, TIOCMIWAIT, modembits);
}
如以上程式碼所示,設定等待的modem訊號為所有輸入訊號DSR、CTS、DCD和RI,只要任意一路串列埠訊號發生改變,則API退出。
關於Linux串列埠程式設計的介紹就到這裡了,關於更多更實用的串列埠用法可以隨時交流討論哈~