Summary: I am writing a ttyUSB snooper. The code is supposed to read(2) data from a serial port and write(2) it over to another serial port. Reading from the serial port works great with /bin/cat but fails with my code.
Hardware Setup is: I made an FTDI cross-over cable, and put one end in the Windows XP machine as Com2 and the other end in a modern Linux machine as /dev/ttyUSB0. The Linux machine has a USB to Serial cable that shows up as /dev/ttyUSB1. It is connected to the actual hardware unit I am trying to snoop. I verified, the hardware works great.
This part works: I will "cat /dev/ttyUSB0 > /tmp/data" and then have the WinXP machine issue the "read from the device over Com2", and the following six (6) bytes data will be sent over.
\x02\x01\x40\x00\x0a\x9e
This "packet" is sent 4 times or so with a very slight delay, this appears to be the WinXP code just trying a few times. If I replay this just once, it works.
If I simply do "cat /tmp/data > /dev/ttyUSB1", the hardware device will respond properly suggesting that it received the command. Great!
Problem and My Code: I am writing some code to be run on the Linux machine that will read(2) from /dev/ttyUSB0 and write it over to /dev/ttyUSB1 and vice versa. However, for some unknown reason it will only receive 4 bytes in the first "packet", then 5 in the subsequent 3 attempts. Sometimes, the 5 bytes appear slightly "damaged", meaning I see \xffffff for the last or second to last byte. Here is my code:
#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;
}
When I actually run this code, I see this:
# 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
Notice that only 4 or 5 bytes are being received and subsequently sent over at any given time. Not 6. Also, notice that the "packet" is distorted. What in the world would cause that???
Rationality if you're interested: I have old software that ONLY runs on Windows XP and will NOT work in a VM (this is a known issue). I would love to capture the traffic going over the serial port. I purchased a WinXP machine just to do this.