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

org.bidib.jbidibc.gateway.GatewaySerialBidib Maven / Gradle / Ivy

package org.bidib.jbidibc.gateway;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.bidib.jbidibc.core.BidibInterface;
import org.bidib.jbidibc.core.BidibMessageProcessor;
import org.bidib.jbidibc.core.exception.InvalidLibraryException;
import org.bidib.jbidibc.core.helpers.Context;
import org.bidib.jbidibc.core.node.NodeRegistry;
import org.bidib.jbidibc.core.utils.ByteUtils;
import org.bidib.jbidibc.serial.AbstractSerialBidib;
import org.bidib.jbidibc.serial.SerialMessageEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.serialpundit.core.SerialComException;
import com.serialpundit.serial.ISerialComDataListener;
import com.serialpundit.serial.ISerialComEventListener;
import com.serialpundit.serial.SerialComLineEvent;
import com.serialpundit.serial.SerialComManager;
import com.serialpundit.serial.SerialComManager.BAUDRATE;
import com.serialpundit.serial.SerialComManager.DATABITS;
import com.serialpundit.serial.SerialComManager.FLOWCONTROL;
import com.serialpundit.serial.SerialComManager.PARITY;
import com.serialpundit.serial.SerialComManager.STOPBITS;

public class GatewaySerialBidib extends AbstractSerialBidib {
    private static final Logger LOGGER = LoggerFactory.getLogger(GatewaySerialBidib.class);

    private static final Logger MSG_RAW_LOGGER = LoggerFactory.getLogger("RAW");

    private SerialComManager scm;

    private long handle = -1;

    private ISerialComDataListener dataListener;

    private ISerialComEventListener eventListener;

    private boolean addEventListener = false;

    private boolean useHardwareFlowControl = false;

    private GatewaySerialBidib() {
    }

    /**
     * Get a new initialized instance of GatewaySerialBidib.
     *
     * @return the instance of ScmSerialBidib
     */
    public static BidibInterface createInstance() {
        LOGGER.info("Create new instance of GatewaySerialBidib.");

        GatewaySerialBidib instance = new GatewaySerialBidib();
        instance.initialize();

        return instance;
    }

    @Override
    protected BidibMessageProcessor createMessageReceiver(NodeRegistry nodeRegistry) {

        LOGGER.info("Set the ignoreMissingTransferListeners flag on the NodeRegistry.");
        nodeRegistry.setIgnoreMissingTransferListeners(true);

        return new GatewayResponseReceiver(nodeRegistry);
    }

    @Override
    public void close() {
        // close the port if available
        if (scm != null) {
            LOGGER.info("Close the port, handle: {}", handle);

            long start = System.currentTimeMillis();

            // unregister data listener
            LOGGER.info("Unregister data listener: {}", dataListener);

            if (dataListener != null && handle > 0) {
                try {
                    scm.unregisterDataListener(handle, dataListener);
                }
                catch (SerialComException ex) {
                    LOGGER.warn("Unregister dataListener failed.", ex);
                }

                try {
                    Thread.sleep(200);
                }
                catch (InterruptedException ex) {
                    LOGGER.warn("Sleep after unregister data listener failed.", ex);
                }
            }
            dataListener = null;

            // unregister line event listener
            if (eventListener != null && handle > 0) {
                LOGGER.info("Unregister line event listener.");
                try {
                    scm.unregisterLineEventListener(handle, eventListener);
                }
                catch (SerialComException ex) {
                    LOGGER.warn("Unregister lineEventListener failed.", ex);
                }

                try {
                    Thread.sleep(200);
                }
                catch (InterruptedException ex) {
                    LOGGER.warn("Sleep after unregister line event listener failed.", ex);
                }
            }

            eventListener = null;

            final BidibMessageProcessor serialMessageReceiver = getMessageReceiver();
            stopReceiverAndQueues(serialMessageReceiver);

            if (handle > 0) {
                try {
                    LOGGER.info("Close the COM port: {}", handle);
                    // port.close();
                    scm.closeComPort(handle);
                }
                catch (Exception e) {
                    LOGGER.warn("Close port failed.", e);
                }
            }
            else {
                LOGGER.info("Don't close port because handle is not valid.");
            }

            long end = System.currentTimeMillis();
            LOGGER.info("Closed the port. duration: {}", end - start);

            setConnected(false);

            scm = null;
            handle = -1;

            cleanupAfterClose(serialMessageReceiver);
        }
        else {
            LOGGER.info("No port to close available.");
        }
    }

    @Override
    public List getPortIdentifiers() {
        List portIdentifiers = new ArrayList();

        try {
            String tempDir = System.getProperty("java.io.tmpdir");
            File temp = new File(tempDir, "jbidibc");
            // temp.mkdirs();

            if (scm == null) {
                LOGGER.info("Create the scm instance.");
                scm = new SerialComManager("scm", temp.getAbsolutePath(), true, false);
            }

            String[] ports = scm.listAvailableComPorts();
            for (String portIdentifier : ports) {
                portIdentifiers.add(portIdentifier);
            }
        }
        catch (UnsatisfiedLinkError ule) {
            LOGGER.warn("Get comm port identifiers failed.", ule);
            throw new InvalidLibraryException(ule.getMessage(), ule.getCause());
        }
        catch (Error error) {
            LOGGER.warn("Get comm port identifiers failed.", error);
            throw new RuntimeException(error.getMessage(), error.getCause());
        }
        catch (IOException ex) {
            LOGGER.warn("Get comm port identifiers failed.", ex);
            throw new InvalidLibraryException(ex.getMessage(), ex.getCause());
        }
        return portIdentifiers;
    }

    @Override
    protected boolean isImplAvaiable() {
        return (scm != null);
    }

    private BAUDRATE getBaudRate(int baudRate) {

        for (BAUDRATE br : BAUDRATE.values()) {

            if (br.getValue() == baudRate) {
                return br;
            }
        }

        return BAUDRATE.B115200;
    }

    @Override
    protected void internalOpen(String portName, final Context context) throws Exception {

        final BidibMessageProcessor serialMessageReceiver = getMessageReceiver();

        String tempDir = System.getProperty("java.io.tmpdir");
        File temp = new File(tempDir, "jbidibc");

        scm = new SerialComManager("scm", temp.getAbsolutePath(), true, false);

        LOGGER.info("Open port with portName: {}", portName);

        // open the port
        handle = scm.openComPort(portName, true, true, true);
        LOGGER.info("Opened serial port, handle: {}", handle);

        if (useHardwareFlowControl) {
            scm.configureComPortControl(handle, FLOWCONTROL.RTS_CTS, 'x', 'x', false, true);
        }
        else {
            scm.configureComPortControl(handle, FLOWCONTROL.NONE, 'x', 'x', false, true);
        }

        Integer baudRate = context.get("serial.baudrate", Integer.class, Integer.valueOf(115200));
        LOGGER.info("Open port with baudRate: {}", baudRate);

        BAUDRATE scmBaudRate = getBaudRate(baudRate);

        scm.configureComPortData(handle, DATABITS.DB_8, STOPBITS.SB_1, PARITY.P_NONE, scmBaudRate, 0);

        startReceiverAndQueues(serialMessageReceiver, context);

        setConnected(true);

        // add event listener
        if (addEventListener) {
            eventListener = new ISerialComEventListener() {

                @Override
                public void onNewSerialEvent(SerialComLineEvent lineEvent) {
                    LOGGER.error("eventCTS : {}, eventDSR : {}", lineEvent.getCTS(), lineEvent.getDSR());
                }
            };
            scm.registerLineEventListener(handle, eventListener);
        }

        dataListener = new ISerialComDataListener() {

            @Override
            public void onNewSerialDataAvailable(final byte[] data) {

                // TODO remove the logger
                MSG_RAW_LOGGER.info("<<<< Serial data available, len: {}", data.length);

                receive(data, data.length);

                // TODO remove the logger
                MSG_RAW_LOGGER.info("<<<< Serial data received.");
            }

            @Override
            public void onDataListenerError(int errorNum) {

                LOGGER.error("Data listener notified an error: {}", errorNum);

                if (isConnected()) {
                    LOGGER.info("Close the port.");

                    setConnected(false);

                    if (dataListener != null) {
                        try {
                            LOGGER.info("Unregister data listener.");
                            scm.unregisterDataListener(handle, dataListener);
                            dataListener = null;
                        }
                        catch (Exception ex) {
                            LOGGER.warn("Unregister data listener after error detection failed.", ex);
                        }
                    }

                    Thread t1 = new Thread(new Runnable() {

                        @Override
                        public void run() {
                            LOGGER.info("Error detected. Close the port.");

                            if (dataListener != null) {
                                try {
                                    scm.unregisterDataListener(handle, dataListener);
                                    dataListener = null;
                                }
                                catch (Exception ex) {
                                    LOGGER.warn("Unregister data listener after error detection failed.", ex);
                                }
                            }

                            if (eventListener != null) {
                                try {
                                    scm.unregisterLineEventListener(handle, eventListener);
                                    eventListener = null;
                                }
                                catch (Exception ex) {
                                    LOGGER.warn("Unregister event listener after error detection failed.", ex);
                                }
                            }
                            try {
                                close();
                            }
                            catch (Exception ex) {
                                LOGGER.warn("Close scm port failed.", ex);
                            }
                        }
                    });
                    t1.start();
                }
                else {
                    LOGGER.info("Port is closed.");
                }
            }
        };

        LOGGER.info("Registering data listener fro handle: {}.", handle);
        // register data listener for this port
        scm.registerDataListener(handle, dataListener);

        LOGGER.info("Registered data listener.");

        if (useHardwareFlowControl) {
            // Activate DTR
            // try {
            // LOGGER.info("Activate DTR.");
            //
            // scm.setDTR(handle, true); // pin 1 in DIN8; on main connector, this is DTR
            // }
            // catch (Exception e) {
            // LOGGER.warn("Set DTR true failed.", e);
            // }

            try {
                LOGGER.info("Activate RTS.");
                scm.setRTS(handle, true);
            }
            catch (Exception e) {
                LOGGER.warn("Set RTS true failed.", e);
            }
        }
    }

    @Override
    public boolean isOpened() {
        boolean isOpened = (handle > 0);
        return isOpened;
    }

    private ByteArrayOutputStream output = new ByteArrayOutputStream(100);

    @Override
    protected void sendData(ByteArrayOutputStream data) {

        if (handle > 0 && data != null) {
            byte[] bytes = data.toByteArray();
            try {
                if (MSG_RAW_LOGGER.isInfoEnabled()) {
                    MSG_RAW_LOGGER.info(">> [{}] - {}", bytes.length, ByteUtils.bytesToHex(bytes));
                }

                // MSG_OUTPUTSTREAM_LOGGER.info(">>>>");

                output.reset();
                SerialMessageEncoder.encodeMessage(data, output);

                int sent = scm.writeBytes(handle, output.toByteArray());

                if (sent == 0) {
                    MSG_RAW_LOGGER.warn(">> sent bytes: {}", sent);
                    LOGGER.error("The message has not been sent to handle: {}, message: {}", handle,
                        ByteUtils.bytesToHex(bytes));

                    throw new RuntimeException("Write message to output failed: " + ByteUtils.bytesToHex(bytes));
                }
                else {
                    MSG_RAW_LOGGER.info(">> sent bytes: {}", sent);
                }
            }
            catch (Exception ex) {
                LOGGER.warn("Send message to output stream failed: [{}] - {}", bytes.length,
                    ByteUtils.bytesToHex(bytes), ex);

                throw new RuntimeException("Send message to output stream failed: " + ByteUtils.bytesToHex(bytes), ex);
            }
            finally {
                output.reset();
            }
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy