2012-06-05 31 views
3

我在使用select,FD_ISSET,讀取等從ttyUSB端口讀取一些linux c代碼時出現問題。我的調制解調器使用FTDI串口連接USB電纜進行輸入。問題是,拔掉USB電纜時選擇解鎖。有沒有辦法阻止它做到這一點?爲什麼拔下USB電纜時選擇返回?

count = 0; 
while (g_running) { 
    FD_ZERO(&readFdSet); 
    maxfd = 0; 
    numTransPorts = 0; 
    logger(DEBUG, "Begin g_running loop - %d", count); 
    for (i = 0; i < MAX_CONFIG_PORTS; i++) { 
     if (configPorts[i].commType == 1 && configPorts[i].pttyHost != NULL) { 
     FD_SET(configPorts[i].pttyHost->fd, &readFdSet); 
     logger(DEBUG, "FD_SET - fd=%d, index=%d", configPorts[i].pttyHost->fd, i); 
     if (configPorts[i].pttyHost->fd >= maxfd) { 
      maxfd = configPorts[i].pttyHost->fd; 
     } 
     numTransPorts++; 
     } 
    } 
    maxfd++; // add one because select check a range to n-1 file descriptors 
    if (maxfd != 0) { // indicates no ports are available 
     logger(DEBUG, "Calling select() with %d ports and maxfd of %d", numTransPorts, maxfd); 
     logger(INFO, "Waiting for input ..."); 
     select(maxfd, &readFdSet, NULL, NULL, NULL); // blocking until one available 
     if(result == -1){ 
     logger(INFO, "select() error. errno: %d", errno); 
     } else if (result > 0){ 
     for (i = 0; i < MAX_CONFIG_PORTS; i++) { 
      if (FD_ISSET(configPorts[i].pttyHost->fd, &readFdSet)) { // input is available 
       logger(INFO, "Input on port %s", configPorts[i].pttyHost->serialPath); 
       result = serialPortRead(buffer, configPorts[i].pttyHost->fd); 
       if (result <= 0) { 
        // there was an error due to the file descriptor. It 
        // probably indicates that the tty ports are no longer available 
       } 
      } 
     } 
     } else { 
     logger (INFO, "select() returns 0"); 
     } 
    } 
    count++; 
} 

serialPortRead:

int serialPortRead(char *buf, int serialHandle) { 
    //char ch; 
    char *ptr; 
    int res = 0; 
    int bytesRead = 0; 
    int i; 

    logger(TRACE, "TRACE: serialPortRead() with fd = %d", serialHandle); 

    ptr = buf; 

    // try 3 times 
    for (i = 0; i < 3; i++) { 
     while ((res = read(serialHandle, ptr, 1)) > 0) { // read 1 byte at a time 
     if (*ptr == 0x0d) { //there is 0x0d as a terminate byte from ECR 
      break; 
     } 
     ptr += res; 
     } 
     if (res < 0 && errno == EAGAIN) { 
     continue; 
     } else { 
     break; 
     } 
    } 

    *ptr = 0x00; // set 0x00 as a terminate byte 
    // pthread_mutex_unlock(&g_serial_trans_mutex); 
    if (res < 0) { 
     // if res is -1, there is an error 
     bytesRead = -1; 
     logger(DEBUG, "serialPortRead error. errno = %d", errno); 
    } else { 
     bytesRead = (int) (ptr - buf); 
     logger(DEBUG, "serialPortRead %d bytes", bytesRead); 
    } 

    return bytesRead; 
} 

當USB電纜被拔掉,select()的解除阻塞,這意味着輸入是可用的,FD_ISSET返回true。在serialPortRead中,read()將返回零字節。然後它返回到select(),它再次解除阻塞,說明輸入可用,依此類推。因此,你得到一個無限循環的select(),FD_ISSET返回true,fd永遠不會被清除,讀取返回0等等。我怎樣才能解決這個問題?我期望的行爲是,當沒有真正需要閱讀的內容時,select不會錯誤地解鎖?

注:當選擇放開它返回一個正數

+1

你確定選擇返回手段'輸入可用'嗎? afaik它也可能意味着'有錯誤',這正是這種情況。 – stijn

+0

當讀取返回0時,沒有更多需要閱讀的內容,因此您必須將fd從您選擇的集合中取出。發生錯誤時,您有機會將錯誤傳遞給您;一旦你被告知錯誤,你必須關閉fd並停止選擇它,而不是試圖繼續選擇和閱讀。 –

+0

我想我所希望的行爲不僅僅是它的工作方式。當應用程序啓動時,它會查看插入的USB設備並將其打開以供輸入。除非偶然拔掉插頭,否則配置不應改變。我希望它不做任何事情。然後,當電纜再次插入時,可以在沒有中斷的情況下接收輸入。 – Jim

回答

5

select()正在恢復,因爲有資料閱讀 - 在這種情況下,事實文件描述符已經達到了「文件結束」。這由read()返回0表示。

read()返回0時,應該關閉相應的文件描述符。

+0

我認爲你是對的,因爲我應該關閉FD。但是,我希望有一些方法可以防止選擇從第一位解鎖。然後,當電纜重新插入時,應用程序仍處於接收輸入狀態。例如,一根RS232電纜可以拔掉,然後重新插入,而不會觸發事件。 – Jim

+3

@ user1100151:這不正是USB ttys的工作原理 - 當您拔出並重新插入USB tty時,這是整個串行端口設備正在消失並重新出現。內核無法知道它是同一個USB設備重新出現還是不同的,所以它會在每個插件事件上創建一個新的設備節點。使用有線RS232串行端口,串行設備本身永遠不會消失。 – caf

相關問題