org.bidib.jbidib.netbidibsimple.tools.BiDiBPiStandalone Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jbidibc-netbidib-simple Show documentation
Show all versions of jbidibc-netbidib-simple Show documentation
jBiDiB jbidibc NetBidib Simple POM. Use -Dpi4j.dev.transfer=true to transfer the artifact to the raspberry pi.
The newest version!
package org.bidib.jbidib.netbidibsimple.tools;
import java.awt.GraphicsEnvironment;
import java.io.File;
import java.util.concurrent.Callable;
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.messages.ConnectionListener;
import org.bidib.jbidibc.messages.HostAdapter;
import org.bidib.jbidibc.messages.helpers.Context;
import org.bidib.jbidibc.messages.message.netbidib.LocalProtocolSignatureMessage;
import org.bidib.jbidibc.messages.message.netbidib.NetBidibLinkData;
import org.bidib.jbidibc.messages.message.netbidib.NetBidibLinkData.LogonStatus;
import org.bidib.jbidibc.messages.message.netbidib.NetBidibLinkData.PairingStatus;
import org.bidib.jbidibc.messages.message.netbidib.NetBidibLinkData.PartnerType;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.jbidibc.netbidib.pairingstore.LocalPairingStore;
import org.bidib.jbidibc.netbidib.pairingstore.LocalPairingStore.PairingLookupResult;
import org.bidib.jbidibc.netbidib.pairingstore.PairingStore;
import org.bidib.jbidibc.netbidib.server.NetBidibServer;
import org.bidib.jbidibc.netbidib.server.NetBidibServerByteArray;
import org.bidib.jbidibc.netbidib.server.NetBidibServerHandler;
import org.bidib.jbidibc.netbidib.server.RoleTypeEnum;
import org.bidib.jbidibc.netbidib.server.adapter.RxtxSerialHostAdapter;
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.bidib.jbidibc.pi.PairingConnector.PortStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.channel.group.ChannelGroup;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.IDefaultValueProvider;
import picocli.CommandLine.Model.ArgSpec;
import picocli.CommandLine.Model.OptionSpec;
import picocli.CommandLine.Option;
@Command(name = "BiDiBPiStandalone", defaultValueProvider = BiDiBPiStandalone.DefaultValueProvider.class)
public class BiDiBPiStandalone implements Callable {
private static final Logger LOGGER = LoggerFactory.getLogger(BiDiBPiStandalone.class);
public static final String PAIRINGSTORE_FILENAME = ".pairingstore-simple";
@Option(names = { "-port" }, description = "Port to use, e.g. 'COM1' or '/dev/ttyAMA0'. ", required = true)
private String portName;
@Option(names = {
"-listenHost" }, defaultValue = "0.0.0.0", description = "Hostname to listen, e.g. 'localhost' or '0.0.0.0' to listen on all network interfaces.")
private String listenHost;
@Option(names = { "-listenPort" }, description = "Network port to listen, default is: '62875'.")
private Integer listenPort;
@Option(names = { "-forceTray" }, arity = "1", description = "Force tray application. ")
private boolean forceTray;
private PairingConnector connector;
private PairingStore pairingStore;
private volatile AtomicBoolean pairingSupportDisabled = new AtomicBoolean();
private NetBidibLinkData serverLinkData;
private NetBidibServer netBidibServer;
public static class DefaultValueProvider implements IDefaultValueProvider {
@Override
public String defaultValue(ArgSpec argSpec) throws Exception {
String defaultValue = null;
if (argSpec.isOption()) {
OptionSpec spec = (OptionSpec) argSpec;
String optionName = spec.names()[0];
LOGGER.info("Get the default value for option: {}", optionName);
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();
int exitCode = new CommandLine(command).execute(args);
System.exit(exitCode);
}
public BiDiBPiStandalone() {
}
/**
* Launch the application.
*/
@Override
public Integer call() throws Exception {
LOGGER
.info("Start the standalone server. Use backend port: {}, listenHost: {}, listenPort: {}, forceTray: {}",
portName, listenHost, listenPort, forceTray);
final ShutdownListener shutdownListener = new ShutdownListener() {
@Override
public void performShutdown() {
LOGGER.info("Shutdown the netBidibServer: {}", netBidibServer);
initShutdown(netBidibServer);
}
};
// load the pairing store
final File pairingStoreFile = new File(".", PAIRINGSTORE_FILENAME);
LOGGER.info("Load the data from the pairing store: {}", pairingStoreFile);
this.pairingStore = new LocalPairingStore(pairingStoreFile);
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 RxtxSerialHostAdapter hostAdapter = new RxtxSerialHostAdapter<>(message -> message.getContent());
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, uniqueId: {}",
ByteUtils.getUniqueIdAsString(bidibLinkData.getUniqueId()));
PairingLookupResult pairingLookupResult = pairingStore.isPaired(bidibLinkData.getUniqueId());
pairingResult = PairingLookupResult.PAIRED == pairingLookupResult;
LOGGER.info("Checked the pairing store, paired: {}", pairingResult);
if (!pairingResult) {
LOGGER
.warn("The partner is not enabled in the pairing store: {}",
ByteUtils.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(ByteUtils.getUniqueIdAsString(bidibLinkData.getUniqueId()), pairingTimeout);
}
else {
LOGGER.info("The pairing result was fetched from the pairing store.");
connector.setPairingLedState(LedState.on);
connector.showAcceptedClient(ByteUtils.getUniqueIdAsString(bidibLinkData.getUniqueId()));
}
}
LOGGER.info("The pairing result: {}", pairingResult);
return pairingResult;
};
serverLinkData = new NetBidibLinkData(PartnerType.LOCAL);
serverLinkData.setRequestorName(LocalProtocolSignatureMessage.EMITTER_PREFIX_BIDIB + "netbidib-simple-v2");
RoleTypeEnum roleType = RoleTypeEnum.INTERFACE;
final NetBidibLinkData pairedPartner = new NetBidibLinkData(PartnerType.REMOTE);
pairedPartner.setPairingStatus(PairingStatus.UNKNOWN);
pairedPartner.setLogonStatus(LogonStatus.LOGGED_OFF);
final NetBidibServer netBidibServer =
new NetBidibServerByteArray(listenHost, listenPort, hostAdapter, portName, serverLinkData, roleType,
pairedPartner) {
@Override
protected NetBidibServerHandler createNetBidibServerHandler(
ChannelGroup channelGroup, final NetBidibLinkData serverLinkData,
final HostAdapter hostAdapter, final String backendPortName,
final Consumer> lazyInitializationCallback, RoleTypeEnum roleType,
final NetBidibLinkData pairedPartner) {
NetBidibServerHandler netBidibServerHandler =
super.createNetBidibServerHandler(channelGroup, serverLinkData, hostAdapter, backendPortName,
lazyInitializationCallback, roleType, pairedPartner);
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, final Context context) {
LOGGER.info("Status, messageKey: {}, context: {}", messageKey, context);
}
@Override
public void opened(String port) {
if (BiDiBPiStandalone.this.connector != null) {
BiDiBPiStandalone.this.connector.setPortStatus(PortStatus.CONNECTED);
}
}
@Override
public void closed(String port) {
LOGGER.info("The connection to the client was closed.");
if (BiDiBPiStandalone.this.connector != null) {
BiDiBPiStandalone.this.connector.setPortStatus(PortStatus.DISCONNECTED);
}
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());
LOGGER.info("Start the server.");
netBidibServer.startServer();
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.");
return 0;
}
public void initShutdown(final NetBidibServer netBidibServer) {
LOGGER.info("Initialize the shutdown: {}", netBidibServer);
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.");
}
}
}