0

摘要:我正在寫一個ttyUSB窺探器。該代碼應該讀取(2)來自串行端口的數據並將其寫入(2)到另一個串行端口。從串口讀取與/ bin/cat的效果很好,但使用我的代碼失敗。編寫ttyUSB窺探器失敗

硬件設置爲:我製作了FTDI交叉電纜,將一端作爲Com2,另一端作爲/ dev/ttyUSB0放在現代Linux機器中。 Linux機器具有USB轉串口電纜,顯示爲/ dev/ttyUSB1。它連接到我試圖窺探的實際硬件單元。我證實,硬件很好。

這部分工作:我會的「貓的/ dev/ttyUSB0>的/ tmp /數據」,然後讓WinXP的機器發出了「從設備在Com2端口讀取」,和下面的六(6)個字節的數據將被髮送。

\x02\x01\x40\x00\x0a\x9e 

這個「包」被髮送4次左右有輕微的滯後,這似乎是隻是嘗試了幾次了WinXP的代碼。如果我只重播一次,它就會起作用。

如果我只是簡單地執行「cat/tmp/data>/dev/ttyUSB1」,硬件設備會正確響應,表明它收到了命令。大!

問題和我的代碼:我寫一些代碼要在Linux機器會從/ dev/ttyUSB0閱讀(2),並將其寫入了到/ dev/ttyUSB1,反之亦然上運行。然而,由於某些未知的原因,它將只在第一個「數據包」中接收4個字節,然後在隨後的3次嘗試中接收5個字節。有時候,這5個字節會略微「損壞」,這意味着我看到\ xffffff是最後一個或倒數第二個字節。這裏是我的代碼:

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <errno.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <strings.h> 

void hexdump(char *data, int size) { 
    for (size_t i = 0; i < size; ++i) 
     printf("%02x ", data[i]); 
    putchar('\n'); 
} 

int main() { 
    int fdzero; 
    int fdone; 

    int maxfd; 

    fd_set sockrd; 
    struct timeval timer; 

    char data[10]; 
    int size; 
    char tmp; 

    fdzero = open("/dev/ttyUSB0", O_RDWR); 
    if (fdzero == -1) { 
     perror("Failed to open /dev/ttyUSB0"); 
     return 1; 
    } 

    fdone = open("/dev/ttyUSB1", O_RDWR); 
    if (fdone == -1) { 
     perror("Failed to open /dev/ttyUSB1"); 
     return 1; 
    } 

    if (fdzero > fdone) 
     maxfd = fdzero; 
    else 
     maxfd = fdone; 

    printf("Enter loop\n"); 
    for(;;) { 
     bzero(data, 10); 
//  fflush(NULL); 
     FD_ZERO(&sockrd); 
     FD_SET(fdzero, &sockrd); 
     FD_SET(fdone, &sockrd); 

     timer.tv_sec = 60; 
     timer.tv_usec = 0; 

     select(maxfd+1, &sockrd, NULL, NULL, &timer); 

     if (FD_ISSET(fdzero, &sockrd)) { 

      size = read(fdzero, data, 10); 
      if (size == -1) { 
       perror("Failed to read /dev/ttyUSB0"); 
       break; 
      } 

      size = write(fdone, data, size); 
      if (size == -1) { 
       perror("Failed to write to /dev/ttyUSB1"); 
       break; 
      } 
      printf("ttyUSB0 -> ttyUSB1: %d\n", size); 
     } 


     // This portion does not trigger yet, but its a mirror 
     // Yes, I know...bad code :(
     else { 
      size = read(fdone, data, 10); 
      if (size == -1) { 
       perror("Failed to read /dev/ttyUSB1"); 
       break; 
      } 
      size = write(fdzero, data, size); 
      if (size == -1) { 
       perror("Failed to write to /dev/ttyUSB0"); 
       break; 
      } 
      printf("ttyUSB1 -> ttyUSB0: %d\n", size); 
     } 

     // Used to monitor what is read()/write() 
     hexdump(data, size); 
    } 

    return 0; 
} 

當我真正運行這段代碼,我看到:正在只得到4或5個字節,隨後在任何給定時間送過來

# cc snoop.c -o snoop 
# ./snoop 
Enter loop 
ttyUSB0 -> ttyUSB1: 4 
02 00 40 ffffff9e 
ttyUSB0 -> ttyUSB1: 4 
02 00 40 ffffff9e 
ttyUSB0 -> ttyUSB1: 4 
02 00 40 ffffff9e 
ttyUSB0 -> ttyUSB1: 5 
01 02 00 40 ffffff9e 
ttyUSB0 -> ttyUSB1: 5 
01 02 00 40 ffffff9e 
ttyUSB0 -> ttyUSB1: 5 
01 02 00 40 ffffff9e 

通知。不是6.另外,請注意「數據包」失真。世界上會造成什麼?

理性,如果你有興趣:我有一個只能運行在Windows XP中,並不會在虛擬機上工作(這是一個已知的問題)舊軟件。我很想捕捉串口上的流量。我購買了一臺WinXP機器來做到這一點。

+0

我懷疑這是與奇偶校驗位有關? –

回答

0

好了,所以你在這裏的兩個問題:

有時,5個字節出現輕微「損壞」,意思是我看到\ xffffff最後或倒數第二個字節。

這是因爲printf如何解釋進入的數據(this可能是感興趣的)。它被作爲已簽署的char傳入。在這種情況下,高位被解釋。要修復此部分,您的hexdump(char* data, int len)應該是hexdump(unsigned char* data, int len)或使用字節大小的類型,如uint8_t,以便您的簽名看起來像hexdump(uint8_t* data, int len)

但是,由於一些未知的原因,它將只在第一個「數據包」中接收4個字節,然後在隨後的3次嘗試中接收5個字節。

這幾乎肯定是由於您沒有在串口上設置任何設置。其中一個字符是0x0A,它是換行字符。這要麼被串行端口驅動程序忽略,要麼一起轉換成不同的字符。爲了解決這個問題,必須設置串行端口設置爲原料,而不是翻譯而來的任何字符我一般做類似如下:

struct termios newio; 
if(tcgetattr(fd, &newio) < 0){ /* error handling here */ }  

/* Set some default settings */ 
newio.c_iflag |= IGNBRK; 
newio.c_iflag &= ~BRKINT; 
newio.c_iflag &= ~ICRNL; 
newio.c_oflag = 0; 
newio.c_lflag = 0; 
newio.c_cc[VTIME] = 0; 
newio.c_cc[VMIN] = 1; 

/* Set our baud rate */ 
cfsetospeed(&newio, B9600); 
cfsetispeed(&newio, B9600); 

/* Character size = 8 */ 
newio.c_cflag &= ~CSIZE; 
newio.c_cflag |= CS8; 

/* One stop bit */ 
newio.c_cflag &= ~CSTOPB; 

/* Parity = none */ 
newio.c_iflag &= ~IGNPAR; 
newio.c_cflag &= ~(PARODD | PARENB); 
newio.c_iflag |= IGNPAR; 

/* No flow control */ 
newio.c_iflag &= ~(IXON | IXOFF | IXANY); 

/* Set our serial port settings */ 
if(tcsetattr(fd, TCSANOW, &newio) < 0) { /* error handling code here */ } 

如果你不想設置串口設置這樣,我寫了一個small library,它應該爲你抽象出小細節。

+0

這看起來像它的伎倆! –

+0

這看起來就像它的伎倆! 奇怪的是,它工作了一段時間,然後突然連接流失敗。我不確定爲什麼和我在監聽的軟件不會產生錯誤消息。是否有任何其他連接設置可能導致更好的連接? –

+0

我無法想象任何其他設置。我發佈的設置來自[GTKTerm](https://fedorahosted.org/gtkterm/),儘管我可能錯過了一個設置。 – rm5248