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

org.bidib.jbidibc.usbstickbasis.adapter.UsbStickBasisAdapter Maven / Gradle / Ivy

package org.bidib.jbidibc.usbstickbasis.adapter;

import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.swing.SwingUtilities;

import org.apache.commons.lang3.StringUtils;
import org.bidib.jbidibc.debug.DebugInterface;
import org.bidib.jbidibc.debug.DebugMessageListener;
import org.bidib.jbidibc.debug.DebugMessageReceiver;
import org.bidib.jbidibc.debug.DebugReaderFactory;
import org.bidib.jbidibc.messages.ConnectionListener;
import org.bidib.jbidibc.messages.exception.PortNotFoundException;
import org.bidib.jbidibc.messages.exception.PortNotOpenedException;
import org.bidib.jbidibc.messages.exception.ProtocolException;
import org.bidib.jbidibc.messages.helpers.Context;
import org.bidib.jbidibc.messages.message.BidibMessageInterface;
import org.bidib.jbidibc.messages.message.ResponseFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UsbStickBasisAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(UsbStickBasisAdapter.class);

    private DebugInterface debugReader;

    private DebugMessageReceiver messageReceiver;

    private DebugMessageListener messageListener;

    private final UsbStickBasisModel usbStickBasisModel;

    private final UsbStickBasisResponseInterface responseInterface;

    private final StringBuilder resultBuffer = new StringBuilder();

    private final List receivedLines = new LinkedList<>();

    protected final ScheduledExecutorService receiverWorker = Executors.newScheduledThreadPool(1);

    private ResponseFactory responseFactory;

    private AtomicBoolean receiverWorkerActive = new AtomicBoolean();

    public UsbStickBasisAdapter(final UsbStickBasisResponseInterface responseInterface,
        final UsbStickBasisModel usbStickBasisModel) {
        this.responseInterface = responseInterface;
        this.usbStickBasisModel = usbStickBasisModel;
    }

    public void openConnection(String portName, String serialPortProvider)
        throws PortNotFoundException, PortNotOpenedException {

        Integer baudRate = usbStickBasisModel.getBaudRate();

        if (baudRate == null) {
            LOGGER.warn("No baudrate selected!");

            throw new IllegalArgumentException("No baudrate selected.");
        }

        LOGGER.info("Selected portName: {}", portName);

        if (debugReader == null) {
            LOGGER.info("Create new instance of debug reader.");

            responseFactory = new UsbStickBasisResponseFactory(responseInterface);
            responseFactory.initialize();

            try {
                messageListener = new DebugMessageListener() {

                    @Override
                    public void debugMessage(final String message) {
                        LOGGER.info("debug message received size: {}, message: {}", message.length(), message);
                        responseInterface.addLog(message);

                        synchronized (resultBuffer) {
                            LOGGER.trace("++ append");
                            resultBuffer.append(message);
                            resultBuffer.notifyAll();
                            LOGGER.trace("-- append");
                        }
                    }
                };
                messageReceiver = new DebugMessageReceiver();
                messageReceiver.addMessageListener(messageListener);

                // create the debug reader

                LOGGER.info("Selected serial port provider: {}", serialPortProvider);
                DebugReaderFactory.SerialImpl serialImpl = null;
                switch (serialPortProvider) {
                    case "scm":
                        serialImpl = DebugReaderFactory.SerialImpl.SCM;
                        break;
                    default:
                        // serialImpl = DebugReaderFactory.SerialImpl.RXTX;
                        serialImpl = DebugReaderFactory.SerialImpl.PUREJAVACOMM;
                        break;
                }

                debugReader = DebugReaderFactory.getDebugReader(serialImpl, messageReceiver);
                LOGGER.info("Created debugReader: {}", debugReader);
            }
            catch (Exception ex) {
                LOGGER.warn("Open debug port failed.", ex);
            }
        }

        try {
            debugReader.open(portName, baudRate, new ConnectionListener() {

                @Override
                public void opened(String port) {
                    LOGGER.info("Port opened: {}", port);
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            usbStickBasisModel.setConnected(true);
                        }
                    });
                }

                @Override
                public void closed(String port) {
                    LOGGER.info("Port closed: {}", port);
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            usbStickBasisModel.setConnected(false);
                        }
                    });
                }

                @Override
                public void status(String messageKey, final Context context) {
                    // no implementation
                }

                @Override
                public void stall(boolean stall) {
                    // no implementation
                }
            }, null);

            int delay = 0;
            // use executor to process the responses
            LOGGER.info("Schedule the receiverWorker.");

            receiverWorkerActive.set(true);

            receiverWorker.schedule(new Runnable() {
                @Override
                public void run() {
                    LOGGER.info("Start process the receive queue.");
                    while (receiverWorkerActive.get()) {
                        try {
                            processReceiveQueue(responseInterface);
                        }
                        catch (ProtocolException ex) {
                            LOGGER.warn("Process received response failed", ex);
                        }
                    }
                    LOGGER.info("Receive queue worker has finished.");
                }
            }, delay, TimeUnit.MILLISECONDS);
        }
        catch (PortNotFoundException |

            PortNotOpenedException ex) {
            LOGGER.warn("Open serial port failed.", ex);

            throw ex;
        }
        catch (

        Exception ex) {
            LOGGER.warn("Open serial port failed.", ex);

            throw new PortNotOpenedException("Open serial port failed.", ex);
        }
    }

    public void closeConnection() {
        LOGGER.info("Close the debug connection.");

        if (debugReader != null) {
            LOGGER.info("Close the debug reader.");
            debugReader.close();

            receiverWorkerActive.set(false);
            usbStickBasisModel.setConnected(false);

            try {
                synchronized (resultBuffer) {
                    resultBuffer.notifyAll();
                }
            }
            catch (Exception ex) {
                LOGGER.warn("Notify the resultBuffer failed.", ex);
            }

            messageReceiver.removeMessageListener(messageListener);
            messageListener = null;
            messageReceiver = null;

            debugReader = null;
        }
        else {
            LOGGER.info("debug reader not available.");
        }
    }

    public void clearReceiveBuffer() {
        LOGGER.info("Clear the receive buffer.");
        synchronized (resultBuffer) {
            resultBuffer.setLength(0);
        }
    }

    public String transmit(String sendText) {

        if (StringUtils.isEmpty(sendText)) {
            LOGGER.info("No data to send!");
            return null;
        }

        LOGGER.info("Send text to debugReader: '{}'", sendText);

        String result = null;
        if (debugReader != null) {
            debugReader.send(sendText, usbStickBasisModel.getLineEnding());
        }

        return result;
    }

    protected void processReceiveQueue(final UsbStickBasisResponseInterface responseInterface)
        throws ProtocolException {
        synchronized (resultBuffer) {

            LOGGER.trace("++ processReceiveQueue, resultBuffer.length(): {}", resultBuffer.length());
            if (resultBuffer.length() < 1) {
                try {
                    resultBuffer.wait(500);
                }
                catch (InterruptedException ex) {
                    LOGGER.warn("Wait for data in result buffer failed.", ex);
                }
            }

            if (resultBuffer.length() > 0) {

                int lastLF = resultBuffer.lastIndexOf("\n");
                LOGGER.trace("lastLF: {}", lastLF);
                if (lastLF > 0) {
                    // append the lines
                    List parts =
                        Pattern
                            .compile("\n").splitAsStream(resultBuffer.substring(0, lastLF)).map(str -> str.trim())
                            .filter(str -> !str.isEmpty()).collect(Collectors.toList());
                    receivedLines.addAll(parts);

                    String remaining = null;
                    if (lastLF < resultBuffer.length()) {
                        remaining = resultBuffer.substring(lastLF).trim();
                        LOGGER.info("Keep the remaining: '{}'", remaining);
                    }
                    // clear the buffer
                    resultBuffer.setLength(0);

                    if (StringUtils.isNotBlank(remaining)) {
                        resultBuffer.append(remaining);
                    }
                }
            }

            while (!receivedLines.isEmpty()) {

                try {

                    String part = receivedLines.remove(0).trim();

                    LOGGER.info("Check part: '{}'", part);

                    final BidibMessageInterface bidibMessage =
                        responseFactory.create(part.getBytes(Charset.forName("UTF-8")));
                    LOGGER.info("Created bidibMessage: {}", bidibMessage);

                    if (bidibMessage != null) {
                        responseInterface.publishReponse(bidibMessage);
                    }
                }
                catch (Exception ex) {
                    LOGGER.warn("Create bidib message from received data failed.", ex);
                }
            }

            LOGGER.trace("-- processReceiveQueue");
        }

        // sleep for 10ms
        try {
            Thread.sleep(10);
        }
        catch (Exception ex) {
            LOGGER.warn("Sleep for 10ms after processing resultBuffer failed.", ex);
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy