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

org.bidib.jbidib.netbidibsimple.tools.BiDiBPiStandalone Maven / Gradle / Ivy

package org.bidib.jbidib.netbidibsimple.tools;

import java.awt.GraphicsEnvironment;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;
import java.util.function.Consumer;

import org.bidib.jbidib.netbidibsimple.tools.ui.SwingPairingConnector;
import org.bidib.jbidibc.core.ConnectionListener;
import org.bidib.jbidibc.core.utils.NodeUtils;
import org.bidib.jbidibc.netbidib.NetBidibServer;
import org.bidib.jbidibc.netbidib.NetBidibServerHandler;
import org.bidib.jbidibc.netbidib.adapter.DefaultHostAdapter;
import org.bidib.jbidibc.netbidib.adapter.ScmSerialHostAdapter;
import org.bidib.jbidibc.netbidib.message.BidibLinkData;
import org.bidib.jbidibc.netbidib.pairingstore.LocalPairingStore;
import org.bidib.jbidibc.netbidib.pairingstore.PairingStore;
import org.bidib.jbidibc.pi.BidibPiConnector;
import org.bidib.jbidibc.pi.LedState;
import org.bidib.jbidibc.pi.PairingButtonHandler;
import org.bidib.jbidibc.pi.PairingButtonStateListener;
import org.bidib.jbidibc.pi.PairingConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beust.jcommander.IDefaultProvider;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.Parameters;

import io.netty.channel.group.ChannelGroup;

@Parameters(separators = "=")
public class BiDiBPiStandalone {
    private static final Logger LOGGER = LoggerFactory.getLogger(BiDiBPiStandalone.class);

    @Parameter(names = {
        "-port" }, description = "Port to use, e.g. 'COM1' or '/dev/ttyAMA0'. ", required = true, echoInput = true)
    private String portName;

    @Parameter(names = {
        "-listenHost" }, description = "Hostname to listen, e.g. 'localhost' or '0.0.0.0' to listen on all network interfaces.", echoInput = true)
    private String listenHost;

    @Parameter(names = {
        "-listenPort" }, description = "Network port to listen, default is: '62875'.", echoInput = true)
    private Integer listenPort;

    @Parameter(arity = 1, names = { "-forceTray" }, description = "Force tray application. ", echoInput = true)
    private boolean forceTray;

    private PairingConnector connector;

    private PairingStore pairingStore;

    private volatile AtomicBoolean pairingSupportDisabled = new AtomicBoolean();

    private BidibLinkData serverLinkData;

    private NetBidibServer netBidibServer;

    private static final IDefaultProvider DEFAULT_PROVIDER = new IDefaultProvider() {
        @Override
        public String getDefaultValueFor(String optionName) {
            String defaultValue = null;
            switch (optionName) {
                case "-listenHost":
                    defaultValue = "0.0.0.0";
                    break;
                case "-listenPort":
                    defaultValue = Integer.toString(NetBidibServer.DEFAULT_PORTNUM);
                    break;
                case "-forceTray":
                    defaultValue = Boolean.toString(Boolean.FALSE);
                    break;
                default:
                    break;
            }
            return defaultValue;
        }
    };

    public static void main(String[] args) {

        final BiDiBPiStandalone command = new BiDiBPiStandalone();

        JCommander jc = null;
        try {
            jc =
                JCommander
                    .newBuilder().addObject(command).programName(command.getClass().getName())
                    .defaultProvider(DEFAULT_PROVIDER).build();
            jc.parse(args);

            command.launch();
        }
        catch (ParameterException ex) {
            LOGGER.warn("Execution of " + command.getClass().getSimpleName() + " command failed: " + ex.getMessage());
            StringBuilder sb = new StringBuilder();
            jc.usage(sb);
            LOGGER.warn(sb.toString());
        }
    }

    public BiDiBPiStandalone() {
    }

    /**
     * Launch the application.
     */
    public void launch() {

        LOGGER
            .info("Start the standalone server. Use backend port: {}, listenHost: {}, listenPort: {}", portName,
                listenHost, listenPort);

        final ShutdownListener shutdownListener = new ShutdownListener() {

            @Override
            public void performShutdown() {
                initShutdown(netBidibServer);
            }
        };

        // load the pairing store
        LOGGER.info("Load the data from the pairing store.");
        this.pairingStore = new LocalPairingStore();
        this.pairingStore.load();

        if (!forceTray) {

            // create the pairing connector
            try {
                this.connector = initializeBidibPiConnector();
            }
            catch (InvalidPlatformException ex) {
                LOGGER.warn("Initialize the BidibPiConnector failed.", ex);

                if (GraphicsEnvironment.isHeadless()) {
                    // non gui mode
                    LOGGER
                        .warn(
                            "##========================================================================================##");
                    LOGGER
                        .warn(
                            "No BidibPiConnector detected. The pairing support is disabled and every partner is accepted.");
                    LOGGER
                        .warn(
                            "##========================================================================================##");
                    pairingSupportDisabled.set(true);
                }
                else {
                    // gui mode

                    LOGGER
                        .warn(
                            "##========================================================================================##");
                    LOGGER
                        .warn("No BidibPiConnector detected. The pairing support is provided by the tray application.");
                    LOGGER
                        .warn(
                            "##========================================================================================##");

                    // add the tray icon that allows pairing

                    this.connector = new SwingPairingConnector(shutdownListener, pairingStore);
                    this.connector.connect();
                }
            }

        }
        else {
            // gui mode
            if (GraphicsEnvironment.isHeadless()) {
                LOGGER.error("Must not start in headless mode.");
                System.exit(1);
            }

            LOGGER.warn("##========================================================================================##");
            LOGGER.warn("Run as tray application is forced. Skip BidibPiConnector.");
            LOGGER.warn("The pairing support is provided by the tray application.");
            LOGGER.warn("##========================================================================================##");

            // add the tray icon that allows pairing

            this.connector = new SwingPairingConnector(shutdownListener, pairingStore);
            this.connector.connect();
        }

        // create the host adapter
        final DefaultHostAdapter hostAdapter = new ScmSerialHostAdapter();

        final BiFunction pairingCallback = (bidibLinkData, pairingTimeout) -> {

            LOGGER
                .info("The pairing callback is called, bidibLinkData: {}, pairingTimeout: {}", bidibLinkData,
                    pairingTimeout);

            boolean pairingResult = false;
            try {
                LOGGER.info("Check the pairing store.");
                pairingResult = pairingStore.isPaired(bidibLinkData.getUniqueId());

                LOGGER.info("Checked the pairing store, paired: {}", pairingResult);

                if (!pairingResult) {
                    LOGGER
                        .warn("The partner is not enabled in the pairing store: {}",
                            NodeUtils.getUniqueIdAsString(bidibLinkData.getUniqueId()));
                }
            }
            catch (Exception ex) {
                LOGGER.warn("Check the pairing status failed.", ex);
            }

            if (!pairingResult && pairingSupportDisabled.get()) {
                LOGGER.warn("The pairing support is disabled. The partner is accepted!");
                pairingResult = true;
            }

            if (connector != null) {
                if (!pairingResult) {
                    LOGGER.info("Call the connector to accept the partner.");
                    pairingResult =
                        connector
                            .acceptClient(NodeUtils.getUniqueIdAsString(bidibLinkData.getUniqueId()), pairingTimeout);
                }
                else {
                    LOGGER.info("The pairing result was fetched from the pairing store.");
                    connector.setPairingLedState(LedState.on);

                    connector.showAcceptedClient(NodeUtils.getUniqueIdAsString(bidibLinkData.getUniqueId()));
                }
            }

            LOGGER.info("The pairing result: {}", pairingResult);
            return pairingResult;
        };

        serverLinkData = new BidibLinkData();

        // // create my unique id
        // byte[] uniqueId = new byte[] { 0x00, 0x00, 0x0D, (byte) 0xFA, 0x01, 0x03, (byte) 0xF1 };
        // serverLinkData.setUniqueId(ByteUtils.convertUniqueIdToLong(uniqueId));
        // serverLinkData.setProdString("netBiDiB-Gateway");
        // serverLinkData.setUserString("Central-Gateway");
        // serverLinkData.setProtocolVersion(ProtocolVersion.VERSION_0_8);

        final NetBidibServer netBidibServer =
            new NetBidibServer(listenHost, listenPort, hostAdapter, portName, serverLinkData) {
                @Override
                protected NetBidibServerHandler createNetBidibServerHandler(
                    ChannelGroup channelGroup, final BidibLinkData serverLinkData,
                    final Consumer lazyInitializationCallback) {
                    NetBidibServerHandler netBidibServerHandler =
                        super.createNetBidibServerHandler(channelGroup, serverLinkData, lazyInitializationCallback);
                    netBidibServerHandler.setPairingStore(pairingStore);
                    netBidibServerHandler.setPairingCallback(pairingCallback);

                    // add the connection listener for the remote connection to the client
                    netBidibServerHandler.addRemoteConnectionListener(new ConnectionListener() {

                        @Override
                        public void status(String messageKey) {
                            LOGGER.info("Status: {}", messageKey);
                        }

                        @Override
                        public void opened(String port) {

                        }

                        @Override
                        public void closed(String port) {
                            LOGGER.info("The connection to the client was closed.");
                            if (connector != null) {
                                connector.showWaitForClient();
                            }
                        }

                        @Override
                        public void stall(boolean stall) {
                            // TODO Auto-generated method stub
                        }
                    });

                    return netBidibServerHandler;
                }
            };

        // assign the variable
        this.netBidibServer = netBidibServer;

        // no pairing button handler if no connector
        if (connector != null) {
            final PairingButtonStateListener pairingButtonStateListener = new PairingButtonStateListener() {

                @Override
                public void pairingButtonStateChanged(boolean pressed) {
                    LOGGER.info("The pairing button state changed, pressed: {}", pressed);

                }
            };
            connector.addPairingButtonStateListener(pairingButtonStateListener);

            // add pairing button handler for long press
            final PairingButtonHandler pairingButtonStateHandler = new PairingButtonHandler(connector, 5000, 12000);

            pairingButtonStateHandler.addLongPressedListener(() -> {
                LOGGER.info("The pairing button was pressed long. Clear the pairingStore.");
                try {
                    pairingStore.clear();
                    pairingStore.store();
                }
                catch (Exception ex) {
                    LOGGER.warn("Clear the pairing store failed.", ex);
                }
            });
            connector.addPairingButtonStateListener(pairingButtonStateHandler);
        }

        netBidibServer.setShutdownHook(new Thread(() -> {
            LOGGER.info("Run shutdown hook.");

            initShutdown(netBidibServer);
        }));
        Runtime.getRuntime().addShutdownHook(netBidibServer.getShutdownHook());

        netBidibServer.start();

        LOGGER.info("Wait for server startup.");

        try {
            Thread.sleep(500);

            LOGGER.info("Wait for shutdown.");
            final Object shutdownLock = netBidibServer.getShutdownLock();
            synchronized (shutdownLock) {
                shutdownLock.wait();
            }
        }
        catch (InterruptedException ex) {
            LOGGER.warn("The server was terminated.", ex);
        }
        finally {

            initShutdown(netBidibServer);
        }

        LOGGER.info("Leave the main.");
        System.exit(0);
    }

    public void initShutdown(final NetBidibServer netBidibServer) {

        LOGGER.info("Initialize the shutdown.");
        try {
            netBidibServer.stop();
        }
        catch (Exception ex) {
            LOGGER.warn("Stop the netBidibServer failed.", ex);
        }

        try {
            if (connector != null) {
                LOGGER.info("Close the connector.");
                connector.close();
            }
        }
        catch (Exception ex) {
            LOGGER.warn("Close the connector failed.", ex);
        }
    }

    private PairingConnector initializeBidibPiConnector() {
        LOGGER.info("Initialize the BidibPiConnector.");

        BidibPiConnector connector = null;
        try {
            BidibPiConnector.checkPlatform(BidibPiConnector.PI_CPUINFOFILENAME);

            connector = new BidibPiConnector();
            connector.connect();

            return connector;
        }
        catch (Exception ex) {
            LOGGER.warn("Create and initialize the connector to the Pi failed.", ex);

            if (connector != null) {
                LOGGER.info("Disconnect and free the pi connector.");
                connector.disconnect();
                connector = null;
            }

            throw new InvalidPlatformException("Init the pi connector failed.");
        }
        catch (Error ex) {
            LOGGER.warn("Create and initialize the connector to the Pi failed.", ex);

            if (connector != null) {
                LOGGER.info("Disconnect and free the pi connector.");
                connector.disconnect();
                connector = null;
            }

            throw new InvalidPlatformException("Init the pi connector failed.");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy