I need to implement communication between two devices through serial ports on Raspberry Pi (with last Raspbian on board). Both uses CP2102 controller and connected to the Pi.
我需要通过Raspberry Pi上的串口实现两个设备之间的通信(最后一个Raspbian板载)。两者都使用CP2102控制器并连接到Pi。
Terminal:
pi@pi ~ $ ls -l /dev/serial/by-id
total 0
Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0 -> ../../ttyUSB2
pi@pi ~ $ ls -l /dev/serial/by-path
total 0
platform-bcm2708_usb-usb-0:1.2.1:1.0-port0 -> ../../ttyUSB1
platform-bcm2708_usb-usb-0:1.2.4:1.0-port0 -> ../../ttyUSB2
platform-bcm2708_usb-usb-0:1.3:1.0-port0 -> ../../ttyUSB0
Normally when I send command to SERIAL A, Device A replies through SERIAL A and sends data through SERIAL B. After that I need to retranslate this data to Device B (SERIAL C) and receive answer from SERIAL C.
通常当我向SERIAL A发送命令时,Device A通过SERIAL A回复并通过SERIAL B发送数据。之后我需要将这些数据重新转换为Device B(SERIAL C)并从SERIAL C接收回答。
The problem is that SERIAL A reply appears on SERIAL B and SERIAL B data appears on SERIAL A.
问题是SERIAL A回复出现在SERIAL B上,而SERIAL B数据出现在SERIAL A上。
I've tried different languages and serial libraries but the result is the same. So the questions are: why is it happening when using Raspberry Pi? How can I implement this functionality on Raspberry Pi?
我尝试过不同的语言和串行库但结果是一样的。所以问题是:为什么在使用Raspberry Pi时会发生这种情况?如何在Raspberry Pi上实现此功能?
P.S. Both devices are working properly. My C# code works perfect. I used System.IO.Ports.SerialPort class for that implementation and it looks like Pi4J and RXTX solutions.
附:两个设备都正常工作。我的C#代码非常完美。我为该实现使用了System.IO.Ports.SerialPort类,它看起来像Pi4J和RXTX解决方案。
P.P.S. Some code that I tried to use on RPi:
P.P.S.我尝试在RPi上使用的一些代码:
Serial, C++: (very bad piece of code)
Serial,C ++ :(非常糟糕的一段代码)
Serial port("/dev/ttyUSB2", 115200U);
Serial port1("/dev/ttyUSB1", 115200U);
port1.setTimeout(Timeout::max(), 250, 0, 250, 0);
port.setTimeout(Timeout::max(), 250, 0, 250, 0);
cout << "Is the serial port open?";
if (port1.isOpen()) {
cout << " Yes." << endl;
uint8_t data[2] = { 0xAA, 0x00 };
port1.write(data, 2);
data[1] = 0xFF;
sleep(1);
port1.write(data, 2);
while (port.available() < 7);
int av = port.available();
string ss;
port.read(ss, av);
for (int i = 0; i < av; i++){
cout << (uint)ss.at(i) << " ";
}
cout << "av: " + (uint)av << endl;
}
RXTX, Java:
public class Bridge_rxtx {
public static final int baudrate = 115200;
protected SerialPort spDevB_Data;
SerialReader devB_DataListener;
protected SerialPort spDevA_Data;
SerialReader DevA_DataListener;
protected SerialPort spDevA_Control;
SerialPortEventListener DevA_ControlListener;
public Bridge_rxtx(String comDevB_Data, String comDevA_Data, String comDevA_Control) {
try {
spDevB_Data = setupPort(comDevB_Data);
spDevA_Data = setupPort(comDevA_Data);
spDevA_Control = setupPort(comDevA_Control);
} catch (Exception ignored){
ignored.printStackTrace();
}
try {
devB_DataListener = new SerialReader(spDevB_Data.getInputStream(), spDevA_Data.getOutputStream(), "B-A");
DevA_DataListener = new SerialReader(spDevA_Data.getInputStream(), spDevB_Data.getOutputStream(), "A-B");
DevA_ControlListener = new SerialPortEventListener() {
@Override
public void serialEvent(SerialPortEvent spe) {
throw new UnsupportedOperationException("Not supported yet.");
}
};
spDevB_Data.notifyOnDataAvailable(true);
spDevA_Data.notifyOnDataAvailable(true);
spDevA_Control.notifyOnDataAvailable(true);
} catch (IOException ex) {
Logger.getLogger(Bridge_rxtx.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void launchBridge(){
System.out.println("Starting...");
try {
spDevA_Control.getOutputStream().write(new byte[] {(byte)0xAA, (byte) 0x00}, 0, 2);
} catch (IOException ex) {
Logger.getLogger(Bridge_rxtx.class.getName()).log(Level.SEVERE, null, ex);
}
try {
Thread.sleep(200);
} catch (InterruptedException ex) {
Logger.getLogger(Bridge_rxtx.class.getName()).log(Level.SEVERE, null, ex);
}
try {
spDevA_Control.getOutputStream().write(new byte[] {(byte)0xAA, (byte) 0xFF}, 0, 2);
} catch (IOException ex) {
Logger.getLogger(Bridge_rxtx.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("Started");
}
SerialPort setupPort(String portName) throws Exception {
SerialPort serialPort = null;
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
if (portIdentifier.isCurrentlyOwned()) {
System.out.println("Error: Port is currently in use");
} else {
CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000);
if (commPort instanceof SerialPort) {
serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
} else {
System.out.println("Error: Only serial ports are handled by this code.");
}
}
return serialPort;
}
public static void main(String[] args) {
Bridge_rxtx bridge = new Bridge_rxtx("/dev/ttyUSB0", "/dev/ttyUSB2", "/dev/ttyUSB1");
bridge.launchBridge();
}
}
Pi4J, Java:
public class Bridge {
public static Bridge instance;
public static final int baudrate = 115200;
protected Serial spDevB_Data;
SerialDataListener devB_DataListener;
protected Serial spDevA_Data;
SerialDataListener devA_DataListener;
protected Serial spDevA_Control;
SerialDataListener devA_ControlListener;
private Bridge() {
}
public Bridge(String comDevB_Data, String comDevA_Data, String comDevA_Control) {
instance = this;
devA_ControlListener = new SerialDataListener() {
//SerialDataEvent in Pi4J doesn't support binary
//data by default. I implemented this myself.
public void dataReceived(SerialDataEvent event) {
System.out.println(bytesToHex(toPrimitives(event.getBinaryData())));
}
};
devB_DataListener = new SerialDataListener() {
public void dataReceived(SerialDataEvent event) {
byte[] data = toPrimitives(event.getBinaryData());
instance.spDevA_Data.write(data);
System.out.println("B -> A: " + bytesToHex(data));
}
};
devA_DataListener = new SerialDataListener() {
public void dataReceived(SerialDataEvent event) {
byte[] data = toPrimitives(event.getBinaryData());
instance.spDevB_Data.write(data);
try {
Thread.sleep(15);
} catch (InterruptedException ex) {
Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("B <- A: " + bytesToHex(data));
}
};
spDevB_Data = SerialFactory.createInstance();
spDevB_Data.addListener(devB_DataListener);
spDevA_Data = SerialFactory.createInstance();
spDevA_Data.addListener(devA_ControlListener);
spDevA_Control = SerialFactory.createInstance();
spDevA_Control.addListener(devA_DataListener);
spDevB_Data.setMonitorInterval(40);
spDevA_Data.setMonitorInterval(80);
spDevA_Control.setMonitorInterval(25);
spDevB_Data.open(comDevB_Data, baudrate);
spDevA_Data.open(comDevA_Data, baudrate);
spDevA_Control.open(comDevA_Control, baudrate);
}
public void SetupBridge() {
spDevA_Control.write(new byte[]{(byte) 0xAA, (byte) 0x00});
try {
Thread.sleep(20);
} catch (InterruptedException ex) {
Logger.getLogger(Bridge.class.getName()).log(Level.SEVERE, null, ex);
}
spDevA_Control.write(new byte[]{(byte) 0xAA, (byte) 0xFF});
}
}
1 个解决方案
#1
1
Not enough reputation to comment: My educated guess would be that it has something to do with how Linux enumerates hardware. I think it's possible that your USB devices will have another serial-path depending on the used distro, and order of connecting them.
没有足够的声誉评论:我有根据的猜测是,它与Linux枚举硬件的方式有关。我认为您的USB设备可能会有另一个串行路径,具体取决于使用的发行版和连接顺序。
Are you sure that you use the same USB port every time? And that the correct USB port is mapped to /dev/tty?
您确定每次都使用相同的USB端口吗?并且正确的USB端口映射到/ dev / tty?
You can force a HID to always have the same name by making sure you have a udev rule for it. Some info here
您可以通过确保具有相应的udev规则来强制HID始终具有相同的名称。这里有一些信息
#1
1
Not enough reputation to comment: My educated guess would be that it has something to do with how Linux enumerates hardware. I think it's possible that your USB devices will have another serial-path depending on the used distro, and order of connecting them.
没有足够的声誉评论:我有根据的猜测是,它与Linux枚举硬件的方式有关。我认为您的USB设备可能会有另一个串行路径,具体取决于使用的发行版和连接顺序。
Are you sure that you use the same USB port every time? And that the correct USB port is mapped to /dev/tty?
您确定每次都使用相同的USB端口吗?并且正确的USB端口映射到/ dev / tty?
You can force a HID to always have the same name by making sure you have a udev rule for it. Some info here
您可以通过确保具有相应的udev规则来强制HID始终具有相同的名称。这里有一些信息