|
|
@ -1,11 +1,15 @@ |
|
|
|
package org.mgc.serial_comm; |
|
|
|
|
|
|
|
import com.fazecast.jSerialComm.SerialPort; |
|
|
|
import com.fazecast.jSerialComm.SerialPortDataListener; |
|
|
|
import com.fazecast.jSerialComm.SerialPortEvent; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
import java.io.InputStream; |
|
|
|
import java.io.OutputStream; |
|
|
|
import java.util.concurrent.BlockingQueue; |
|
|
|
import java.util.concurrent.LinkedBlockingQueue; |
|
|
|
import java.util.concurrent.TimeUnit; |
|
|
|
import java.io.ByteArrayOutputStream; |
|
|
|
|
|
|
|
@Slf4j |
|
|
|
public class SerialComm { |
|
|
@ -18,6 +22,8 @@ public class SerialComm { |
|
|
|
|
|
|
|
private final SerialPort serialPort; |
|
|
|
|
|
|
|
private final BlockingQueue<byte[]> responseQueue = new LinkedBlockingQueue<>(); |
|
|
|
|
|
|
|
public SerialComm(String portName, int baudRate, int dataBits, int stopBits, int parity) { |
|
|
|
this.portName = portName; |
|
|
|
this.baudRate = baudRate; |
|
|
@ -33,23 +39,67 @@ public class SerialComm { |
|
|
|
} |
|
|
|
|
|
|
|
public void open() throws Exception { |
|
|
|
if (!serialPort.openPort()) { |
|
|
|
log.warn("Could not open serial port {}", serialPort.getSystemPortName()); |
|
|
|
throw new IOException("Failed to open serial port: " + serialPort.getSystemPortName()); |
|
|
|
if (serialPort.openPort()) { |
|
|
|
log.info("Opened serial port: {} open Success ", serialPort.getSystemPortName()); |
|
|
|
|
|
|
|
clearSerialPortBuffer(); |
|
|
|
|
|
|
|
// 新增:临时缓冲区 |
|
|
|
ByteArrayOutputStream tempBuffer = new ByteArrayOutputStream(); |
|
|
|
|
|
|
|
SerialPortDataListener dataListener = new SerialPortDataListener() { |
|
|
|
@Override |
|
|
|
public int getListeningEvents() { |
|
|
|
return SerialPort.LISTENING_EVENT_DATA_RECEIVED; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void serialEvent(SerialPortEvent event) { |
|
|
|
if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_RECEIVED) { |
|
|
|
byte[] newData = event.getReceivedData(); |
|
|
|
if (newData != null && newData.length > 0) { |
|
|
|
synchronized (tempBuffer) { |
|
|
|
try { |
|
|
|
tempBuffer.write(newData); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("Error writing to tempBuffer", e); |
|
|
|
} |
|
|
|
// 延时 1ms |
|
|
|
try { |
|
|
|
Thread.sleep(5); |
|
|
|
} catch (InterruptedException e) { |
|
|
|
Thread.currentThread().interrupt(); |
|
|
|
log.error("Sleep interrupted", e); |
|
|
|
} |
|
|
|
// 只有缓冲区为空时才入队 |
|
|
|
if (serialPort.bytesAvailable() == 0) { |
|
|
|
byte[] frame = tempBuffer.toByteArray(); |
|
|
|
if (frame.length > 0) { |
|
|
|
responseQueue.add(frame); |
|
|
|
} |
|
|
|
tempBuffer.reset(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
serialPort.addDataListener(dataListener); |
|
|
|
} |
|
|
|
else{ |
|
|
|
log.info("Opened serial port: " + serialPort.getSystemPortName()); |
|
|
|
log.warn("Could not open serial port {}", serialPort.getSystemPortName()); |
|
|
|
throw new IOException("Failed to open serial port: " + serialPort.getSystemPortName()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void setReadTimeOut(int readTimeOut) { |
|
|
|
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, readTimeOut, 0); |
|
|
|
} |
|
|
|
|
|
|
|
public void close() throws Exception { |
|
|
|
// 清空缓存数据 |
|
|
|
responseQueue.clear(); |
|
|
|
if (serialPort != null) { |
|
|
|
// 移除监听 |
|
|
|
serialPort.removeDataListener(); |
|
|
|
serialPort.closePort(); |
|
|
|
log.info("Closed serial port: {}", serialPort.getSystemPortName()); |
|
|
|
log.info("Closed serial port: {} Suc", serialPort.getSystemPortName()); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
@ -59,15 +109,16 @@ public class SerialComm { |
|
|
|
|
|
|
|
byte[] sendBlockAutoRetry(byte[] send_data, int timeout) |
|
|
|
{ |
|
|
|
clearSerialPortBuffer(); |
|
|
|
for(int i = 0; i < retry_times; i++) |
|
|
|
{ |
|
|
|
byte[] data = sendBlocked(send_data, timeout); |
|
|
|
if(data.length != 0) |
|
|
|
{ |
|
|
|
// 成功 |
|
|
|
return data; |
|
|
|
} |
|
|
|
log.warn("sendBlockAutoRetry failed for {} times", retry_times); |
|
|
|
byte[] data = sendBlocked(send_data, timeout); |
|
|
|
if(data != null && data.length != 0) |
|
|
|
{ |
|
|
|
// 成功 |
|
|
|
return data; |
|
|
|
} |
|
|
|
log.warn("sendBlockAutoRetry failed for {} times", i); |
|
|
|
} |
|
|
|
// 三次超时失败视为 断联 立即进行重启 |
|
|
|
try { |
|
|
@ -83,9 +134,8 @@ public class SerialComm { |
|
|
|
|
|
|
|
synchronized public byte[] sendBlocked(byte[] send_data, int timeout) |
|
|
|
{ |
|
|
|
setReadTimeOut(timeout); // 指定超时时间,通过串口配置超时时间 |
|
|
|
writeBytes(send_data); |
|
|
|
return readBytes(); |
|
|
|
return readBytes(timeout); |
|
|
|
} |
|
|
|
|
|
|
|
public int writeBytes(byte[] data) |
|
|
@ -95,29 +145,30 @@ public class SerialComm { |
|
|
|
return num; |
|
|
|
} |
|
|
|
|
|
|
|
public byte[] readBytes() |
|
|
|
// 读取时间 |
|
|
|
public byte[] readBytes(int timeout) |
|
|
|
{ |
|
|
|
int numRead = 0; |
|
|
|
byte[] readBuffer = new byte[1024]; |
|
|
|
try { |
|
|
|
Thread.sleep(100); |
|
|
|
} catch (InterruptedException e) { |
|
|
|
log.info("thread interrupted while waiting for read bytes {}", e.getMessage()); |
|
|
|
} |
|
|
|
if (serialPort.bytesAvailable() > 0) |
|
|
|
{ |
|
|
|
numRead = serialPort.readBytes(readBuffer, readBuffer.length); |
|
|
|
if(numRead > 0) |
|
|
|
{ |
|
|
|
byte[] data = new byte[numRead]; |
|
|
|
System.arraycopy(readBuffer, 0, data, 0, numRead); |
|
|
|
return data; |
|
|
|
} |
|
|
|
} |
|
|
|
return responseQueue.poll(timeout, TimeUnit.MILLISECONDS); |
|
|
|
} catch (InterruptedException ignored) |
|
|
|
{} |
|
|
|
log.info("Read bytes failed"); |
|
|
|
return new byte[0]; |
|
|
|
} |
|
|
|
|
|
|
|
private void clearSerialPortBuffer() { |
|
|
|
try { |
|
|
|
int availableBytes = serialPort.bytesAvailable(); |
|
|
|
if (availableBytes > 0) { |
|
|
|
byte[] buffer = new byte[availableBytes]; |
|
|
|
serialPort.readBytes(buffer, availableBytes); |
|
|
|
log.info("Cleared {} bytes of residual data from the serial port.", availableBytes); |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("Error clearing serial port buffer: ", e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public int getBaudRate() { |
|
|
|
return this.baudRate; |
|
|
|
} |
|
|
@ -133,4 +184,4 @@ public class SerialComm { |
|
|
|
public int getDataBits() { |
|
|
|
return this.dataBits; |
|
|
|
} |
|
|
|
} |
|
|
|
} |