All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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);
    // }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy