1. 程式人生 > >struct termios結構體詳解【轉】

struct termios結構體詳解【轉】

一、資料成員

termios 函式族提供了一個常規的終端介面,用於控制非同步通訊埠。 這個結構包含了至少下列成員:
tcflag_t c_iflag;      /* 輸入模式 */
tcflag_t c_oflag;      /* 輸出模式 */
tcflag_t c_cflag;      /* 控制模式 */
tcflag_t c_lflag;      /* 本地模式 */
cc_t c_cc[NCCS];       /* 控制字元 */

struct termios
{unsigned short c_iflag; /* 輸入模式標誌*/
unsigned short c_oflag; /* 輸出模式標誌*/
unsigned short c_cflag; /* 控制模式標誌*/
unsigned short c_lflag; /*區域模式標誌或本地模式標誌或區域性模式*/
unsigned char c_line; /*行控制line discipline */
unsigned char c_cc[NCC]; /* 控制字元特性*/
};
二、作用
這個變數被用來提供一個健全的線路設定集合, 如果這個埠在被使用者初始化前使用. 驅動初始化這個變數使用一個標準的數值集, 它拷貝自 tty_std_termios 變數. tty_std_termos 在 tty 核心被定義為:

struct termios tty_std_termios = {
 .c_iflag = ICRNL | IXON,
 .c_oflag = OPOST | ONLCR,
 .c_cflag = B38400 | CS8 | CREAD | HUPCL,
 .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
 ECHOCTL | ECHOKE | IEXTEN,
 .c_cc = INIT_C_CC
};這個 struct termios 結構用來持有所有的當前線路設定, 給這個 tty 裝置的一個特定埠. 這些線路設定控制當前波特率, 資料大小, 資料流控設定, 以及許多其他值. 三、成員的值(一)c_iflag 標誌常量:Input mode ( 輸入模式) input mode可以在輸入值傳給程式之前控制其處理的方式。其中輸入值可能是由序列埠或鍵盤的終端驅動程式所接收到的字元。   我們可以利用termios結構的c_iflag的標誌來加以控制,其定義的方式皆以OR來加以組合。    
IGNBRK :忽略輸入中的 BREAK 狀態。 (忽略命令列中的中斷) 
BRKINT :(命令列出現中斷時,可產生一插斷)如果設定了 IGNBRK,將忽略 BREAK。如果沒有設定,但是設定了 BRKINT,那麼 BREAK 將使得輸入和輸出佇列被重新整理,如果終端是一個前臺程序組的控制終端,這個程序組中所有程序將收到 SIGINT 訊號。如果既未設定 IGNBRK 也未設定 BRKINT,BREAK 將視為與 NUL 字元同義,除非設定了 PARMRK,這種情況下它被視為序列 377 � �。  
IGNPAR :忽略楨錯誤和奇偶校驗錯。  
PARMRK :如果沒有設定 IGNPAR,在有奇偶校驗錯或楨錯誤的字元前插入 377 �。如果既沒有設定 IGNPAR 也沒有設定 PARMRK,將有奇偶校驗錯或楨錯誤的字元視為 �。  
INPCK :啟用輸入奇偶檢測。  
ISTRIP :去掉第八位。  
INLCR :將輸入中的 NL 翻譯為 CR。(將收到的換行符號轉換為Return)  
IGNCR :忽略輸入中的回車。  
ICRNL :將輸入中的回車翻譯為新行 (除非設定了 IGNCR)(否則當輸入訊號有 CR 時不會終止輸入)。  
IUCLC :(不屬於 POSIX) 將輸入中的大寫字母對映為小寫字母。  
IXON :啟用輸出的 XON/XOFF 流控制。   
IXANY :(不屬於 POSIX.1;XSI) 允許任何字元來重新開始輸出。(?)  
IXOFF :啟用輸入的 XON/XOFF 流控制。  
IMAXBEL:(不屬於 POSIX) 當輸入佇列滿時響零。Linux 沒有實現這一位,總是將它視為已設定。  
(二) c_oflag 標誌常量:Output mode ( 輸出模式)

Output mode主要負責控制輸出字元的處理方式。輸出字元在傳送到序列埠或顯示器之前是如何被程式來處理。

輸出模式是利用termios結構的c_oflag的標誌來加以控制,其定義的方式皆以OR來加以組合。

  
OPOST :啟用具體實現自行定義的輸出處理。  
OLCUC :(不屬於 POSIX) 將輸出中的小寫字母對映為大寫字母。  
ONLCR :(XSI) 將輸出中的新行符對映為回車-換行。  
OCRNL :將輸出中的回車對映為新行符  
ONOCR :不在第 0 列輸出回車。  
ONLRET :不輸出回車。  
OFILL :傳送填充字元作為延時,而不是使用定時來延時。  
OFDEL :(不屬於 POSIX) 填充字元是 ASCII DEL (0177)。如果不設定,填充字元則是 ASCII NUL。  
NLDLY :新行延時掩碼。取值為 NL0 和 NL1。  
CRDLY :回車延時掩碼。取值為 CR0, CR1, CR2, 或 CR3。  
TABDLY :水平跳格延時掩碼。取值為 TAB0, TAB1, TAB2, TAB3 (或 XTABS)。取值為 TAB3,即 XTABS,將擴充套件跳格為空格 (每個跳格符填充 8 個空格)。(?)  
BSDLY :回退延時掩碼。取值為 BS0 或 BS1。(從來沒有被實現過)  
VTDLY :豎直跳格延時掩碼。取值為 VT0 或 VT1。  
FFDLY :進表延時掩碼。取值為 FF0 或 FF1。 
(三)c_cflag 標誌常量:Control mode ( 控制模式)

Control mode主要用於控制終端裝置的硬體設定。利用termios結構的c_cflag的標誌來加以控制。控制模式用在序列線連線到資料裝置,也可以用在與終端裝置的交談。

一般來說,改變終端裝置的組態要比使用termios的控制模式來改變行(lines)的行為來得容易。

  
CBAUD :(不屬於 POSIX) 波特率掩碼 (4+1 位)。  
CBAUDEX :(不屬於 POSIX) 擴充套件的波特率掩碼 (1 位),包含在 CBAUD 中。  
(POSIX 規定波特率儲存在 termios 結構中,並未精確指定它的位置,而是提供了函式 cfgetispeed() 和 cfsetispeed() 來存取它。一些系統使用 c_cflag 中 CBAUD 選擇的位,其他系統使用單獨的變數,例如 sg_ispeed 和 sg_ospeed 。)  
CSIZE:字元長度掩碼(傳送或接收字元時用的位數)。取值為 CS5(傳送或接收字元時用5bits), CS6, CS7, 或 CS8。  
CSTOPB :設定兩個停止位,而不是一個。  
CREAD :開啟接受者。  
PARENB :允許輸出產生奇偶資訊以及輸入的奇偶校驗(啟用同位產生與偵測)。  
PARODD :輸入和輸出是奇校驗(使用奇同位而非偶同位)。  
HUPCL :在最後一個程序關閉裝置後,降低 modem 控制線 (結束通話)。(?)  
CLOCAL :忽略 modem 控制線。  
LOBLK :(不屬於 POSIX) 從非當前 shell 層阻塞輸出(用於 shl )。(?)  
CIBAUD :(不屬於 POSIX) 輸入速度的掩碼。CIBAUD 各位的值與 CBAUD 各位相同,左移了 IBSHIFT 位。  
CRTSCTS :(不屬於 POSIX) 啟用 RTS/CTS (硬體) 流控制。

(四)c_lflag 標誌常量:Local mode ( 區域性模式)
Local mode主要用來控制終端裝置不同的特色。利用termios結構裡的c_lflag的標誌來設定區域性模式。
在巨集中有兩個比較重要的標誌:
1.ECHO:它可以讓你阻止鍵入字元的迴應。
2.ICANON(正規模式)標誌,它可以對所接收的字元在兩種不同的終端裝置模式之間來回切換。 
ISIG:當接受到字元 INTR, QUIT, SUSP, 或 DSUSP 時,產生相應的訊號。  
ICANON:啟用標準模式 (canonical mode)。允許使用特殊字元 EOF, EOL, EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, 和 WERASE,以及按行的緩衝。  
XCASE:(不屬於 POSIX; Linux 下不被支援) 如果同時設定了 ICANON,終端只有大寫。輸入被轉換為小寫,除了有字首的字元。輸出時,大寫字元被字首(某些系統指定的特定字元) ,小寫字元被轉換成大寫。  
ECHO :回顯輸入字元。  
ECHOE :如果同時設定了 ICANON,字元 ERASE 擦除前一個輸入字元,WERASE 擦除前一個詞。  
ECHOK :如果同時設定了 ICANON,字元 KILL 刪除當前行。  
ECHONL :如果同時設定了 ICANON,回顯字元 NL,即使沒有設定 ECHO。  
ECHOCTL :(不屬於 POSIX) 如果同時設定了 ECHO,除了 TAB, NL, START, 和 STOP 之外的 ASCII 控制訊號被回顯為 ^X, 這裡 X 是比控制訊號大 0x40 的 ASCII 碼。例如,字元 0x08 (BS) 被回顯為 ^H。  
ECHOPRT :(不屬於 POSIX) 如果同時設定了 ICANON 和 IECHO,字元在刪除的同時被列印。  
ECHOKE :(不屬於 POSIX) 如果同時設定了 ICANON,回顯 KILL 時將刪除一行中的每個字元,如同指定了 ECHOE 和 ECHOPRT 一樣。  
DEFECHO :(不屬於 POSIX) 只在一個程序讀的時候回顯。  
FLUSHO :(不屬於 POSIX; Linux 下不被支援) 輸出被重新整理。這個標誌可以通過鍵入字元 DISCARD 來開關。  
NOFLSH :禁止在產生 SIGINT, SIGQUIT 和 SIGSUSP 訊號時重新整理輸入和輸出佇列,即關閉queue中的flush。  
TOSTOP :向試圖寫控制終端的後臺程序組傳送 SIGTTOU 訊號(傳送欲寫入的資訊到後臺處理)。  
PENDIN :(不屬於 POSIX; Linux 下不被支援) 在讀入下一個字元時,輸入佇列中所有字元被重新輸出。(bash 用它來處理 typeahead)  
IEXTEN :啟用實現自定義的輸入處理。這個標誌必須與 ICANON 同時使用,才能解釋特殊字元 EOL2,LNEXT,REPRINT 和 WERASE,IUCLC 標誌才有效。  
(五)c_cc 陣列:特殊控制字元

可提供使用者設定一些特殊的功能, 如Ctrl+C的字元組合。特殊控制字元主要是利用termios結構裡c_cc的陣列成員來做設定。
c_cc陣列主要用於正規與非正規兩種環境,但要注意的是正規與非正規不可混為一談。
其定義了特殊的控制字元。符號下標 (初始值) 和意義為:

VINTR:(003, ETX, Ctrl-C, or also 0177, DEL, rubout) 中斷字元。發出 SIGINT 訊號。當設定 ISIG 時可被識別,不再作為輸入傳遞。  
VQUIT :(034, FS, Ctrl-) 退出字元。發出 SIGQUIT 訊號。當設定 ISIG 時可被識別,不再作為輸入傳遞。  
VERASE :(0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) 刪除字元。刪除上一個還沒有刪掉的字元,但不刪除上一個 EOF 或行首。當設定 ICANON 時可被識別,不再作為輸入傳遞。  
VKILL :(025, NAK, Ctrl-U, or Ctrl-X, or also @) 終止字元。刪除自上一個 EOF 或行首以來的輸入。當設定 ICANON 時可被識別,不再作為輸入傳遞。  
VEOF :(004, EOT, Ctrl-D) 檔案尾字元。更精確地說,這個字元使得 tty 緩衝中的內容被送到等待輸入的使用者程式中,而不必等到 EOL。如果它是一行的第一個字元,那麼使用者程式的 read() 將返回 0,指示讀到了 EOF。當設定 ICANON 時可被識別,不再作為輸入傳遞。  
VMIN :非 canonical 模式讀的最小字元數(MIN主要是表示能滿足read的最小字元數)。  
VEOL :(0, NUL) 附加的行尾字元。當設定 ICANON 時可被識別。  
VTIME :非 canonical 模式讀時的延時,以十分之一秒為單位。  
VEOL2 :(not in POSIX; 0, NUL) 另一個行尾字元。當設定 ICANON 時可被識別。  
VSWTCH :(not in POSIX; not supported under Linux; 0, NUL) 開關字元。(只為 shl 所用。)  
VSTART :(021, DC1, Ctrl-Q) 開始字元。重新開始被 Stop 字元中止的輸出。當設定 IXON 時可被識別,不再作為輸入傳遞。  
VSTOP :(023, DC3, Ctrl-S) 停止字元。停止輸出,直到鍵入 Start 字元。當設定 IXON 時可被識別,不再作為輸入傳遞。  
VSUSP :(032, SUB, Ctrl-Z) 掛起字元。傳送 SIGTSTP 訊號。當設定 ISIG 時可被識別,不再作為輸入傳遞。  
VDSUSP :(not in POSIX; not supported under Linux; 031, EM, Ctrl-Y) 延時掛起訊號。當用戶程式讀到這個字元時,傳送 SIGTSTP 訊號。當設定 IEXTEN 和 ISIG,並且系統支援作業管理時可被識別,不再作為輸入傳遞。  
VLNEXT :(not in POSIX; 026, SYN, Ctrl-V) 字面上的下一個。引用下一個輸入字元,取消它的任何特殊含義。當設定 IEXTEN 時可被識別,不再作為輸入傳遞。  
VWERASE :(not in POSIX; 027, ETB, Ctrl-W) 刪除詞。當設定 ICANON 和 IEXTEN 時可被識別,不再作為輸入傳遞。  
VREPRINT :(not in POSIX; 022, DC2, Ctrl-R) 重新輸出未讀的字元。當設定 ICANON 和 IEXTEN 時可被識別,不再作為輸入傳遞。  
VDISCARD :(not in POSIX; not supported under Linux; 017, SI, Ctrl-O) 開關:開始/結束丟棄未完成的輸出。當設定 IEXTEN 時可被識別,不再作為輸入傳遞。  
VSTATUS :(not in POSIX; not supported under Linux; status request: 024, DC4, Ctrl-T).  
這些符號下標值是互不相同的,除了 VTIME,VMIN 的值可能分別與 VEOL,VEOF 相同。 (在 non-canonical 模式下,特殊字元的含義更改為延時含義。MIN 表示應當被讀入的最小字元數。TIME 是以十分之一秒為單位的計時器。如果同時設定了它們,read 將等待直到至少讀入一個字元,一旦讀入 MIN 個字元或者從上次讀入字元開始經過了 TIME 時間就立即返回。如果只設置了 MIN,read 在讀入 MIN 個字元之前不會返回。如果只設置了 TIME,read 將在至少讀入一個字元,或者計時器超時的時候立即返回。如果都沒有設定,read 將立即返回,只給出當前準備好的字元。) 
 MIN與TIME組合有以下四種:

1、 MIN = 0 , TIME =0
              有READ立即回傳
              否則傳回 0 ,不讀取任何字元
2、 MIN = 0 , TIME >0
              READ 傳回讀到的字元,或在十分之一秒後傳回TIME
       若來不及讀到任何字元,則傳回0
3、 MIN > 0 , TIME =0
              READ 會等待,直到MIN字元可讀
4、 MIN > 0 , TIME > 0
              每一格字元之間計時器即會被啟動
              READ 會在讀到MIN字元,傳回值或TIME的字元計時(1/10秒)超過時將值傳回
四、與此結構體相關的函式
(一)tcgetattr()
1.原型
int tcgetattr(int fd,struct termois & termios_p);
2.功能 
取得終端介質(fd)初始值,並把其值 賦給temios_p;函式可以從後臺程序中呼叫;但是,終端屬性可能被後來的前臺程序所改變。


(二)tcsetattr() 
1.原型
int tcsetattr(int fd,int actions,const struct    termios *termios_p);
2.功能
設定與終端相關的引數 (除非需要底層支援卻無法滿足),使用 termios_p 引用的 termios 結構。optional_actions (tcsetattr函式的第二個引數)指定了什麼時候改變會起作用: 
TCSANOW:改變立即發生  
TCSADRAIN:改變在所有寫入 fd 的輸出都被傳輸後生效。這個函式應當用於修改影響輸出的引數時使用。(當前輸出完成時將值改變)  
TCSAFLUSH :改變在所有寫入 fd 引用的物件的輸出都被傳輸後生效,所有已接受但未讀入的輸入都在改變發生前丟棄(同TCSADRAIN,但會捨棄當前所有值)。  
(三)tcsendbreak()
  傳送連續的 0 值位元流,持續一段時間,如果終端使用非同步序列資料傳輸的話。如果 duration 是 0,它至少傳輸 0.25 秒,不會超過 0.5 秒。如果 duration 非零,它傳送的時間長度由實現定義。 
如果終端並非使用非同步序列資料傳輸,tcsendbreak() 什麼都不做。 
(四)tcdrain() 
等待直到所有寫入 fd 引用的物件的輸出都被傳輸。 
(五)tcflush() 
丟棄要寫入 引用的物件,但是尚未傳輸的資料,或者收到但是尚未讀取的資料,取決於 queue_selector 的值:

TCIFLUSH :重新整理收到的資料但是不讀  
TCOFLUSH :重新整理寫入的資料但是不傳送  
TCIOFLUSH :同時重新整理收到的資料但是不讀,並且重新整理寫入的資料但是不傳送  
(六)tcflow() 
掛起 fd 引用的物件上的資料傳輸或接收,取決於 action 的值:

TCOOFF :掛起輸出  
TCOON :重新開始被掛起的輸出  
TCIOFF :傳送一個 STOP 字元,停止終端裝置向系統傳送資料  
TCION :傳送一個 START 字元,使終端裝置向系統傳輸資料  
開啟一個終端裝置時的預設設定是輸入和輸出都沒有掛起。


(七)波特率函式 
被用來獲取和設定 termios 結構中,輸入和輸出波特率的值。新值不會馬上生效,直到成功呼叫了 tcsetattr() 函式。
設定速度為 B0 使得 modem "掛機"。與 B38400 相應的實際位元率可以用 setserial(8) 調整。 
輸入和輸出波特率被保存於 termios 結構中。 
cfmakeraw 設定終端屬性如下: 
            termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
            termios_p->c_oflag &= ~OPOST;
            termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
            termios_p->c_cflag &= ~(CSIZE|PARENB);
            termios_p->c_cflag |= CS8;

1.cfgetospeed() 返回 termios_p 指向的 termios 結構中儲存的輸出波特率 
2.cfsetospeed() 設定 termios_p 指向的 termios 結構中儲存的輸出波特率為 speed。取值必須是以下常量之一: 
        B0        B50        B75        B110        B134        B150        B200        B300        B600        B1200        B1800        B2400        B4800        B9600        B19200        B38400        B57600        B115200        B230400
其中:零值 B0 用來中斷連線。如果指定了 B0,不應當再假定存在連線。通常,這樣將斷開連線。CBAUDEX 是一個掩碼,指示高於 POSIX.1 定義的速度的那一些 (57600 及以上)。因此,B57600 & CBAUDEX 為非零。 
3.cfgetispeed() 返回 termios 結構中儲存的輸入波特率。 
4.cfsetispeed() 設定 termios 結構中儲存的輸入波特率為 speed。如果輸入波特率被設為0,實際輸入波特率將等於輸出波特率。 
五、RETURN VALUE 返回值
1.cfgetispeed() 返回 termios 結構中儲存的輸入波特率。 
2.cfgetospeed() 返回 termios 結構中儲存的輸出波特率。 
3.其他函式返回: 
  (1)0:成功 
   (2)-1:失敗,
         並且為 errno 置值來指示錯誤。 
注意 tcsetattr() 返回成功,如果任何所要求的修改可以實現的話。因此,當進行多重修改時,應當在這個函式之後再次呼叫 tcgetattr() 來檢測是否所有修改都成功實現。 
六、NOTES 注意
Unix V7 以及很多後來的系統有一個波特率的列表,在十四個值 B0, ..., B9600 之後可以看到兩個常數 EXTA, EXTB ("External A" and "External B")。很多系統將這個列表擴充套件為更高的波特率。 
tcsendbreak 中非零的 duration 有不同的效果。SunOS 指定中斷 duration*N 秒,其中 N 至少為 0.25,不高於 0.5 。Linux, AIX, DU, Tru64 傳送 duration 微秒的 break 。FreeBSD, NetBSD, HP-UX 以及 MacOS 忽略 duration 的值。在 Solaris 和 Unixware 中, tcsendbreak 搭配非零的 duration 效果類似於 tcdrain。 
SEE ALSO 參見

stty(1), setserial(8)