|
|
@ -1,13 +1,21 @@ |
|
|
|
package com.dreamworks.boditech.driver.connection; |
|
|
|
import com.dreamworks.boditech.utils.MyByteBuffer; |
|
|
|
import com.fazecast.jSerialComm.SerialPort; |
|
|
|
import com.fazecast.jSerialComm.SerialPortDataListener; |
|
|
|
import com.fazecast.jSerialComm.SerialPortEvent; |
|
|
|
import jakarta.annotation.PostConstruct; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import org.springframework.beans.factory.annotation.Value; |
|
|
|
import org.springframework.stereotype.Component; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
import java.nio.ByteOrder; |
|
|
|
import java.util.*; |
|
|
|
@Component |
|
|
|
public class ComSerialPort { |
|
|
|
// message type : ack |
|
|
|
private static final byte MESSAGE_TYPE_ACK = 0x01; |
|
|
|
|
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(ComSerialPort.class); |
|
|
|
@Value("${app.device.connectionType}") |
|
|
|
private String connectionType; |
|
|
@ -17,6 +25,8 @@ public class ComSerialPort { |
|
|
|
private int baudRate; |
|
|
|
// serial port connection |
|
|
|
private SerialPort port; |
|
|
|
// request list |
|
|
|
private final List<ClientRequest> requestList = new ArrayList<>(); |
|
|
|
|
|
|
|
@PostConstruct |
|
|
|
public void init() { |
|
|
@ -40,35 +50,108 @@ public class ComSerialPort { |
|
|
|
} |
|
|
|
|
|
|
|
this.port.setBaudRate(this.baudRate); |
|
|
|
this.port.addDataListener(new SerialPortDataListener() { |
|
|
|
@Override |
|
|
|
public int getListeningEvents() { |
|
|
|
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void serialEvent(SerialPortEvent event) { |
|
|
|
if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE) { |
|
|
|
return ; |
|
|
|
} |
|
|
|
handleOnData(); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// write bytes to serial port |
|
|
|
public void write( ByteBuffer content ) { |
|
|
|
byte[] bytes = content.array(); |
|
|
|
this.port.writeBytes(bytes, bytes.length); |
|
|
|
// handle on data |
|
|
|
public void handleOnData() { |
|
|
|
ByteBuffer message = this.readAll(); |
|
|
|
message.order(ByteOrder.LITTLE_ENDIAN); |
|
|
|
LOG.info("device <= {}", MyByteBuffer.toHex(message)); |
|
|
|
|
|
|
|
byte messageType = message.get(5); |
|
|
|
if ( ComSerialPort.MESSAGE_TYPE_ACK == messageType ) { |
|
|
|
this.onMessageHandleAck(message); |
|
|
|
} else { |
|
|
|
throw new RuntimeException("unknown message type"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// read text from serial port |
|
|
|
public ByteBuffer read() { |
|
|
|
int readableLength = this.port.bytesAvailable(); |
|
|
|
byte[] buffer = new byte[readableLength]; |
|
|
|
int numRead = this.port.readBytes(buffer, buffer.length); |
|
|
|
return ByteBuffer.wrap(buffer, 0, numRead); |
|
|
|
// handle ack message |
|
|
|
private void onMessageHandleAck(ByteBuffer message) { |
|
|
|
ClientRequest request = this.getRequestMessage(message); |
|
|
|
if ( null == request ) { |
|
|
|
return ; |
|
|
|
} |
|
|
|
synchronized (Objects.requireNonNull(request)) { |
|
|
|
request.isResponseReceived = true; |
|
|
|
request.response = message; |
|
|
|
request.notify(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// get request message |
|
|
|
private ClientRequest getRequestMessage( ByteBuffer message ) { |
|
|
|
short messageId = message.getShort(0); |
|
|
|
for ( ClientRequest requestItem : this.requestList ) { |
|
|
|
if ( requestItem.id == messageId ) { |
|
|
|
return requestItem; |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
// wait for response |
|
|
|
public boolean waitForResponse( Integer timeout ) { |
|
|
|
int count = timeout / 200; |
|
|
|
for (int i=0; i<count; i++) { |
|
|
|
if ( this.port.bytesAvailable() > 0 ) { |
|
|
|
return true; |
|
|
|
// call device method and wait for response |
|
|
|
public ByteBuffer call(ClientRequest request ) { |
|
|
|
this.requestList.add(request); |
|
|
|
int index = this.requestList.indexOf(request); |
|
|
|
ClientRequest requestItem = this.requestList.get(index); |
|
|
|
|
|
|
|
// timeout check |
|
|
|
TimerTask timerTask = new TimerTask() { |
|
|
|
@Override |
|
|
|
public void run() { |
|
|
|
synchronized (requestItem) { |
|
|
|
if ( requestItem.isResponseReceived ) { |
|
|
|
return ; |
|
|
|
} |
|
|
|
LOG.info("device -- timeout"); |
|
|
|
requestItem.response = null; |
|
|
|
requestItem.errorCode = ClientRequest.ERROR_CODE_TIMEOUT; |
|
|
|
requestItem.notify(); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
Timer timer = new Timer(); |
|
|
|
timer.schedule(timerTask, 10000); |
|
|
|
|
|
|
|
synchronized (requestItem) { |
|
|
|
String cmd = MyByteBuffer.toHex(request.parameter); |
|
|
|
LOG.info("device => {}", cmd); |
|
|
|
|
|
|
|
byte[] bytes = request.parameter.array(); |
|
|
|
this.port.writeBytes(bytes, bytes.length); |
|
|
|
try { |
|
|
|
Thread.sleep(200); |
|
|
|
requestItem.wait(); |
|
|
|
} catch (InterruptedException e) { |
|
|
|
e.printStackTrace(); |
|
|
|
throw new RuntimeException(e); |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
|
|
|
|
if ( 0 != request.errorCode ) { |
|
|
|
throw new RuntimeException("device error : " + request.errorCode); |
|
|
|
} |
|
|
|
return request.response; |
|
|
|
} |
|
|
|
|
|
|
|
// read all data from serial port |
|
|
|
public ByteBuffer readAll() { |
|
|
|
int readableLength = this.port.bytesAvailable(); |
|
|
|
byte[] buffer = new byte[readableLength]; |
|
|
|
int numRead = this.port.readBytes(buffer, buffer.length); |
|
|
|
return ByteBuffer.wrap(buffer, 0, numRead); |
|
|
|
} |
|
|
|
} |