2011年9月30日

Serial Programming(step 0:馬桶蓋)

好文章-講解set與get周邊device的原理

引用:http://www.programmer-club.com.tw/showsametitleN/c/39077.html


從 serial programming HOWTO 這份文件中讓我可以透過RS232 使得兩台電腦互相溝通,
但其中有一些不解的地方,想請各位幫我解答.
以下次一個完整的非標準的接收程式(serial programming HOWTO 中的範例)
其中有疑問的利用註解方式標示出來//???????????????????????????????????????????????????

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>


#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define false 0
#define true 1
volatile int STOP=false;


main()
{
    int fd,c, res;
    struct termios oldtio,newtio;//?????????????????????????????????????????????????????
    char buf[255];


    fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
    if (fd <0) {perror(MODEMDEVICE); exit(−1); }
    tcgetattr(fd,&oldtio); /* save current port settings *//???????????????????????????????????
    bzero(&newtio, sizeof(newtio));
    newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
    newtio.c_iflag = IGNPAR;
    newtio.c_oflag = 0;
    /* set input mode (non−canonical, no echo,...) */
    newtio.c_lflag = 0;
    newtio.c_cc[VTIME] = 0; /* inter−character timer unused */
    newtio.c_cc[VMIN] = 5; /* blocking read until 5 chars received */
    tcflush(fd, TCIFLUSH);
    tcsetattr(fd,TCSANOW,&newtio);//?????????????????????????????????????????????????????
    while (STOP==false) { /* loop for input */
     res = read(fd,buf,255); /* returns after 5 chars have been input */
     buf[res]=0; /* so we can printf... */
     printf(":%s:%d\n", buf, res);
     if (buf[0]=='z') STOP=true;
    }
    tcsetattr(fd,TCSANOW,&oldtio);//??????????????????????????????????????????????????????
}





對於以上有//???????????????????的那幾行 我存在的主要疑問就是
為什麼要宣告兩個struct termios oldtio,newtio
事有什麼特別用途嗎? 是要備份嗎? 還是有其他原因呢?







答案其實很簡單,一個是 ..get..、另一個是..set..,也就是取得跟設定罷了。
當應用程式在存取周邊設備時,程式設計師必須記得一件事情,那就是各項周邊(通常來說)應該是大家共用的,當然,有時候會因系統架構上的特殊考量,出現讓某一個程式獨佔某一個周邊的情形,但這算是特例。讀過OS相關書籍的人應該會明白,其實作業系統的其中一項重要工作,就是讓所有周邊能夠開放給所有應用程式,但這是題外話,所以就此打住。
既然周邊是共用的,那麼當我需要使用時,我該怎麼做呢?這就像馬桶蓋的學問....???
男生宿舍的廁所裡,馬桶座通常都是翻起來的,為什麼?...這應該不用我說明;相反的,女生廁所的馬桶座通常都是保持放下的狀態,這也不需要我說明。如果你進入某人家的廁所,不論其馬桶座是處於何種狀態,以禮貌性來說,回復最初的位置,就是最好的策略!所以你在使用前,必須先記住它的位置(翻起或放下),然後才開始使用(可能是翻起或放下),完成後,再回復最早的狀態就行了。重點是,如果你一開始沒有先留意它的狀態,你就不知道該如何回復,這就可能要被主人白眼了!當然,好朋友可能不會在乎這種小事情,可是在程式運作上,卻會出現大災難喔!
除非你是很古老的程式人,否則你應該沒有機會在單人單工的環境下寫程式(Embedded System除外)。現代的程式設計幾乎都是在多工的假設下發展的,這意味著,同一時間會有很多程式在運行。當然,在單一CPU的電腦系統,一個時間只能服務一個行程(process/thread),但其他因呼叫IPC服務而處於Waiting/Blocking、或被 preemption 而 Suspend 的行程,仍可視為同時執行的個體,在這種情況下,你如果沒有適當地回復(周邊設備)先前的狀態,那麼另一個被停格(被點穴不能動)但回復運作(解穴)的程式就倒楣了!你能想像你放下馬桶座,一屁股坐下去,馬桶座竟然是翻起來的狀況嗎?你的反應會是........好涼喔~~~嗎?
周邊設備在使用前必須先設定參數,以RS232為例,你必須設定 Baud/Data/Stop/Parity等,一旦設定後,這些數值會儲存在周邊的控制暫存器裡,前述的 get 就是先取得目前暫存器的內容,再用 get 來設定你所需的,最後再用一次 get 來寫回原來的內容。
Good Luck.

沒有留言:

張貼留言

NO-CARRIER 網卡無法啟動

 工作時,由於想要啟動linux OS的網卡, 發現某張新設定的網卡一直無法啟動,就算下指令UP了,但是也沒有順利啟動 所以爬文後,想要確認該網卡的status, 發現某行為: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu...