說明
:armcomtest 是友善之臂爲了方便測試而開發的linux 下的簡易實用串口終端程
序,它使用標準的系統調用,和硬件無關。通常Linux 系統系統啓動後,串口 0,1,2對應的設
備名分別爲
/dev/ttySAC0,1,2,3
測試串口2 須要藉助另外一臺帶有串口的PC
,鏈接好 COM2 和另外一臺PC的串口,並設置該PC的超級終端爲波特率115200 ,
無流控制,其餘默認。
在命令行下輸入:
#
armcomtest –d /dev/ttySAC1 - o
這時若是輸入字符會在另外一臺PC的超級終端出現,反之亦然。
若是要測試串口3,則須要鏈接擴展小板的COM3 ,並在命令行輸入:
#
armcomtest –d /dev/ttySAC2 - o
# include <stdio.h>
# include <stdlib.h>
# include <termio.h>
# include <unistd.h>
# include <fcntl.h>
# include <getopt.h>
# include <time.h>
# include <errno.h>
# include <string.h>
static void Error(const char *Msg)
{
fprintf (stderr, "%s\n", Msg);
fprintf (stderr, "strerror() is %s\n", strerror(errno));
exit(1);
}
static void Warning(const char *Msg)
{
fprintf (stderr, "Warning: %s\n", Msg);
}
static int SerialSpeed(const char *SpeedString) //波特率選擇
{
int SpeedNumber = atoi(SpeedString);
# define TestSpeed(Speed) if (SpeedNumber == Speed) return B##Speed
TestSpeed(1200);
TestSpeed(2400);
TestSpeed(4800);
TestSpeed(9600);
TestSpeed(19200);
TestSpeed(38400);
TestSpeed(57600);
TestSpeed(115200);
TestSpeed(230400);
Error("Bad speed");
return -1;
}
static void PrintUsage(void) //打印消息
{
fprintf(stderr, "comtest - interactive program of comm port\n");
fprintf(stderr, "press [ESC] 3 times to quit\n\n");
fprintf(stderr, "Usage: comtest [-d device] [-t tty] [-s speed] [-7] [-c] [-x] [-o] [-h]\n");
fprintf(stderr, " -7 7 bit\n");
fprintf(stderr, " -x hex mode\n");
fprintf(stderr, " -o output to stdout too\n");
fprintf(stderr, " -c stdout output use color\n");
fprintf(stderr, " -h print this help\n");
exit(-1);
}
static inline void WaitFdWriteable(int Fd)
/*
相似於一種宏定義
這種宏定義在形式上相似於一個函數,
但在使用它時,僅僅只是作預處理器符號表中的簡單替換,
所以它不能進行參數有效性的檢測,
也就不能享受C++編譯器嚴格類型檢查的好處,
另外它的返回值也不能被強制轉換爲可轉換的合適的類型,
這樣,它的使用就存在着一系列的隱患和侷限性。
*/
{
fd_set WriteSetFD;
FD_ZERO(&WriteSetFD);
FD_SET(Fd, &WriteSetFD);
if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) < 0) {
Error(strerror(errno));
} //select用來監控
}
int main(int argc, char **argv)
{
int CommFd, TtyFd;
struct termios TtyAttr;
struct termios BackupTtyAttr;
int DeviceSpeed = B115200;
int TtySpeed = B115200;
int ByteBits = CS8;
const char *DeviceName = "/dev/ttyS0";
const char *TtyName = "/dev/tty";
int OutputHex = 0;
int OutputToStdout = 0;
int UseColor = 0;
opterr = 0;
for (;;) {
int c = getopt(argc, argv, "d:s:t:7xoch");
/*
函數說明 getopt()用來分析命令行參數。
參數argc和argv是由main()傳遞的參數個數和內容。
參數optstring 則表明欲處理的選項字符串。
此函數會返回在argv 中下一個的選項字母,
此字母會對應參數optstring 中的字母。
若是選項字符串裏的字母后接着冒號「:」,
則表示還有相關的參數,全域變量optarg
即會指向此額外參數。若是getopt()
找不到符合的參數則會印出錯信息,
並將全域變量optopt設爲「?」字符,
若是不但願getopt()印出錯信息,
則只要將全域變量opterr設爲0便可。
*/
if (c == -1)
break;
switch(c) {
case 'd':
DeviceName = optarg;
break;
case 't':
TtyName = optarg;
break;
case 's':
if (optarg[0] == 'd') {
DeviceSpeed = SerialSpeed(optarg + 1);
} else if (optarg[0] == 't') {
TtySpeed = SerialSpeed(optarg + 1);
} else
TtySpeed = DeviceSpeed = SerialSpeed(optarg);
break;
case 'o':
OutputToStdout = 1;
break;
case '7':
ByteBits = CS7;
break;
case 'x':
OutputHex = 1;
break;
case 'c':
UseColor = 1;
break;
case '?':
case 'h':
default:
PrintUsage();
}
}
if (optind != argc)
PrintUsage();//打印消息
CommFd = open(DeviceName, O_RDWR, 0);
if (CommFd < 0)
Error("Unable to open device");
if (fcntl(CommFd, F_SETFL, O_NONBLOCK) < 0)
Error("Unable set to NONBLOCK mode");
/*
F_SETFL 設置文件描述詞狀態旗標,
參數arg爲新旗標,但只容許O_APPEND、
O_NONBLOCK和O_ASYNC位的改變,其餘位的改變將不受影響。
O_NONBLOCK 若是路徑名指向 FIFO/塊文件/字符文件,則把文件的打開和後繼 I/O
*/
memset(&TtyAttr, 0, sizeof(struct termios));
/*
函數原型 void *memset(void *s, int ch, unsigned n);
將s所指向的某一塊內存中的每一個字節的內容所有設置爲ch指定的ASCII值,
塊的大小由第三個參數指定,這個函數一般爲新申請的內存作初始化工做,
其返回值爲指向S的指針。
將TtyAttr 所指向的內存區域的值所有設置爲0 的Ascii值
*/
//設置串口的一些參數
TtyAttr.c_iflag = IGNPAR; //IGNPAR 忽略奇偶校驗錯誤
//c_iflag:輸入模式標誌,控制終端輸入方式,具體參數如表6.3所示。
TtyAttr.c_cflag = DeviceSpeed | HUPCL | ByteBits | CREAD | CLOCAL;
//CREAD 使用接收器 HUPCL 關閉設備時掛起 CLOCAL 忽略調制解調器線路狀態
//c_cflag:控制模式標誌,指定終端硬件控制信息,具體參數如表6.5所示。
TtyAttr.c_cc[VMIN] = 1; //VMIN 非規範模式讀取時的最小字符數
//c_cc[NCCS]:控制字符,用於保存終端驅動程序中的特殊字符,
//如輸入結束符等。c_cc中定義瞭如表6.7所示的控制字符。
if (tcsetattr(CommFd, TCSANOW, &TtyAttr) < 0)
Warning("Unable to set comm port");
/*
爲了使程序控制終端參數,
在標準庫中POSIX須要幾個函數,
最重要的兩個函數爲tcsetattr和tcgetattr。
tcgetattr取回一個如圖3-34中顯示的數據結構的一份拷貝,
該結構爲termios,它包含用來改變特殊字符、
設置模式和修改終端其餘特性的全部信息。
程序能夠檢查當前的設置,
當須要時對這些設置進行修改,
而後調用tcsetattr把這個結構寫回終端任務中。
頭文件
<termios.h>
<unistd.h>
函數形式
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
*/
TtyFd = open(TtyName, O_RDWR | O_NDELAY, 0); //ndelay 自我解釋應該是延時的意思
if (TtyFd < 0)
Error("Unable to open tty");
TtyAttr.c_cflag = TtySpeed | HUPCL | ByteBits | CREAD | CLOCAL;
if (tcgetattr(TtyFd, &BackupTtyAttr) < 0)
Error("Unable to get tty");
//BackupTtyAttr 用於存儲得到的終端參數信息
if (tcsetattr(TtyFd, TCSANOW, &TtyAttr) < 0)
//使用tcsetattr函數將修改後的終端參數設置到標準輸入中
Error("Unable to set tty");
for (;;) {
unsigned char Char = 0;
fd_set ReadSetFD;
void OutputStdChar(FILE *File)
{
char Buffer[10];
int Len = sprintf(Buffer, OutputHex ? "%.2X " : "%c", Char);
fwrite(Buffer, 1, Len, File);
}
/*
int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);
參數maxfd是須要監視的最大的文件描述符值+1;rdset,wrset,exset分別對應於須要檢測的可讀文件描述符的集合,
可寫文件描述符的集 合及異常文件描述符的集合。struct timeval結構用於描述一段時間長度,若是在這個時間內,
須要監視的描述符沒有事件發生則函數返回,返回值爲0。
fd_set(它比較重要因此先介紹一下)是一組文件描述字(fd)的集合,
它用一位來表示一個fd(下面會仔細介紹),對於fd_set類型經過下面四個宏來操做:
FD_ZERO(fd_set *fdset);將指定的文件描述符集清空,
在對文件描述符集合進行設置前,必須對其進行初始化,若是不清空,
因爲在系統分配內存空間後,一般並不做清空處理,因此結果是不可知的。
FD_SET(fd_set *fdset);用於在文件描述符集合中增長一個新的文件描述符。
FD_CLR(fd_set *fdset);用於在文件描述符集合中刪除一個文件描述符。
FD_ISSET(int fd,fd_set *fdset);用於測試指定的文件描述符是否在該集合中。
過去,一個fd_set一般只能包含<32的fd(文件描述字),
由於fd_set其實只用了一個32位矢量來表示fd;如今,
UNIX系統一般會在頭文件<sys/select.h>中定義常量FD_SETSIZE,
它是數據類型fd_set的描述字數量,其值一般是1024,這樣就能表示<1024的fd。
根據fd_set的位矢量實現,咱們能夠從新理解操做fd_set的四個宏:
fd_set set;
FD_ZERO(&set);
FD_SET(0, &set);
FD_CLR(4, &set);
FD_ISSET(5, &set);
*/
FD_ZERO(&ReadSetFD);
FD_SET(CommFd, &ReadSetFD);
FD_SET( TtyFd, &ReadSetFD);
# define max(x,y) ( ((x) >= (y)) ? (x) : (y) )
if (select(max(CommFd, TtyFd) + 1, &ReadSetFD, NULL, NULL, NULL) < 0) {
Error(strerror(errno));
//檢測可讀的文件的文件描述符的集合
}
# undef max
if (FD_ISSET(CommFd, &ReadSetFD)) {
/*
int FD_ISSET(int fd,fd_set *fdset)
宏說明:在調用select()函數後,用FD_ISSET來檢測fdset中文件fd有無發生變化
*/
while (read(CommFd, &Char, 1) == 1) {
WaitFdWriteable(TtyFd);
//監控TtyFd這個文件描述符中是否有數據發生變化
//這個函數在上面有定義
// ssize_t write (int fd,const void * buf,size_t count);
//write()會把參數buf所指的內存寫入count個字節到參數fd所指的文件內。
//固然,文件讀寫位置也會隨之移動。
if (write(TtyFd, &Char, 1) < 0) {
Error(strerror(errno));
}
//若是用到了-O的屬性 OutputTostdout 就會變成1就會輸出下面的信息
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[01;34m", 1, 8, stdout);
OutputStdChar(stdout);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stdout);
fflush(stdout);
}
}
}
if (FD_ISSET(TtyFd, &ReadSetFD)) {
while (read(TtyFd, &Char, 1) == 1) {
static int EscKeyCount = 0;
WaitFdWriteable(CommFd);
if (write(CommFd, &Char, 1) < 0) {
Error(strerror(errno));
}
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[01;31m", 1, 8, stderr);
OutputStdChar(stderr);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stderr);
fflush(stderr);
}
if (Char == '\x1b') {
EscKeyCount ++;
if (EscKeyCount >= 3)
goto ExitLabel;
// 跳出到退出label
} else
EscKeyCount = 0;
}
}
}
ExitLabel:
if (tcsetattr(TtyFd, TCSANOW, &BackupTtyAttr) < 0)
Error("Unable to set tty");
return 0;
另外一種解析
/*************************************************************************** ** 文件: comtest.c ** 描述: ** 以串口通信的測試程序 ** **------------------------------------------------------------------------------------------------------ ********************************************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> /*標準輸入輸出定義*/ #include <stdlib.h> /*標準函數庫定義*/ #include <termio.h> /*PPSIX 終端控制定義*/ #include <unistd.h>/*Unix 標準函數定義,使用exit()*/ #include <fcntl.h>/*文件控制定義*/ #include <getopt.h>/*參數提取定義*/ #include <time.h> #include <errno.h>/*錯誤號定義*/ #include <string.h> #include <assert.h> int OutputHex = 0;//是否以十六進制發送。OutputHex爲1時,以十六進制發送;爲0,以字符串方式發送 int OutputToStdout = 0;//是否將消息一樣發送一份到標準輸出。爲1時,發送;爲0,不發送 int UseColor = 0; //是否使用顏色。爲1時,使用顏色;爲0,不使用顏色。 struct termios BackupTtyAttr;//終端屬性的備份 int IsWrite=0; static void Error(const char *Msg) { fprintf (stderr, "%s\n", Msg); fprintf (stderr, "strerror() is %s\n", strerror(errno)); exit(EXIT_FAILURE); } static void Warning(const char *Msg) { fprintf (stderr, "Warning: %s\n", Msg); } static int SerialSpeed(const char *SpeedString) { int SpeedNumber = atoi(SpeedString); # define TestSpeed(Speed) if (SpeedNumber == Speed) return B##Speed TestSpeed(1200); TestSpeed(2400); TestSpeed(4800); TestSpeed(9600); TestSpeed(19200); TestSpeed(38400); TestSpeed(57600); TestSpeed(115200); TestSpeed(230400); Error("Bad speed"); return -1; } /** *@brief 打印錯誤信息 */ static void PrintUsage(void) { fprintf(stderr, "comtest - interactive program of comm port\n"); fprintf(stderr, "press [ESC] 3 times to quit\n\n"); fprintf(stderr, "Usage: comtest [-d device] [-t tty] [-s speed] [-7] [-c] [-x] [-o] [-h]\n"); fprintf(stderr, " -7 7 bit\n"); fprintf(stderr, " -x hex mode\n"); fprintf(stderr, " -o output to stdout too\n"); fprintf(stderr, " -c stdout output use color\n"); fprintf(stderr, " -h print this help\n"); exit(-1); } /******************************************************************************************************* ** 函數: WaitFdWriteable, 等待文件可寫 **------------------------------------------------------------------------------------------------------ ** 參數: Fd 文件描述符 ** 返回: void ** 函數說明:使用inline標識符,防止由於函數頻繁的調用佔用大量的棧空間 ** 日期: 2013.06.19 ********************************************************************************************************/ static inline void WaitFdWriteable(int Fd) { fd_set WriteSetFD; //定義可寫的設備集合 FD_ZERO(&WriteSetFD);//將可寫的設備集合清空 FD_SET(Fd, &WriteSetFD);//將fd添加到可寫的設備集合中 //select函數原型: int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout); //值得說明的是:int maxfdp是一個整數值,是指須要測試的文件描述符的數目,測試的描述符範圍從0到nfds-1.即全部文件描述符的最大值加1,不能錯! if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) < 0) {//判斷是否有可寫的設備,若是沒有就一直阻塞,這裏沒有設置超時,若是沒有可寫的,會一直阻塞下去 //select函數中readfds、errorfds描述符集合都爲空,表示不進行測試 Error(strerror(errno)); } } void setAttrByArgvs(){ } /******************************************************************************************************* ** 函數: OutputStdChar, 打開一個串口 **------------------------------------------------------------------------------------------------------ ** 參數: FILE *File 文件描述符 int OutputHex,是否以十六進制發送。OutputHex爲1時,以十六進制發送;爲0,以字符串方式發送 unsigned char aCharToSend將要發送的字符 ** 返回: void ** ** 日期: 2013.06.19 ********************************************************************************************************/ void OutputStdChar(FILE *File,int OutputHex,unsigned char aCharToSend) {//向設備寫數據 char Buffer[10]; int Len = sprintf(Buffer, OutputHex ? "%.2X " : "%c", aCharToSend);//%.2X表示輸出01,02樣式的十六進制數 // int Len = sprintf(Buffer, 0x01);//%.2X表示輸出01,02樣式的十六進制數 fwrite(Buffer, 1, Len, File); } /******************************************************************************************************* ** 函數: SetFD, 設置文件描述符 **------------------------------------------------------------------------------------------------------ ** 參數:int argc char **argv int * CommFd 串口文件描述符 int * TtyFd 終端文件描述符 ** 返回: void **函數說明: **本函數經過對main函數的argc、argv進行參數的提取,實現對串口文件描述符(CommFd)和終 端文件描述符TtyFd的設置 ** 日期: 2013.06.19 ********************************************************************************************************/ void SetFD(int argc, char **argv,int * CommFd,int * TtyFd){ struct termios TtyAttr; //終端屬性 int DeviceSpeed = B2400; //串口波特率 int TtySpeed = B2400; //終端波特率 int ByteBits = CS8; //數據位:8位 const char *DeviceName = "/dev/ttySAC1";//串口設備名 const char *TtyName = "/dev/tty"; //終端設備名,防止重要的信息被用戶重定向 opterr = 0; printf("init........\n"); //經過Argc和Argv設置必要的參數 for (;;) { int c = getopt(argc, argv, "d:s:t:7xoch");//利用getopt將argv參數一個個提取出來 if (c == -1) break; switch(c) { case 'd'://設置串口的名稱 DeviceName = optarg; break; case 't'://設置終端的名稱 TtyName = optarg; break; case 's'://設置比特率 if (optarg[0] == 'd') {//設置串口的波特率 DeviceSpeed = SerialSpeed(optarg + 1); } else if (optarg[0] == 't') {//設置終端的波特率 TtySpeed = SerialSpeed(optarg + 1); } else TtySpeed = DeviceSpeed = SerialSpeed(optarg);//若是沒有帶d或t,直接將兩個設備的波特率設置成相同的 break; case 'o'://設置同時將消息向標準輸出(stdout)輸出 OutputToStdout = 1; break; case '7'://設置數據位爲7位 ByteBits = CS7; break; case 'x': OutputHex = 1;//以十六進制輸出 printf("OutputHex = 1\n"); break; case 'c'://使用顏色標記 UseColor = 1; break; case '?': case 'h': default: PrintUsage();//輸出main參數的說明 } }//end of for(;;) printf("end of getopt\n"); if (optind != argc)//判斷參數是否符合要求 PrintUsage(); //輸出main參數的說明 *CommFd = open(DeviceName, O_RDWR, 0);//以讀寫的方式打開 if (*CommFd < 0) Error("Unable to open device");//不能打開設備 if (fcntl(*CommFd, F_SETFL, O_NONBLOCK) < 0)//設置文件訪問模式爲非阻塞 Error("Unable set to NONBLOCK mode"); //不能使用NONBLOCK模式 memset(&TtyAttr, 0, sizeof(struct termios)); TtyAttr.c_iflag = IGNPAR;//忽略輸入行中的停止狀態 TtyAttr.c_cflag = DeviceSpeed | HUPCL | ByteBits | CREAD | CLOCAL;//DeviceSpeed: //HUPCL:關閉時掛斷調制解調器;CREAD:啓用字符接收器;CLOCAL:忽略全部調制解調器的狀態行 TtyAttr.c_cc[VMIN] = 1;//設置MIN值,read調用將一直等待,直到有MIN個字符可讀的時候才返回,返回是讀取的字符數量。到達文件結尾的時候返回0 if (tcsetattr(*CommFd, TCSANOW, &TtyAttr) < 0)//當即對屬性進行修改,不等當前輸出完成 Warning("Unable to set comm port"); *TtyFd = open(TtyName, O_RDWR | O_NDELAY, 0);//只有在CTEAT模式下,才須要第三個參數,這邊的第三個參數是沒有做用的。 if (*TtyFd < 0) Error("Unable to open tty"); TtyAttr.c_cflag = TtySpeed | HUPCL | ByteBits | CREAD | CLOCAL; if (tcgetattr(*TtyFd, &BackupTtyAttr) < 0)//將當前Tty的屬性備份在BackupTtyAttr,以便在程序退出時還原Tty的設置 Error("Unable to get tty"); if (tcsetattr(*TtyFd, TCSANOW, &TtyAttr) < 0) Error("Unable to set tty"); } /******************************************************************************************************* ** 函數: OutputCharUseColor 輸出帶顏色的字符 **------------------------------------------------------------------------------------------------------ ** 參數:char * colorCode 顏色代碼 unsigned char aChar 要輸出的字符 ** 返回: void ** 日期: 2013.06.19 ********************************************************************************************************/ void OutputCharUseColor(char * colorCode,unsigned char aChar){ if (OutputToStdout) { //同時向標準輸出寫消息 if (UseColor) fwrite(colorCode, 1, 8, stdout); OutputStdChar(stdout,OutputHex,aChar); if (UseColor) fwrite("\x1b[00m", 1, 8, stdout); fflush(stdout);//將stdout緩衝區中的數據當即輸出,即在屏幕上顯示 } } int uart_pthread(int argc, char **argv) { printf("into main\n"); int SendBufferIndex=0; char * SendBuffer=(char *)malloc(sizeof(char)*20);//發送緩存 /** TtyFD是爲了防止與用戶交互的信息被重定向,而沒有在屏幕上顯示。使用TtyFd能夠直接將 不想被重定向的信息直接向用戶終端(屏幕)輸出。 **/ int CommFd, TtyFd; //串口、終端描述符 SetFD( argc, argv,&CommFd,&TtyFd); for (;;) { unsigned char aCharToSend = 0; fd_set ReadSetFD; //可讀設備集合 FD_ZERO(&ReadSetFD); //清空可讀設備集合 FD_SET(CommFd, &ReadSetFD);//將串口加入可讀設備集合 FD_SET( TtyFd, &ReadSetFD);//將終端加入可讀設備集合 # define max(x,y) ( ((x) >= (y)) ? (x) : (y) )//最大值函數,返回兩個數中較大的數 if (select(max(CommFd, TtyFd) + 1, &ReadSetFD, NULL, NULL, NULL) < 0) {//同時測試串口和終端是否可讀 Error(strerror(errno)); } # undef max if (FD_ISSET(CommFd, &ReadSetFD)) {//判斷串口是否可讀 while (read(CommFd, &aCharToSend, 1) == 1) {//從串口中讀取一個char型,放在aCharToSend WaitFdWriteable(TtyFd);//會一直阻塞在這裏,直到終端設備可寫 if (write(TtyFd, &aCharToSend, 1) < 0) {//向屏幕輸出收到的字符 Error(strerror(errno)); //若是寫入錯誤,輸出錯誤信息 } OutputCharUseColor("\x1b[01;34m",aCharToSend); } } // printf("------INTO if (FD_ISSET(TtyFd, &ReadSetFD)) "); if (FD_ISSET(TtyFd, &ReadSetFD)) { //判斷終端是否可讀 while (read(TtyFd, &aCharToSend, 1) == 1) {//從終端中讀取一個值 // fprintf(stderr,"\n------SendBufferIndex:%d ",SendBufferIndex); SendBuffer[SendBufferIndex++]=aCharToSend; // fprintf(stderr, "\nRead From Tty"); static int EscKeyCount = 0; //按下Esc的次數 OutputCharUseColor("\x1b[01;31m",aCharToSend); if (aCharToSend == '\r') {//監測是否按下回車 SendBuffer[SendBufferIndex-1]='\0'; IsWrite=1; fprintf(stderr, "\x1b[01;34m you have enter :%s\n \x1b[00m",SendBuffer); // fprintf(stderr,"\n---11---IsWrite==%d ",IsWrite); } if(SendBufferIndex==19){ SendBuffer[SendBufferIndex]='\0'; // fprintf(stderr, "you have enter :%s\n",SendBuffer); IsWrite=1; } if(IsWrite==1){ // fprintf(stderr,"\n------WaitFdWriteable "); WaitFdWriteable(CommFd); if (write(CommFd, SendBuffer, SendBufferIndex) < 0) { Error(strerror(errno)); } IsWrite=0; SendBufferIndex=0; } if (aCharToSend == '\x1b') {//監測是否按下Esc fprintf(stderr, "EscKeyPressed\x1b\n"); EscKeyCount ++; if (EscKeyCount >= 3) goto ExitLabel; }else{ EscKeyCount = 0; } // fprintf(stderr,"\n---22---IsWrite==%d ",IsWrite); } } }//end of for (;;) ExitLabel: free(SendBuffer); if (tcsetattr(TtyFd, TCSANOW, &BackupTtyAttr) < 0)//恢復以前終端的設置 Error("Unable to set tty"); return 0; }