org.bidib.jbidibc.spsw.debug.NetDebugReader Maven / Gradle / Ivy
The newest version!
package org.bidib.jbidibc.spsw.debug;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import org.bidib.jbidibc.debug.AbstractDebugReader;
import org.bidib.jbidibc.debug.DebugMessageProcessor;
import org.bidib.jbidibc.debug.LineEndingEnum;
import org.bidib.jbidibc.messages.ConnectionListener;
import org.bidib.jbidibc.messages.exception.NoAnswerException;
import org.bidib.jbidibc.messages.exception.PortNotFoundException;
import org.bidib.jbidibc.messages.exception.PortNotOpenedException;
import org.bidib.jbidibc.messages.helpers.Context;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.ibapl.spsw.api.DataBits;
import de.ibapl.spsw.api.FlowControl;
import de.ibapl.spsw.api.Parity;
import de.ibapl.spsw.api.Speed;
import de.ibapl.spsw.api.StopBits;
import de.ibapl.spsw.ser2net.Ser2NetProvider;
public class NetDebugReader extends AbstractDebugReader {
private static final Logger LOGGER = LoggerFactory.getLogger(NetDebugReader.class);
private static final Logger MSG_RAW_LOGGER = LoggerFactory.getLogger("DEBUG_RAW");
private Ser2NetProvider ser2NetProvider;
// private DebugMessageProcessor messageReceiver;
//
// private String requestedPortName;
//
// private ConnectionListener connectionListener;
private Semaphore portSemaphore = new Semaphore(1);
private Semaphore sendSemaphore = new Semaphore(1);
private final ScheduledExecutorService receiveWorker = Executors.newScheduledThreadPool(1);
private AtomicBoolean closeInProgress = new AtomicBoolean();
// private BlockingQueue freeBufferQueue = new LinkedBlockingQueue<>();
//
// private BlockingQueue receiveQueue = new LinkedBlockingQueue<>();
//
// private Thread receiveQueueWorker;
//
// private AtomicBoolean receiverRunning = new AtomicBoolean();
//
// private AtomicLong receiveQueueWorkerThreadId = new AtomicLong();
public NetDebugReader(final DebugMessageProcessor messageReceiver) {
super(messageReceiver);
}
@Override
public void initialize() {
// // warmup
// for (int i = 0; i < 100; i++) {
// ByteArrayOutputStream item = new ByteArrayOutputStream(64);
//
// freeBufferQueue.add(item);
// }
}
@Override
public List getPortIdentifiers() {
return Collections.emptyList();
}
// @Override
// public DebugMessageProcessor getMessageReceiver() {
// return messageReceiver;
// }
//
// /**
// * @return the connectionListener
// */
// @Override
// public ConnectionListener getConnectionListener() {
// return connectionListener;
// }
//
// /**
// * @param connectionListener
// * the connectionListener to set
// */
// @Override
// public void setConnectionListener(ConnectionListener connectionListener) {
// this.connectionListener = connectionListener;
// }
private Ser2NetProvider internalOpen(String portName, int baudRate, Context context) throws IOException {
// reset the close in progress flag
closeInProgress.set(false);
startReceiveQueueWorker();
// open the port
LOGGER.info("The interface port is a valid inet address. Create the Ser2NetProvider instance.");
String[] splited = portName.split(":");
String host = splited[0];
int dataPort = Integer.parseInt(splited[1]);
LOGGER.info("Create ser2NetProvider with host: {}, dataPort: {}", host, dataPort);
Ser2NetProvider ser2NetProvider = null;
try {
// ser2NetProvider = new Ser2NetProvider(host, dataPort);
DataBits dataBits = DataBits.DB_8;
StopBits stopBits = StopBits.SB_1;
Parity parity = Parity.NONE;
Set flowControls = FlowControl.getFC_NONE();
ser2NetProvider =
new Ser2NetProvider(host, dataPort, Speed.fromNative(baudRate), dataBits, stopBits, parity,
flowControls);
}
catch (IOException ex) {
LOGGER.warn("Open connection to remote serial port failed.", ex);
throw ex;
}
getConnectionListener().opened(portName);
// enable the message receiver before the event listener is added
getMessageReceiver().enable();
final Ser2NetProvider ser2NetProviderReciever = ser2NetProvider;
receiveWorker.submit(new Runnable() {
@Override
public void run() {
LOGGER.info("The receiverWorker is running.");
receiverWorkerEnabled.set(true);
byte[] receiveData = new byte[1024];
try (BufferedInputStream in = new BufferedInputStream(ser2NetProviderReciever.getInputStream())) {
int receivedCount = 0;
// wait for client sending data
while ((receivedCount = in.read(receiveData)) > 0 && receiverWorkerEnabled.get()) {
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug("Received data from tcp socket, len: {}, data: {}.", receivedCount,
ByteUtils.bytesToHex(receiveData, receivedCount));
}
receive(receiveData, receivedCount);
}
}
catch (IOException ex) {
if (receiverWorkerEnabled.get()) {
LOGGER.warn("--- Interrupt NetDebugReader-run", ex);
}
else {
LOGGER.info("The NetDebugReader worker is terminating.");
}
}
}
});
return ser2NetProvider;
}
private AtomicBoolean receiverWorkerEnabled = new AtomicBoolean();
@Override
public void close() {
// close the port if available
if (ser2NetProvider != null) {
LOGGER.info("Close the port, ser2NetProvider: {}", ser2NetProvider);
long start = System.currentTimeMillis();
// TODO Auto-generated method stub
// no longer process received messages
getMessageReceiver().disable();
stopReceiveQueueWorker();
try {
LOGGER.info("Close the COM port: {}", ser2NetProvider);
ser2NetProvider.close();
}
catch (Exception e) {
LOGGER.warn("Close port failed.", e);
}
long end = System.currentTimeMillis();
LOGGER.info("Closed the port. duration: {}", end - start);
ser2NetProvider = null;
if (getConnectionListener() != null) {
getConnectionListener().closed(getRequestedPortName());
}
setRequestedPortName(null);
}
}
@Override
public boolean isOpened() {
boolean isOpened = false;
try {
portSemaphore.acquire();
LOGGER.debug("Check if port is opened: {}", ser2NetProvider);
isOpened = (ser2NetProvider != null && ser2NetProvider.getOutputStream() != null);
}
catch (InterruptedException ex) {
LOGGER.warn("Wait for portSemaphore was interrupted.", ex);
}
catch (IOException ex) {
LOGGER.warn("OutputStream is not available.", ex);
}
finally {
portSemaphore.release();
}
return isOpened;
}
@Override
public void open(String portName, int baudRate, ConnectionListener connectionListener, Context context)
throws PortNotFoundException, PortNotOpenedException {
LOGGER.info("Open the port: {}", portName);
setConnectionListener(connectionListener);
if (ser2NetProvider == null) {
if (portName == null || portName.trim().isEmpty()) {
throw new PortNotFoundException("");
}
LOGGER.info("Open port with name: {}, baudRate: {}", portName, baudRate);
setRequestedPortName(portName);
try {
portSemaphore.acquire();
try {
close();
// open the commPort
internalOpen(portName, baudRate, context);
LOGGER.info("The port was opened internally.");
}
catch (NoAnswerException naex) {
LOGGER.warn("Open communication failed.", naex);
try {
close();
}
catch (Exception e4) { // NOSONAR
// ignore
}
throw naex;
}
catch (Exception e2) {
LOGGER.info("Open port failed. Close port and throw exception.", e2);
// close port to cleanup and stop the send queue worker
try {
close();
}
catch (Exception e3) { // NOSONAR
LOGGER.warn("Close port failed.", e3);
}
throw new PortNotOpenedException(portName, PortNotOpenedException.UNKNOWN);
}
catch (UnsatisfiedLinkError err) {
LOGGER.info("Open port failed. Close port and throw exception.", err);
throw new PortNotOpenedException(portName, PortNotOpenedException.UNKNOWN);
}
}
catch (InterruptedException ex) {
LOGGER.warn("Wait for portSemaphore was interrupted.", ex);
throw new PortNotOpenedException(portName, PortNotOpenedException.UNKNOWN);
}
finally {
portSemaphore.release();
}
}
else {
LOGGER.warn("Port is already opened.");
}
}
/**
* Send the bytes of the message to the outputstream and add <CR>+<LF>.
*
* @param bytes
* the bytes to send
*/
@Override
public void send(final String message, LineEndingEnum lineEnding) {
if (ser2NetProvider != null) {
try {
sendSemaphore.acquire();
if (MSG_RAW_LOGGER.isInfoEnabled()) {
MSG_RAW_LOGGER.info(">> '{}'", message);
}
OutputStream output = ser2NetProvider.getOutputStream();
output.write(message.getBytes());
output.write(lineEnding.getValues());
}
catch (Exception e) {
throw new RuntimeException("Send message to output stream failed.", e);
}
finally {
sendSemaphore.release();
}
}
}
@Override
public void send(byte[] content) {
if (ser2NetProvider != null) {
try {
sendSemaphore.acquire();
if (MSG_RAW_LOGGER.isInfoEnabled()) {
MSG_RAW_LOGGER.info(">> '{}'", ByteUtils.bytesToHex(content));
}
OutputStream output = ser2NetProvider.getOutputStream();
output.write(content);
}
catch (Exception e) {
throw new RuntimeException("Send message to output stream failed.", e);
}
finally {
sendSemaphore.release();
}
}
}
private final ByteArrayOutputStream output = new ByteArrayOutputStream(2048);
/**
* @param data
* the received data
* @param len
* the len of data
*/
private void receive(final byte[] data, int len) {
try {
output.reset();
// ByteArrayOutputStream buffer = freeBufferQueue.take();
output.write(data, 0, len);
addDataToReceiveQueue(output);
// boolean added = receiveQueue.offer(buffer);
// if (!added) {
// LOGGER
// .error("The message was not added to the receive queue: {}",
// ByteUtils.bytesToHex(buffer.toByteArray()));
// }
}
catch (Exception ex) {
LOGGER.warn("Add buffer to receive queue failed.", ex);
}
}
// @Override
// private void startReceiveQueueWorker() {
// receiverRunning.set(true);
//
// LOGGER.info("Start the receiveQueueWorker. Current receiveQueueWorker: {}", receiveQueueWorker);
// receiveQueueWorker = new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// processReceiveQueue();
// }
// catch (Exception ex) {
// LOGGER.warn("The processing of the receive queue was terminated with an exception!", ex);
//
// // running.set(false);
// }
//
// LOGGER.info("Process receive queue has finished.");
// }
// }, "receiveQueueWorker");
//
// try {
// receiveQueueWorkerThreadId.set(receiveQueueWorker.getId());
// receiveQueueWorker.start();
// }
// catch (Exception ex) {
// LOGGER.error("Start the receiveQueueWorker failed.", ex);
// }
// }
//
// @Override
// private void stopReceiveQueueWorker() {
// LOGGER.info("Stop the receive queue worker.");
// receiverRunning.set(false);
// receiverWorkerEnabled.set(false);
//
// try {
// receiveQueueWorker.interrupt();
//
// receiveQueueWorker.join(1000);
//
// LOGGER.info("receiveQueueWorker has finished.");
// }
// catch (Exception ex) {
// LOGGER.warn("Interrupt receiveQueueWorker failed.", ex);
// }
//
// try {
// LOGGER.info("Shutdown receiveWorker.");
// receiveWorker.shutdown();
// receiveWorker.awaitTermination(2000, TimeUnit.MILLISECONDS);
// }
// catch (Exception ex) {
// LOGGER.warn("Wait for shutdown of receiveWorker failed.", ex);
// }
//
// receiveQueueWorker = null;
// }
//
// private void processReceiveQueue() {
// LOGGER.info("The receiveQueueWorker is ready for processing.");
//
// while (receiverRunning.get()) {
// ByteArrayOutputStream bytes = null;
// try {
// // get the message to process
// bytes = receiveQueue.take();
//
// if (bytes != null) {
// // process
// try {
// getMessageReceiver().processMessages(bytes);
// }
// catch (Exception ex) {
// LOGGER.warn("Process received bytes failed.", ex);
// }
//
// }
// }
// catch (InterruptedException ex) {
// LOGGER.warn("Get message from receiveQueue failed because thread was interrupted.");
// }
// catch (Exception ex) {
// LOGGER.warn("Get message from receiveQueue failed.", ex);
// }
// finally {
// if (bytes != null) {
// bytes.reset();
// freeBufferQueue.add(bytes);
// }
// }
// bytes = null;
// }
//
// LOGGER.info("The receiveQueueWorker has finished processing.");
// receiveQueueWorkerThreadId.set(0);
// }
}