本文将实现一个linux下串口通讯的bundle,为了简单说明,代码中我们只是将串口做一个回环(收到的数据原封不动发送出去)。Window下代码无需改动,只需将代码中virPortName 改成对应“COM0“即可。另外,本工程需要下载RXTXcomm.jar并将其添加进库中。
先来看看SerialPortBundle.java,代码如下:
package demo.serialport.bundle;
import java.nio.ByteBuffer;
import java.io.IOException;
import java.io.InputStream;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPortEventListener;
public class SerialPortBundle{
private static CommPortIdentifier portId;
private static String virPortName = "/dev/ttyS0";
private static SerialPort serialPort;
private static InputStream inputStream;
public static boolean RunningFlag = false;
private static byte Count = 0;
public static void openVirtualPort() {
try {
portId = CommPortIdentifier.getPortIdentifier(virPortName);
} catch (Exception ex) {
System.out.println("Can not find device!\n");
ex.printStackTrace();
}
System.out.printf("Port name : " + portId.getName() + "\n");
if (portId.getName().equals(virPortName)) {
//open the virtual com port
try {
serialPort = (SerialPort)portId.open("demo_serial_port", 2000);
System.out.println("serial port open success!");
serialPort.setSerialPortParams(115200, 8, 1, 0);
} catch (Exception ex) {
System.out.println("serial port open failed!");
serialPort.close();
}
}
}
public static void closePort() throws IOException {
serialPort.notifyOnDataAvailable(false);
serialPort.removeEventListener();
serialPort.close();
}
public static class SerialPortRunnable implements Runnable, SerialPortEventListener {
ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(256);
public void run() {
try{
//open the virtual port
openVirtualPort();
//get Input Stream
inputStream = serialPort.getInputStream();
serialPort.notifyOnDataAvailable(true);
//Add this thread to EventListener
serialPort.addEventListener(this);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void serialEvent(SerialPortEvent event) {
switch(event.getEventType()) {
case SerialPortEvent.BI: //Break interrupt
case SerialPortEvent.OE: //Overrun error
case SerialPortEvent.FE: //Framing error
case SerialPortEvent.PE: //Parity error
case SerialPortEvent.CD: //Carrier detect
case SerialPortEvent.CTS: //Clear to send
case SerialPortEvent.DSR: //Data set ready
case SerialPortEvent.RI: //Ring indicator
case SerialPortEvent.OUTPUT_BUFFER_EMPTY: break; //Output buffer is empty
case SerialPortEvent.DATA_AVAILABLE: //Data available at the serial port
try {
receivePackage(receiveBuffer, 256);
// ......
// ...... do something if need to
receiveBuffer.clear();
sendPackage(receiveBuffer, 256);
receiveBuffer.clear();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
public static void receivePackage(ByteBuffer recvBuffer, int size) throws IOException {
byte[] tempBuffer = new byte[size];
int leftSize = size;
int index = 0;
try {
while ((leftSize > 0) && (RunningFlag == true)) {
if (inputStream.available() > 0) {
tempBuffer[index] = (byte)inputStream.read();
index ++;
leftSize --;
}
}
recvBuffer.put(tempBuffer, 0, size);
} catch (IOException ex) {
ex.printStackTrace();
}
finally {
recvBuffer.flip();
}
}
public static void sendPackage(ByteBuffer buffer, int size) throws IOException {
byte[] tempByteArray = new byte[size];
buffer.get(tempByteArray);
try {
outputStream.write(tempByteArray);
} catch(Exception ex) {
ex.printStackTrace();
}
finally {
buffer.flip();
}
}
}
先来实现Activator.java,代码比较简单,只需在start和stop方法中开始和结束串口收发的进程:
package demo.serialport.bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import demo.serialport.bundle.SerialPortBundle.SerialPortRunnable;
public class Activator implements BundleActivator {
public void start(BundleContext context) throws Exception {
System.out.println("serial port bundle started!");
SerialPortBundle.RunningFlag = true;
new Thread(new SerialPortRunnable()).start();
}
public void stop(BundleContext context) throws Exception {
System.out.println("serial port bundle stop!");
SerialPortcBundle.RunningFlag = false;
SerialPortBundle.VirtualPort();
}
}
上述例子经过实际测试,读写数据都正常。 实际应用中,串口收到数据后,可以通过发布event的方式告知其他Bundle有数据到来,而该串口Bundle只需负责纯粹的数据通讯,数据运算和其他处理交由其他Bundle负责,从而实现多Bundle协同动作。