2011-07-13 29 views
2

該訪問信息是後續對這個問題:How to wait for input from the serial port in the middle of a program使用select(),並與fgets()從串口

我寫一個程序來控制,需要等待來自響應銥調制解調器串行端口在程序中間,以便驗證是否給出了正確的響應。爲了做到這一點,用戶建議我使用select()命令來等待這個輸入。

但是,我遇到了這種方法的一些困難。最初,select()會每次返回指示響應超時的值(即使調制解調器發回了正確的響應,我通過另一個同時運行的程序進行了驗證)。現在,程序在一次迭代後停止,即使從調制解調器發回正確的響應。

//setting the file descriptor to the port 
int fd = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); 

if (fd == -1) 
{ 
    /* 
    * Could not open the port. 
    */ 

    perror("open_port: Unable to open /dev/ttyS0 - "); 
} 
else 
fcntl(fd, F_SETFL, 0); 

FILE *out = fopen(portName.c_str(), "w");//sets the serial port 
FILE *in = fopen(portName.c_str(), "r"); 


fd_set fds; 
FD_ZERO(&fds); 
FD_SET(fd, &fds); 
struct timeval timeout = { 10, 0 }; /* 10 seconds */ 
//int ret = select(fd+1, &fds, NULL, NULL, &timeout); 
/* ret == 0 means timeout, ret == 1 means descriptor is ready for reading, 
ret == -1 means error (check errno) */ 

char buf[100]; 

int i =0; 
while(i<(sizeof(messageArray)/sizeof(messageArray[0]))) 
{ 
    //creates a string with the AT command that writes to the module 
    std::string line1("AT+SBDWT="); 
    line1+=convertInt(messageArray[i].numChar); 
    line1+=" "; 
    line1+=convertInt(messageArray[i].packetNumber); 
    line1+=" "; 
    line1+=messageArray[i].data; 
    line1+=std::string("\r\n"); 

    //creates a string with the AT command that initiates the SBD session 
    std::string line2("AT+SBDI"); 
    line2+=std::string("\r\n"); 

    fputs(line1.c_str(), out); //sends to serial port 

    //usleep(7000000);  
    int ret =select(fd+1, &fds, NULL, NULL, &timeout); 
    /* ret == 0 means timeout, ret == 1 means descriptor is ready for reading, 
ret == -1 means error (check errno) */ 

    if (ret ==1){ 
fgets (buf ,sizeof(buf), in); 
//add code to check if response is correct 
    } 
    else if(ret == 0) { 
perror("timeout error "); 
    } 
    else if (ret ==-1) { 
perror("some other error"); 
    } 

    fputs(line2.c_str(), out); //sends to serial port 

    //usleep(7000000); //Pauses between the addition of each packet. 
    int ret2 = select(fd+1, &fds, NULL, NULL, &timeout); 
    /* ret == 0 means timeout, ret == 1 means descriptor is ready for reading, 
ret == -1 means error (check errno) */ 

    if(ret2 == 0) { 
perror("timeout error "); 
    } 
    else if (ret2 ==-1) { 
perror("some other error"); 
    } 

    i++; 
} 
+0

你正在試圖在Windows或Linux? –

+0

爲什麼你在select函數的第一個參數中傳遞(fd + 1)?嘗試傳遞1作爲select的第一個參數是fd數組中的描述符的計數,儘管此參數在窗口中被忽略 –

+0

@Muhammad Linux –

回答

3

你沒有使用相同的文件句柄進行讀/寫/選擇,這有點奇怪。

您沒有重置您的fd_sets,這是由select修改的,並且在超時的情況下會讓您的所有fds都未設置,從而使默認情況下下一次呼叫超時(因爲您不需要fds)。

你也在使用緩衝IO,在這種情況下,它肯定會引起頭痛。例如。 fgets等待EOF(不會發生)或換行,閱讀所有的時間。它會阻塞直到它獲得新行,所以如果永遠不會發生,可能會讓你無限期地掛起。 它也可能讀取比緩衝區更多的數據,將讀取的信號搞亂(數據在緩衝區中,但選擇將超時,因爲文件句柄上沒有可讀的內容)。

底線是這樣的:

  • 使用FD_SET在迴路設置/重置您的FD集,也重置超時,如select可以修改它。
  • 使用單個句柄進行讀取/寫入/選擇,而不是多個句柄,例如。打開文件fopen(..., "w+")open(..., O_RDWR)
  • 如果仍在使用fopen,請嘗試禁用緩衝使用setvbuf_IONBF緩衝選項。
  • 否則,使用open/read/write,而不是fopen

我會注意到這一部分是在this answer提到你前面的問題。

-1

您應該在輸出文件流中使用fflush()。