diff --git a/plugins-dev/remote-actions-extra/src/java/pt/lsts/neptus/plugins/remoteactionsextra/RemoteActionsExtra.java b/plugins-dev/remote-actions-extra/src/java/pt/lsts/neptus/plugins/remoteactionsextra/RemoteActionsExtra.java index 60490ce4e3..95c66b7a10 100644 --- a/plugins-dev/remote-actions-extra/src/java/pt/lsts/neptus/plugins/remoteactionsextra/RemoteActionsExtra.java +++ b/plugins-dev/remote-actions-extra/src/java/pt/lsts/neptus/plugins/remoteactionsextra/RemoteActionsExtra.java @@ -34,13 +34,17 @@ import com.google.common.eventbus.Subscribe; import net.miginfocom.swing.MigLayout; +import pt.lsts.imc.EntityState; import pt.lsts.imc.RemoteActions; import pt.lsts.imc.RemoteActionsRequest; +import pt.lsts.imc.VehicleState; import pt.lsts.neptus.NeptusLog; import pt.lsts.neptus.console.ConsoleLayout; import pt.lsts.neptus.console.ConsolePanel; import pt.lsts.neptus.console.events.ConsoleEventMainSystemChange; import pt.lsts.neptus.console.plugins.MainVehicleChangeListener; +import pt.lsts.neptus.plugins.ConfigurationListener; +import pt.lsts.neptus.plugins.NeptusProperty; import pt.lsts.neptus.plugins.PluginDescription; import pt.lsts.neptus.plugins.Popup; import pt.lsts.neptus.plugins.update.Periodic; @@ -63,7 +67,7 @@ author = "Paulo Dias", icon = "images/control-mode/teleoperation.png", description = "This plugin listen for non motion related remote actions and displays its controls.") @Popup(name = "Remote Actions Extra", width = 300, height = 200, pos = Popup.POSITION.BOTTOM, accelerator = KeyEvent.VK_3) -public class RemoteActionsExtra extends ConsolePanel implements MainVehicleChangeListener { +public class RemoteActionsExtra extends ConsolePanel implements MainVehicleChangeListener, ConfigurationListener { static final boolean defaultAxisDecimalVal = false; private static final int DECIMAL_HOUSES_FOR_DECIMAL_AXIS = 6; @@ -118,12 +122,23 @@ enum ActionTypeEnum { private String lastCmdBuilt = ""; + private TakeControlMonitor takeControlMonitor; + private TakeControlMonitor takeControlMonitor2; + + @NeptusProperty(name = "OBS Entity Name", userLevel = NeptusProperty.LEVEL.ADVANCED, + description = "Used to check the state of the OBS take control status.") + public String obsEntityName = "OBS Broker"; + public RemoteActionsExtra(ConsoleLayout console) { - super(console); + this(console, false); } public RemoteActionsExtra(ConsoleLayout console, boolean usedInsideAnotherConsolePanel) { super(console, usedInsideAnotherConsolePanel); + takeControlMonitor = new TakeControlMonitor(this); + takeControlMonitor.setEntityName(obsEntityName); + takeControlMonitor2 = new TakeControlMonitor(this); + takeControlMonitor2.setEntityName(obsEntityName); } @Override @@ -133,9 +148,20 @@ public void initSubPanel() { @Override public void cleanSubPanel() { + takeControlMonitor.setButton(null); + takeControlMonitor2.setButton(null); + } + + @Override + public void propertiesChanged() { + takeControlMonitor.setEntityName(obsEntityName); + takeControlMonitor2.setEntityName(obsEntityName); } private synchronized void resetUIWithActions() { + takeControlMonitor.setButton(null); + takeControlMonitor2.setButton(null); + removeAll(); setLayout(new MigLayout("insets 10px")); @@ -169,6 +195,14 @@ private synchronized void resetUIWithActions() { String lay = "dock center, sg grp" + grpIdx; lay += ", " + wrapLay; add(button, lay); + if ("Take Control".equalsIgnoreCase(action)) { + takeControlMonitor.setButton(button); + takeControlMonitor.askedControl(); + } else if ("Relinquish Control".equalsIgnoreCase(action)) { + takeControlMonitor2.setButton(button); + takeControlMonitor2.askedControl(); + } + break; case AXIS: case SLIDER: @@ -186,6 +220,8 @@ private synchronized void resetUIWithActions() { @Subscribe public void on(ConsoleEventMainSystemChange evt) { configureActions("", defaultAxisDecimalVal, false); + takeControlMonitor.on(evt); + takeControlMonitor2.on(evt); } @Subscribe @@ -199,6 +235,18 @@ public void on(RemoteActionsRequest msg) { configureActions(msg.getActions(), defaultAxisDecimalVal, false); } + @Subscribe + public void on(EntityState msg) { + takeControlMonitor.on(msg); + takeControlMonitor2.on(msg); + } + + @Subscribe + public void on(VehicleState msg) { + takeControlMonitor.on(msg); + takeControlMonitor2.on(msg); + } + @Periodic(millisBetweenUpdates = 1_000) public void sendRemoteActionsToMainSystem() { try { diff --git a/plugins-dev/remote-actions-extra/src/java/pt/lsts/neptus/plugins/remoteactionsextra/TakeControlMonitor.java b/plugins-dev/remote-actions-extra/src/java/pt/lsts/neptus/plugins/remoteactionsextra/TakeControlMonitor.java new file mode 100644 index 0000000000..59485f6827 --- /dev/null +++ b/plugins-dev/remote-actions-extra/src/java/pt/lsts/neptus/plugins/remoteactionsextra/TakeControlMonitor.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2004-2023 Universidade do Porto - Faculdade de Engenharia + * Laboratório de Sistemas e Tecnologia Subaquática (LSTS) + * All rights reserved. + * Rua Dr. Roberto Frias s/n, sala I203, 4200-465 Porto, Portugal + * + * This file is part of Neptus, Command and Control Framework. + * + * Commercial Licence Usage + * Licencees holding valid commercial Neptus licences may use this file + * in accordance with the commercial licence agreement provided with the + * Software or, alternatively, in accordance with the terms contained in a + * written agreement between you and Universidade do Porto. For licensing + * terms, conditions, and further information contact lsts@fe.up.pt. + * + * Modified European Union Public Licence - EUPL v.1.1 Usage + * Alternatively, this file may be used under the terms of the Modified EUPL, + * Version 1.1 only (the "Licence"), appearing in the file LICENSE.md + * included in the packaging of this file. You may not use this work + * except in compliance with the Licence. Unless required by applicable + * law or agreed to in writing, software distributed under the Licence is + * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF + * ANY KIND, either express or implied. See the Licence for the specific + * language governing permissions and limitations at + * https://github.com/LSTS/neptus/blob/develop/LICENSE.md + * and http://ec.europa.eu/idabc/eupl.html. + * + * For more information please see . + * + * Author: Paulo Dias + * 8/11/2023 + */ +package pt.lsts.neptus.plugins.remoteactionsextra; + +import pt.lsts.imc.EntityState; +import pt.lsts.imc.VehicleState; +import pt.lsts.neptus.console.events.ConsoleEventMainSystemChange; + +import javax.swing.JButton; +import java.awt.Color; + +class TakeControlMonitor { + private static final Color COLOR_IN_CONTROL = new Color(144, 255, 0, 128); + private static final Color COLOR_ASKED_CONTROL = new Color(255, 221, 0, 128); + private static final Color COLOR_ERR_CONTROL = new Color(255, 0, 0, 128); + private static final Color COLOR_NO_INFO_CONTROL = null; + + private final RemoteActionsExtra parent; + private String entityName = "OBS Broker"; + private JButton button; + private EntityState.STATE entState = null; + private VehicleState.OP_MODE opMode = null; + + public TakeControlMonitor(RemoteActionsExtra parent, JButton button) { + this.parent = parent; + this.button = button; + } + + public TakeControlMonitor(RemoteActionsExtra parent) { + this.parent = parent; + this.button = null; + } + + public String getEntityName() { + return entityName; + } + + public void setEntityName(String entityName) { + if (!entityName.equalsIgnoreCase(this.entityName)) { + reset(); + } + + this.entityName = entityName; + } + + private void reset() { + entState = null; + opMode = null; + resetControl(); + } + + public JButton getButton() { + return button; + } + + public void setButton(JButton button) { + this.button = button; + } + + public void on(ConsoleEventMainSystemChange evt) { + reset(); + } + + public void on(EntityState msg) { + if (!msg.getSourceName().equals(parent.getMainVehicleId()) + || !msg.getEntityName().equals(entityName)) { + return; + } + + entState = msg.getState(); + updateState(); + } + + public void on(VehicleState msg) { + if (!msg.getSourceName().equals(parent.getMainVehicleId())) { + return; + } + + opMode = msg.getOpMode(); + updateState(); + } + + private void updateState() { + if (button == null) return; + if (entState == null) return; + if (opMode == null) return; + + boolean isExternal = false; + switch (opMode) { + case EXTERNAL: + isExternal = true; + break; + case BOOT: + case ERROR: + case MANEUVER: + case CALIBRATION: + case SERVICE: + default: + break; + } + + switch (entState) { + case NORMAL: + if (isExternal) { + askedControl(); + } else { + inControl(); + } + break; + case ERROR: + case BOOT: + case FAULT: + case FAILURE: + default: + noControl(); + break; + } + } + + void askedControl() { + changeColor(COLOR_ASKED_CONTROL); + } + + private void inControl() { + changeColor(COLOR_IN_CONTROL); + } + + private void noControl() { + changeColor(COLOR_ERR_CONTROL); + } + + private void resetControl() { + changeColor(COLOR_NO_INFO_CONTROL); + } + + private void changeColor(Color color) { + if (button == null) return; + + button.setBackground(color); + button.revalidate(); + button.repaint(100); + } +}