摘要:我正在编写一个ttyUSB窥探器。该代码应该从串行端口读取(2)数据并将其写入(2)到另一个串行端口。从串口读取可以很好地使用/ bin / cat,但是我的代码失败了。
硬件设置是:我制作了一条FTDI交叉电缆,将一端作为Com2放在Windows XP机器中,另一端放在现代Linux机器上作为/ dev / ttyUSB0。 Linux机器有一个USB转串口电缆,显示为/ dev / ttyUSB1。它连接到我试图窥探的实际硬件单元。我验证了,硬件效果很好。
这部分有效:我会" cat / 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;
}
当我实际运行此代码时,我看到了:
# 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
请注意,在任何给定时间只接收4个或5个字节并随后发送。不是6.另外,请注意&#34;数据包&#34;是扭曲的。世界上会发生什么?
理性如果您感兴趣:我的旧软件只能在Windows XP上运行,不能在VM中运行(这是一个已知问题)。我很想捕捉通过串口的流量。我刚刚购买了一台WinXP机器。
答案 0 :(得分:0)
好的,所以你的两个问题在这里:
有时候,5个字节会略微“损坏”,这意味着我会看到\ xffffff表示最后一个或倒数第二个字节。
这是因为printf如何解释进来的数据(here可能感兴趣)。它是作为hexdump(char* data, int len)
传递的,已签名。在这种情况下,正在解释高阶位。要修复此部分,您的hexdump(unsigned char* data, int len)
应该是uint8_t
或使用字段大小的类型,例如hexdump(uint8_t* data, int len)
,以便您的签名看起来像0x0A
。
但是,由于某些未知原因,它只会在第一个“数据包”中接收4个字节,然后在随后的3次尝试中接收5个字节。
这几乎可以肯定是因为您没有在串行端口上设置任何设置。您拥有的其中一个字符是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 */ }
,它是换行符。这可以被串行端口驱动程序忽略,也可以一起转换为不同的字符。要解决此问题,您必须将串行端口设置设置为原始设置,而不是翻译任何进入的字符。我通常会执行以下操作:
file1.ts
import { Component } from "@angular/core";
@Component({
selector: "search",
templateUrl: '<div>Hello{{testData}}</div>'
})
export class File1Component{
public testData = "Hello";
}
file2.ts
import { Component } from "@angular/core";
@Component({
selector: "profile",
templateUrl: '<div>Hello</div>'
})
export class File2Component{
}
如果您不想以这种方式设置串口设置,我写了一个this,它应该为您提取小细节。