diff --git a/settings.gradle b/settings.gradle index f6ec52ab..6ca3c545 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,6 +15,7 @@ if(build_simulator_java) include 'snobot_sim_utilities' include 'snobot_sim_gui' +include 'snobot_sim_gui_javafx' include 'snobot_sim_joysticks' include 'snobot_sim_example_robot' diff --git a/snobot_sim_gui/build.gradle b/snobot_sim_gui/build.gradle index 37b6d2b6..0b515f43 100644 --- a/snobot_sim_gui/build.gradle +++ b/snobot_sim_gui/build.gradle @@ -29,7 +29,8 @@ dependencies { // 3rd Party - native3rdPartyDeps 'net.java.jinput:jinput:2.0.9' + compile 'net.java.jinput:jinput:2.0.9' + wpilibNativeDeps 'net.java.jinput:jinput:2.0.9:natives-all' compile 'jfree:jcommon:1.0.16' compile 'jfree:jfreechart:1.0.13' compile 'org.apache.logging.log4j:log4j-api:2.12.0' diff --git a/snobot_sim_gui_javafx/build.gradle b/snobot_sim_gui_javafx/build.gradle new file mode 100644 index 00000000..ed0f4249 --- /dev/null +++ b/snobot_sim_gui_javafx/build.gradle @@ -0,0 +1,128 @@ + +evaluationDependsOn(':snobot_sim_utilities') +evaluationDependsOn(':sim_adx_family') +evaluationDependsOn(':sim_extension_navx') + +ext +{ + baseId = "snobot_sim_gui_javafx" +} + +apply from: "${rootDir}/common/base_java_script.gradle" + +configurations { + native3rdPartyDeps + compile.extendsFrom(native3rdPartyDeps) +} + +configurations.maybeCreate("wpilibNativeDeps") +dependencies { + + compile "org.openjfx:javafx-base:11:win" + compile "org.openjfx:javafx-graphics:11:win" + compile "org.openjfx:javafx-controls:11:win" + compile "org.openjfx:javafx-fxml:11:win" + + // WPILib + compile 'edu.wpi.first.wpilibj:wpilibj-java:' + allwpilibVersion() + compile 'edu.wpi.first.wpiutil:wpiutil-java:' + getWpiUtilVersion() + compile 'edu.wpi.first.cscore:cscore-java:' + getCsCoreVersion() + runtime 'edu.wpi.first.cscore:cscore-jni:' + getCsCoreVersion() + ':all' + compile 'edu.wpi.first.ntcore:ntcore-java:' + getNtCoreVersion() + runtime 'edu.wpi.first.ntcore:ntcore-jni:' + getNtCoreVersion() + ':all' + runtime 'edu.wpi.first.hal:hal-jni:' + allwpilibVersion() + ':all' + compile 'org.opencv:opencv-java:' + getWpilibOpencvVersion() + runtime 'org.opencv:opencv-jni:' + getWpilibOpencvVersion() + ':all' + + // 3rd Party + compile 'net.java.jinput:jinput:2.0.9' + wpilibNativeDeps 'net.java.jinput:jinput:2.0.9:natives-all' + compile 'jfree:jcommon:1.0.16' + compile 'jfree:jfreechart:1.0.13' + compile 'org.apache.logging.log4j:log4j-api:2.11.0' + compile 'org.apache.logging.log4j:log4j-core:2.11.0' + compile 'org.yaml:snakeyaml:1.18' + compile 'com.miglayout:miglayout-swing:4.2' + //compile 'org.python:jython:2.7.1b3' + + // Internal + compile project(":snobot_sim_utilities") + compile project(":snobot_sim_joysticks") + + if(build_simulator_cpp) + { + compile project(":snobot_sim_jni") + wpilibNativeDeps project(':snobot_sim_jni').packageNativeFiles.outputs.files + } + + if(build_simulator_java) + { + compile project(":snobot_sim_java") + wpilibNativeDeps project(':sim_extension_navx').packageNativeFiles.outputs.files + wpilibNativeDeps project(':sim_adx_family').packageNativeFiles.outputs.files + } + + // Test + testCompile 'org.junit.jupiter:junit-jupiter-api:5.2.0' + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.2.0' + testRuntime 'org.junit.platform:junit-platform-launcher:1.2.0' + runtime 'com.snobot.simulator:ctre_sim_override:' + getCtreSimVersion() + ':all' + runtime 'com.snobot.simulator:rev_simulator:' + getRevRoboticsSimVersion() + ':all' +} + +apply from: "${rootDir}/common/extract_native_libraries.gradle" +test.dependsOn extract_wpilib + + +task unzipNativeLibraries(type: Copy) { + + configurations.native3rdPartyDeps.each { + from zipTree(it) + into "build/native_libs" + include "**/*.dll" + include "**/*.lib" + include "**/*.pdb" + include "**/*.so*" + include "**/*.a" + include "**/*.dylib*" + } + + includeEmptyDirs = false + +} + +eclipse.classpath.file { + whenMerged { classpath -> + classpath.entries.each { + if(it.path.contains("jinput") && !it.path.contains("natives")) { + it.setNativeLibraryLocation("snobot_sim_gui_javafx/build/native_libs") + } + } + } +} + +build.dependsOn unzipNativeLibraries + +if(build_simulator_cpp) +{ + compileJava.dependsOn(":snobot_sim_jni:build") +} +if(build_simulator_java) +{ + compileJava.dependsOn(":snobot_sim_java:build") +} + +sourceSets.main.java.srcDir "${buildDir}/generated/java/" +compileJava { + apply from: "${rootDir}/common/create_version_file.gradle" + createJavaVersion("com/snobot/simulator", "SnobotSimGuiVersion", "com.snobot.simulator", getVersionName()) +} + +clean { + delete "src/main/java/com/snobot/simulator/SnobotSimGuiVersion.java" +} + + +spotbugs { + ignoreFailures = true +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/BaseSimulator.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/BaseSimulator.java new file mode 100644 index 00000000..c06f8ba6 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/BaseSimulator.java @@ -0,0 +1,45 @@ +package com.snobot.simulator; + +import com.snobot.simulator.config.v1.SimulatorConfigReaderV1; +import com.snobot.simulator.robot_container.IRobotClassContainer; + +/** + * Base class for a custom simulator. + * + * @author PJ + * + */ +public class BaseSimulator implements ISimulatorUpdater +{ + private final SimulatorConfigReaderV1 mConfigReader; + private String mConfigFile; + + protected BaseSimulator() + { + mConfigReader = new SimulatorConfigReaderV1(); + } + + public boolean loadConfig(String aConfigFile) + { + mConfigFile = aConfigFile; + return mConfigReader.loadConfig(mConfigFile); + } + + + @Override + public void update() + { + // Nothing to do + } + + @Override + public void setRobot(IRobotClassContainer aRobot) + { + // Nothing to do + } + + public String getConfigFile() + { + return mConfigFile; + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/DefaultDataAccessorFactory.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/DefaultDataAccessorFactory.java new file mode 100644 index 00000000..1c1923e6 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/DefaultDataAccessorFactory.java @@ -0,0 +1,28 @@ +package com.snobot.simulator; + +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; +import com.snobot.simulator.wrapper_accessors.java.JavaDataAccessor; + +/** + * Helper class that sets up the data accessor abstraction layer + * + * @author PJ + * + */ +public final class DefaultDataAccessorFactory +{ + private static final boolean sINITIALIZED = false; + + private DefaultDataAccessorFactory() + { + + } + + public static void initalize() + { + if (!sINITIALIZED) + { + DataAccessorFactory.setAccessor(new JavaDataAccessor()); + } + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/ISimulatorUpdater.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/ISimulatorUpdater.java new file mode 100644 index 00000000..b06ce30a --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/ISimulatorUpdater.java @@ -0,0 +1,11 @@ +package com.snobot.simulator; + +import com.snobot.simulator.robot_container.IRobotClassContainer; + +public interface ISimulatorUpdater +{ + + public abstract void update(); + + public abstract void setRobot(IRobotClassContainer aRobot); +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/Main.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/Main.java new file mode 100644 index 00000000..749c5101 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/Main.java @@ -0,0 +1,22 @@ +package com.snobot.simulator; + +import com.sun.javafx.application.LauncherImpl; + +public final class Main +{ + private Main() + { + + } + + public static void main(String[] aArgs) + { + DefaultDataAccessorFactory.initalize(); + + // JavaFX 11+ uses GTK3 by default, and has problems on some display + // servers + // This flag forces JavaFX to use GTK2 + // System.setProperty("jdk.gtk.version", "2"); + LauncherImpl.launchApplication(SimulatorApplication.class, SimulatorPreloader.class, aArgs); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/RobotContainerFactory.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/RobotContainerFactory.java new file mode 100644 index 00000000..95b7170d --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/RobotContainerFactory.java @@ -0,0 +1,51 @@ +package com.snobot.simulator; + +import java.io.File; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; + +import com.snobot.simulator.robot_container.CppRobotContainer; +import com.snobot.simulator.robot_container.IRobotClassContainer; +import com.snobot.simulator.robot_container.JavaRobotContainer; + +import edu.wpi.first.networktables.NetworkTableInstance; + +public final class RobotContainerFactory +{ + private RobotContainerFactory() + { + + } + + public static IRobotClassContainer createRobotContainer(File aConfigDirectory, String aRobotType, String aRobotClassName) + throws ReflectiveOperationException + { + LogManager.getLogger(RobotContainerFactory.class).log(Level.INFO, "Starting Robot Code"); + + IRobotClassContainer mRobot; + + if (aRobotType == null || "java".equals(aRobotType)) + { + mRobot = new JavaRobotContainer(aRobotClassName); + } + else if ("cpp".equals(aRobotType)) + { + mRobot = new CppRobotContainer(aRobotClassName); + } + else + { + throw new RuntimeException("Unsupported robot type " + aRobotType); + } + + mRobot.constructRobot(); + + // Change the network table preferences path. Need to start + // the robot, stop the server and restart it + NetworkTableInstance inst = NetworkTableInstance.getDefault(); + inst.stopServer(); + inst.startServer(aConfigDirectory.toString() + "/networktables.ini"); + + return mRobot; + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/Simulator.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/Simulator.java new file mode 100644 index 00000000..fb18850e --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/Simulator.java @@ -0,0 +1,197 @@ +package com.snobot.simulator; + +import java.io.File; +import java.util.function.Consumer; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.snobot.simulator.SimulatorPreloader.StateNotification.StateNotificationType; +import com.snobot.simulator.gui.SimulatorFrameController; +import com.snobot.simulator.joysticks.IJoystickInterface; +import com.snobot.simulator.joysticks.NullJoystickInterface; +import com.snobot.simulator.joysticks.SnobotSimJoystickInterface; +import com.snobot.simulator.robot_container.IRobotClassContainer; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; +import com.snobot.simulator.wrapper_accessors.SimulatorDataAccessor.SnobotLogLevel; + +import edu.wpi.first.wpilibj.DriverStation; +import javafx.application.Platform; +import javafx.concurrent.Service; +import javafx.concurrent.Task; + +public class Simulator +{ + private static final Logger LOGGER = LogManager.getLogger(Simulator.class); + + private IRobotClassContainer mRobot; // The robot code to run + private BaseSimulator mSimulator; // The simulator for the robot + private final File mUserConfigDirectory; + private final SimulatorFrameController mController; + private final IJoystickInterface mJoystickInterface; + + protected Thread mRobotThread; + protected Thread mSimulatorThread; + protected boolean mRunningSimulator; + protected final boolean mUseSnobotSimDriverStation; + + /** + * Constructor + * + * @param aLogLevel + * The log level to set up the simulator with + * @param aUserConfigDir + * The config directory where settings are saved + * @throws Exception + * Throws an exception if the plugin loading failed + */ + public Simulator(SimulatorFrameController aController, SnobotLogLevel aLogLevel, String aUserConfigDir, boolean aUseSnobotSimDriverstation) + throws Exception + { + mUserConfigDirectory = new File(aUserConfigDir); + mController = aController; + mUseSnobotSimDriverStation = aUseSnobotSimDriverstation; + + if (mUseSnobotSimDriverStation) + { + mJoystickInterface = new SnobotSimJoystickInterface(); + } + else + { + mJoystickInterface = new NullJoystickInterface(); + } + } + + protected void showInitializationMessage() + { + String message = DataAccessorFactory.getInstance().getInitializationErrors(); + if (message != null && !message.isEmpty()) + { + System.out.println("Initialization warning"); +// String message = "Some simulator components were specified in the config file, but not in the robot.
" +// + "They will be removed from the simulator registery, to make it easier to fix your config file."; +// JLabel label = new JLabel(message); +// label.setFont(new Font("serif", Font.PLAIN, 14)); +// +// JOptionPane.showMessageDialog(null, label, "Config file mismatch", JOptionPane.ERROR_MESSAGE); + } + } + + public void setupSimulator(Consumer aProgressCallback) throws ReflectiveOperationException + { + aProgressCallback.accept(new SimulatorPreloader.StateNotification(StateNotificationType.LoadingSimulatorProperties)); + SimulatorPropertiesLoader propertyLoader = new SimulatorPropertiesLoader(); + propertyLoader.loadProperties(mUserConfigDirectory); + + // Force the jinput libraries to load + mJoystickInterface.sendJoystickUpdate(); + + mSimulator = propertyLoader.getSimulator(); + + aProgressCallback.accept(new SimulatorPreloader.StateNotification(StateNotificationType.CreatingRobot)); + mRobot = RobotContainerFactory.createRobotContainer(mUserConfigDirectory, propertyLoader.getRobotType(), propertyLoader.getRobotClassName()); + + if (mRobot == null) + { + throw new IllegalArgumentException("Cannot start, could not create robot class"); + } + else if (mSimulator == null) + { + throw new IllegalArgumentException("Cannot start, could not create simulator class"); + } + else + { + mRobotThread = new Thread(createRobotThread(), "RobotThread"); + + mRunningSimulator = true; + LOGGER.log(Level.INFO, "Starting simulator"); + + aProgressCallback.accept(new SimulatorPreloader.StateNotification(StateNotificationType.StartingRobotThread)); + mRobotThread.start(); + + aProgressCallback.accept(new SimulatorPreloader.StateNotification(StateNotificationType.WaitingForProgramToStart)); + DataAccessorFactory.getInstance().getDriverStationAccessor().waitForProgramToStart(); + + showInitializationMessage(); + mSimulator.setRobot(mRobot); + + mController.initialize(mUserConfigDirectory + "/simulator_config.yml", mUseSnobotSimDriverStation); + + aProgressCallback.accept(new SimulatorPreloader.StateNotification(StateNotificationType.Finished)); + } + } + + public void startSimulation() + { + createSimulatorBackgroundService().start(); + } + + private Runnable createRobotThread() + { + return new Runnable() + { + + @Override + public void run() + { + + try + { + DriverStation.getInstance(); + mJoystickInterface.waitForLoop(); + mRobot.startCompetition(); + } + catch (UnsatisfiedLinkError e) + { + throw new RuntimeException( + "Unsatisfied link error. This likely means that there is a native " + + "call in WpiLib or the NetworkTables libraries. Please tell PJ so he can mock it out.\n\nError Message: " + e, + e); + } + catch (Exception e) + { + throw new RuntimeException("Unexpected exception, shutting down simulator", e); + } + } + }; + } + + private Service createSimulatorBackgroundService() + { + return new Service() + { + @Override + protected Task createTask() + { + return new Task() + { + @Override + protected Void call() throws Exception + { + DataAccessorFactory.getInstance().getDriverStationAccessor().setDisabled(false); + + while (mRunningSimulator) + { + mJoystickInterface.waitForLoop(); + DataAccessorFactory.getInstance().getSimulatorDataAccessor().updateSimulatorComponents(); + mSimulator.update(); + mJoystickInterface.sendJoystickUpdate(); + + Platform.runLater(() -> mController.updateLoop()); + } + + return null; + } + }; + } + }; + } + + public void stop() + { + mRunningSimulator = false; + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorApplication.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorApplication.java new file mode 100644 index 00000000..a92ca553 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorApplication.java @@ -0,0 +1,63 @@ +package com.snobot.simulator; + +import com.snobot.simulator.SimulatorPreloader.StateNotification.StateNotificationType; +import com.snobot.simulator.gui.SimulatorFrameController; +import com.snobot.simulator.wrapper_accessors.SimulatorDataAccessor.SnobotLogLevel; + +import javafx.application.Application; +import javafx.application.Preloader.PreloaderNotification; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.layout.Pane; +import javafx.stage.Screen; +import javafx.stage.Stage; + +public class SimulatorApplication extends Application +{ + private static final String USER_CONFIG_DIR = "simulator_config/"; + + private Simulator mSimulator; + private Pane mMainPane; + + @Override + public void init() throws Exception + { + boolean useSnobotSimDriverstation = !getParameters().getRaw().contains("--use_native_ds"); + + notifyPreloader(new SimulatorPreloader.StateNotification(StateNotificationType.Starting)); + + FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/snobot/simulator/gui/simulator_frame.fxml")); + mMainPane = loader.load(); + SimulatorFrameController controller = loader.getController(); + + mSimulator = new Simulator(controller, SnobotLogLevel.DEBUG, USER_CONFIG_DIR, useSnobotSimDriverstation); + mSimulator.setupSimulator(this::notifyPreloader2); + + } + + public final void notifyPreloader2(PreloaderNotification aInfo) + { + notifyPreloader(aInfo); + } + + @Override + public void start(Stage aPrimaryStage) throws Exception + { + aPrimaryStage.setScene(new Scene(mMainPane)); + aPrimaryStage.setTitle("SnobotSim"); + aPrimaryStage.setMinWidth(300); + aPrimaryStage.setMinHeight(480); + aPrimaryStage.setWidth(300); + aPrimaryStage.setHeight(Screen.getPrimary().getVisualBounds().getHeight()); + + aPrimaryStage.show(); + + mSimulator.startSimulation(); + + aPrimaryStage.setOnCloseRequest(closeEvent -> + { + // There is no way to stop the robot thread, so kill it with fire + System.exit(0); + }); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorPreloader.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorPreloader.java new file mode 100644 index 00000000..bc6da9cb --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorPreloader.java @@ -0,0 +1,85 @@ +package com.snobot.simulator; + +import javafx.application.Preloader; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.layout.Pane; +import javafx.stage.Stage; +import javafx.stage.StageStyle; + +public class SimulatorPreloader extends Preloader +{ + private Stage mPreloaderStage; + private SimulatorPreloaderController mController; + + @Override + public void start(Stage aStage) throws Exception + { + mPreloaderStage = aStage; + + FXMLLoader loader = new FXMLLoader(SimulatorPreloader.class.getResource("preloader.fxml")); + + Pane preloaderPane = loader.load(); + mController = loader.getController(); + + Scene scene = new Scene(preloaderPane); + + aStage.setScene(scene); + aStage.initStyle(StageStyle.UNDECORATED); + aStage.show(); + } + + @Override + public void handleApplicationNotification(PreloaderNotification aInfo) + { + StateNotification notification = (StateNotification) aInfo; + System.out.println("Getting notification...." + aInfo); + mController.setStateText(notification.getState()); + mController.setProgress(notification.getProgress()); + } + + @Override + public void handleStateChangeNotification(StateChangeNotification aInfo) + { + if (aInfo.getType() == StateChangeNotification.Type.BEFORE_START) + { + mPreloaderStage.close(); + } + } + + public static final class StateNotification implements PreloaderNotification + { + public static enum StateNotificationType + { + Starting, + LoadingSimulatorProperties, + CreatingRobot, + StartingRobotThread, + WaitingForProgramToStart, + Finished; + } + + private final StateNotificationType mState; + + public StateNotification(StateNotificationType aState) + { + mState = aState; + } + + public double getProgress() + { + return mState.ordinal() / (StateNotificationType.values().length - 1.0); + } + + public String getState() + { + return mState.toString(); + } + + @Override + public String toString() + { + return mState.toString(); + } + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorPreloaderController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorPreloaderController.java new file mode 100644 index 00000000..307b2803 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorPreloaderController.java @@ -0,0 +1,38 @@ +package com.snobot.simulator; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.scene.layout.Pane; + +public class SimulatorPreloaderController +{ + @FXML + private Pane mRoot; + @FXML + private Pane mBackgroundContainer; + @FXML + private Label mVersionLabel; + @FXML + private Label mStateLabel; + @FXML + private ProgressBar mProgressBar; + + @FXML + private void initialize() + { + mProgressBar.setProgress(-1); + mVersionLabel.setText(SnobotSimGuiVersion.Version); + } + + public void setStateText(String aText) + { + mStateLabel.setText(aText); + } + + public void setProgress(double aProgress) + { + mProgressBar.setProgress(aProgress); + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorPropertiesLoader.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorPropertiesLoader.java new file mode 100644 index 00000000..7d4966c6 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/SimulatorPropertiesLoader.java @@ -0,0 +1,120 @@ +package com.snobot.simulator; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.Properties; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class SimulatorPropertiesLoader +{ + private static final Logger LOGGER = LogManager.getLogger(SimulatorPropertiesLoader.class); + + private String mRobotClassName; + private String mRobotType; + private BaseSimulator mSimulator; + + public void loadProperties(File aConfigDirectory) + { + File propertiesFile = new File(aConfigDirectory, "simulator_config.properties"); + + try + { + if (!propertiesFile.exists()) + { + createDefaultConfig(aConfigDirectory, propertiesFile); + } + + Properties p = new Properties(); + + try (FileInputStream fis = new FileInputStream(propertiesFile)) + { + p.load(fis); + } + + mRobotClassName = p.getProperty("robot_class"); + mRobotType = p.getProperty("robot_type"); + + String simulatorClassName = p.getProperty("simulator_class"); + + createSimulator(simulatorClassName, p.getProperty("simulator_config")); + } + catch (IOException ex) + { + LOGGER.log(Level.WARN, "Could not read properties file", ex); + } + } + + private void createDefaultConfig(File aConfigDirectory, File aPropertiesFile) throws IOException + { + LOGGER.log(Level.WARN, "Could not read properties file, will use defaults and will overwrite the file if it exists"); + + if (!aConfigDirectory.exists() && !aConfigDirectory.mkdirs()) + { + throw new IllegalStateException(); + } + + String defaultSimConfig = aConfigDirectory + "/simulator_config.yml"; + Properties defaults = new Properties(); + + defaults.putIfAbsent("robot_class", "com.snobot.simulator.example_robot.ExampleRobot"); + defaults.putIfAbsent("robot_type", "java"); + defaults.putIfAbsent("simulator_config", defaultSimConfig); + + File defaultConfigFile = new File(defaultSimConfig); + if (!defaultConfigFile.exists() && !defaultConfigFile.createNewFile()) + { + LOGGER.log(Level.WARN, "Could not create default config file at " + defaultConfigFile); + } + + try (OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(aPropertiesFile), StandardCharsets.UTF_8)) + { + defaults.store(fw, ""); + } + } + + private void createSimulator(String aSimulatorClassName, String aSimulatorConfig) + { + try + { + if (aSimulatorClassName == null || aSimulatorClassName.isEmpty()) + { + mSimulator = new BaseSimulator(); + mSimulator.loadConfig(aSimulatorConfig); + + LOGGER.log(Level.DEBUG, "Created default simulator"); + } + else + { + mSimulator = (BaseSimulator) Class.forName(aSimulatorClassName).getDeclaredConstructor().newInstance(); + mSimulator.loadConfig(aSimulatorConfig); + LOGGER.log(Level.INFO, aSimulatorClassName); + } + } + catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) + { + LOGGER.log(Level.FATAL, "Could not find simulator class " + aSimulatorClassName, e); + } + } + + public String getRobotType() + { + return mRobotType; + } + + public String getRobotClassName() + { + return mRobotClassName; + } + + public BaseSimulator getSimulator() + { + return mSimulator; + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/TestMain.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/TestMain.java new file mode 100644 index 00000000..299d10f2 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/TestMain.java @@ -0,0 +1,65 @@ +package com.snobot.simulator; + +import com.snobot.simulator.gui.motor_graphs.MotorCurveDisplayController; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.event.EventHandler; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.layout.Pane; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; + +public final class TestMain +{ + private TestMain() + { + + } + + public static class PseudoMain extends Application + { + @Override + public void start(Stage aPrimaryStage) throws Exception + { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/snobot/simulator/gui/motor_graphs/motor_curve_display.fxml")); + Pane root = loader.load(); + MotorCurveDisplayController controller = loader.getController(); + + + Scene scene = new Scene(root); + aPrimaryStage.setScene(scene); + aPrimaryStage.show(); + controller.setCurveParams("CIM", 12, 5330, 131, 2.7, 2.410); + + aPrimaryStage.setOnHidden(new EventHandler() + { + + @Override + public void handle(WindowEvent aEvent) + { + Platform.runLater(new Runnable() + { + @Override + public void run() + { + System.exit(0); + } + }); + } + }); + } + } + + public static void main(String[] aArgs) + { + DefaultDataAccessorFactory.initalize(); + + // JavaFX 11+ uses GTK3 by default, and has problems on some display + // servers + // This flag forces JavaFX to use GTK2 + // System.setProperty("jdk.gtk.version", "2"); + Application.launch(PseudoMain.class, aArgs); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/example_robot/ExampleRobot.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/example_robot/ExampleRobot.java new file mode 100644 index 00000000..4e958e90 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/example_robot/ExampleRobot.java @@ -0,0 +1,153 @@ +package com.snobot.simulator.example_robot; + +import edu.wpi.first.wpilibj.ADXL345_I2C; +import edu.wpi.first.wpilibj.ADXRS450_Gyro; +import edu.wpi.first.wpilibj.AnalogGyro; +import edu.wpi.first.wpilibj.AnalogOutput; +import edu.wpi.first.wpilibj.DriverStation; +import edu.wpi.first.wpilibj.Encoder; +import edu.wpi.first.wpilibj.I2C; +import edu.wpi.first.wpilibj.Joystick; +import edu.wpi.first.wpilibj.Relay; +import edu.wpi.first.wpilibj.Relay.Value; +import edu.wpi.first.wpilibj.Solenoid; +import edu.wpi.first.wpilibj.SpeedController; +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.Timer; +import edu.wpi.first.wpilibj.VictorSP; +import edu.wpi.first.wpilibj.interfaces.Accelerometer; +import edu.wpi.first.wpilibj.interfaces.Gyro; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; + +/** + * Example robot used in the event that no robot to simulate is specified. Does + * a simple simulation by hooking up a few commonly used components + * + * @author PJ + * + */ +public class ExampleRobot extends TimedRobot +{ + private Joystick mJoystick; + private Solenoid mSolenoid; + private SpeedController mLeftDrive; + private SpeedController mRightDrive; + private Relay mTestRelay; + private AnalogOutput mAnalogOut; + private Encoder mLeftDriveEncoder; + private Encoder mRightDriveEncoder; + private Gyro mAnalogGyro; + private Gyro mSpiGyro; + private ADXL345_I2C mAdxAccelerometer; + + private Timer mAutoTimer; + + @Override + public void robotInit() + { + mJoystick = new Joystick(0); + + mSolenoid = new Solenoid(0); + mLeftDrive = new VictorSP(0); + mRightDrive = new VictorSP(1); + mTestRelay = new Relay(0); + mLeftDriveEncoder = new Encoder(0, 1); + mRightDriveEncoder = new Encoder(2, 3); + mAnalogOut = new AnalogOutput(0); + mAnalogGyro = new AnalogGyro(0); + mSpiGyro = new ADXRS450_Gyro(); + mAdxAccelerometer = new ADXL345_I2C(I2C.Port.kMXP, Accelerometer.Range.k2G); + + mAutoTimer = new Timer(); + + mLeftDriveEncoder.setDistancePerPulse(.01); + mRightDriveEncoder.setDistancePerPulse(.01); + + String errorMessage = "Warning, this is the example robot bundled with the simulator!\n"; + errorMessage += "To configure this for your robot, change /simulator_config/simulator_config.properties, and update the robot_class field"; // NOPMD + + System.err.println(errorMessage); // NOPMD + } + + @Override + public void autonomousInit() + { + mLeftDriveEncoder.reset(); + mRightDriveEncoder.reset(); + mAutoTimer.start(); + + System.out.println("Game Information: "); // NOPMD + System.out.println(" Match Number : " + DriverStation.getInstance().getMatchNumber()); // NOPMD + System.out.println(" Match Replay : " + DriverStation.getInstance().getReplayNumber()); // NOPMD + System.out.println(" Match Type : " + DriverStation.getInstance().getMatchType()); // NOPMD + System.out.println(" Event Name : " + DriverStation.getInstance().getEventName()); // NOPMD + System.out.println(" Game Info : " + DriverStation.getInstance().getGameSpecificMessage()); // NOPMD + } + + @Override + public void autonomousPeriodic() + { + if (mAutoTimer.get() < 2) + { + mLeftDrive.set(1); + mRightDrive.set(-1); + } + else + { + mLeftDrive.set(0); + mRightDrive.set(0); + } + } + + @Override + public void teleopPeriodic() + { + mLeftDrive.set(mJoystick.getRawAxis(1)); + mRightDrive.set(-mJoystick.getRawAxis(5)); + + mSolenoid.set(mJoystick.getRawButton(1)); + + if (mJoystick.getRawButton(2)) + { + mTestRelay.set(Value.kForward); + } + else if (mJoystick.getRawButton(3)) + { + mTestRelay.set(Value.kReverse); + } + else if (mJoystick.getRawButton(4)) + { + mTestRelay.set(Value.kOn); + } + else + { + mTestRelay.set(Value.kOff); + } + + if (mJoystick.getRawButton(5)) + { + mAnalogOut.setVoltage(2.5); + } + else if (mJoystick.getRawButton(6)) + { + mAnalogOut.setVoltage(5.0); + } + else + { + mAnalogOut.setVoltage(0); + } + + SmartDashboard.putNumber("Left Enc", mLeftDriveEncoder.getDistance()); + SmartDashboard.putNumber("Right Enc", mRightDriveEncoder.getDistance()); + SmartDashboard.putNumber("Analog Gyro", mAnalogGyro.getAngle()); + SmartDashboard.putNumber("SPI Gyro", mSpiGyro.getAngle()); + SmartDashboard.putNumber("I2C Accelerometer", mAdxAccelerometer.getX()); + } + + @Override + public void disabledPeriodic() + { + // Nothing to do + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/ConfigurationPaneController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/ConfigurationPaneController.java new file mode 100644 index 00000000..07103437 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/ConfigurationPaneController.java @@ -0,0 +1,78 @@ +package com.snobot.simulator.gui; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.TitledPane; +import javafx.scene.layout.Pane; + +public class ConfigurationPaneController +{ + @FXML + private Pane mMainPane; + + private final List mControllers; + + public ConfigurationPaneController() + { + mControllers = new ArrayList<>(); + } + + public void loadWidgets(Supplier aSaveFunction) + { + try + { + initializeWidgetGroup(aSaveFunction, "Speed Controllers", DataAccessorFactory.getInstance().getSpeedControllerAccessor().getPortList(), + "/com/snobot/simulator/gui/widgets/speed_controller_widget.fxml"); + initializeWidgetGroup(aSaveFunction, "Solenoids", DataAccessorFactory.getInstance().getSolenoidAccessor().getPortList(), + "/com/snobot/simulator/gui/widgets/solenoid_widget.fxml"); + initializeWidgetGroup(aSaveFunction, "Digital IO", DataAccessorFactory.getInstance().getDigitalAccessor().getPortList(), + "/com/snobot/simulator/gui/widgets/digital_io_controller_widget.fxml"); + initializeWidgetGroup(aSaveFunction, "Relays", DataAccessorFactory.getInstance().getRelayAccessor().getPortList(), + "/com/snobot/simulator/gui/widgets/relay_widget.fxml"); + initializeWidgetGroup(aSaveFunction, "Analog In", DataAccessorFactory.getInstance().getAnalogInAccessor().getPortList(), + "/com/snobot/simulator/gui/widgets/analog_in_widget.fxml"); + initializeWidgetGroup(aSaveFunction, "Analog Out", DataAccessorFactory.getInstance().getAnalogOutAccessor().getPortList(), + "/com/snobot/simulator/gui/widgets/analog_out_widget.fxml"); + initializeWidgetGroup(aSaveFunction, "Encoders", DataAccessorFactory.getInstance().getEncoderAccessor().getPortList(), + "/com/snobot/simulator/gui/widgets/encoder_widget.fxml"); + initializeWidgetGroup(aSaveFunction, "Gyros", DataAccessorFactory.getInstance().getGyroAccessor().getPortList(), + "/com/snobot/simulator/gui/widgets/gyro_widget.fxml"); + initializeWidgetGroup(aSaveFunction, "Accelerometers", DataAccessorFactory.getInstance().getAccelerometerAccessor().getPortList(), + "/com/snobot/simulator/gui/widgets/accelerometer_widget.fxml"); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } + + private void initializeWidgetGroup(Supplier aSaveFunction, String aGroupName, List aIds, String aFxmlConfig) throws IOException + { + FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/snobot/simulator/gui/widget_group.fxml")); + Pane newGroup = loader.load(); + + TitledPane titlePane = new TitledPane(aGroupName, newGroup); + + mMainPane.getChildren().add(titlePane); + + WidgetGroupController controller = loader.getController(); + controller.initialize(aSaveFunction, aIds, aFxmlConfig); + + mControllers.add(controller); + } + + public void update() + { + for (WidgetGroupController controller : mControllers) + { + controller.update(); + } + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/EnablePanelController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/EnablePanelController.java new file mode 100644 index 00000000..dee8f3a1 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/EnablePanelController.java @@ -0,0 +1,50 @@ +package com.snobot.simulator.gui; + +import java.text.DecimalFormat; + +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import edu.wpi.first.wpilibj.DriverStation; +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; + +public class EnablePanelController +{ + private static final DecimalFormat MATCH_TIME_FORMAT = new DecimalFormat("000.00"); + + @FXML + private Label mMatchTime; + + @FXML + private CheckBox mEnableButton; + + @FXML + private CheckBox mAutonButton; + + public void setUseSnobotSim(boolean aUseSnobotSimDriverstation) + { + mEnableButton.setDisable(!aUseSnobotSimDriverstation); + mAutonButton.setDisable(!aUseSnobotSimDriverstation); + } + + public void setTime(double aTime) + { + mMatchTime.setText(MATCH_TIME_FORMAT.format(aTime)); + } + + public void updateLoop(boolean aUseSnobotSimDriverstation) + { + + if (aUseSnobotSimDriverstation) + { + setTime(DataAccessorFactory.getInstance().getDriverStationAccessor().getTimeSinceEnabled()); + } + else + { + setTime(DriverStation.getInstance().getMatchTime()); + mEnableButton.setSelected(DriverStation.getInstance().isEnabled()); + mAutonButton.setSelected(DriverStation.getInstance().isAutonomous()); + } + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/SimulatorFrameController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/SimulatorFrameController.java new file mode 100644 index 00000000..c9b95928 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/SimulatorFrameController.java @@ -0,0 +1,70 @@ +package com.snobot.simulator.gui; + +import com.snobot.simulator.config.SimulatorConfigWriter; +import com.snobot.simulator.gui.joysticks.JoystickManagerController; +import com.snobot.simulator.gui.widgets.AdvancedSettingsController; +import com.snobot.simulator.gui.widgets.settings.DialogRunner; + +import javafx.fxml.FXML; +import javafx.scene.control.Button; + +public class SimulatorFrameController +{ + @FXML + private ConfigurationPaneController mConfigurationPanelController; + + @FXML + private AdvancedSettingsController mAdvancedSettingsWidgetController; + + @FXML + private EnablePanelController mEnablePanelController; + + @FXML + private Button mJoystickSettingsButton; + + private boolean mUseSnobotSimDriverstation; + + private String mSimulatorConfigFile; + + public void initialize(String aSimulatorConfigFile, boolean aUseSnobotSimDriverstation) + { + mUseSnobotSimDriverstation = aUseSnobotSimDriverstation; + mSimulatorConfigFile = aSimulatorConfigFile; + mConfigurationPanelController.loadWidgets(this::saveSettings); + mAdvancedSettingsWidgetController.setSaveCallback(this::saveSettings); + + mEnablePanelController.setUseSnobotSim(mUseSnobotSimDriverstation); + mJoystickSettingsButton.setVisible(mUseSnobotSimDriverstation); + } + + public void updateLoop() + { + mConfigurationPanelController.update(); + mEnablePanelController.updateLoop(mUseSnobotSimDriverstation); + } + + public boolean saveSettings() + { + SimulatorConfigWriter writer = new SimulatorConfigWriter(); + writer.writeConfig(mSimulatorConfigFile); + + return true; + } + + public void setTime(double aTime) + { + mEnablePanelController.setTime(aTime); + } + + @FXML + public void handleJoystickSettingsButton() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/joysticks/joystick_manager_controller.fxml"); + + if (dialog.showAndWait()) + { + System.out.println("XFDF"); + } + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/Util.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/Util.java new file mode 100644 index 00000000..7a233efd --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/Util.java @@ -0,0 +1,43 @@ +package com.snobot.simulator.gui; + +import javafx.scene.paint.Color; + +/** + * + * @author PJ + */ +public final class Util +{ + private Util() + { + // Class is static helper, don't construct it + } + + public static Color getMotorColor(double aSpeed) + { + return colorGetShadedColor(aSpeed, 1, -1); + } + + public static Color colorGetShadedColor(double aSpeed, double aMax, double aMin) // NOPMD + { + if (Double.isNaN(aSpeed)) + { + aSpeed = 0; + } + if (aSpeed > aMax) + { + aSpeed = aMax; + } + else if (aSpeed < aMin) + { + aSpeed = aMin; + } + + double percent = (aSpeed - aMin) / (aMax - aMin); + double hue = percent * 120; + double saturation = 1; + double brightness = 1; + + return Color.hsb(hue, saturation, brightness); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/WidgetGroupController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/WidgetGroupController.java new file mode 100644 index 00000000..f70fb8bb --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/WidgetGroupController.java @@ -0,0 +1,60 @@ +package com.snobot.simulator.gui; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +import com.snobot.simulator.gui.widgets.IWidgetController; + +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.layout.Pane; +import javafx.scene.layout.VBox; + +public class WidgetGroupController +{ + @FXML + public VBox mMainPane; + + private final List mControllers; + + public WidgetGroupController() + { + mControllers = new ArrayList<>(); + } + + public void initialize(Supplier aSaveFunction, List aIds, String aFxmlPath) + { + try + { + for (int id : aIds) + { + + FXMLLoader loader = new FXMLLoader(getClass().getResource(aFxmlPath)); + Pane widgetPane = loader.load(); + mMainPane.getChildren().add(widgetPane); + + IWidgetController controller = loader.getController(); + controller.initialize(id); + controller.setSaveAction(aSaveFunction); + + mControllers.add(controller); + } + } + catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void update() + { + for (IWidgetController controller : mControllers) + { + controller.update(); + } + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/game_data/BaseGameDataController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/game_data/BaseGameDataController.java new file mode 100644 index 00000000..c9e84dd3 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/game_data/BaseGameDataController.java @@ -0,0 +1,52 @@ +package com.snobot.simulator.gui.game_data; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; + +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; +import com.snobot.simulator.wrapper_accessors.DriverStationDataAccessor.MatchType; + +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; +import javafx.scene.control.TextField; + +public abstract class BaseGameDataController +{ + @FXML + protected TextField mMatchNumber; + + @FXML + protected ComboBox mMatchType; + + @FXML + protected TextField mEventName; + + @FXML + public void initialize() + { + mMatchType.getItems().addAll(MatchType.values()); + mMatchType.getSelectionModel().select(MatchType.Practice); + } + + @FXML + protected void handleUpdate() + { + int matchNumber = 1; + + try + { + matchNumber = Integer.parseInt(mMatchNumber.getText()); + } + catch (NumberFormatException ex) + { + LogManager.getLogger().log(Level.ERROR, "Could not parse match number", ex); + } + + System.out.println("Setting game data"); + + DataAccessorFactory.getInstance().getDriverStationAccessor().setMatchInfo(mEventName.getText(), + mMatchType.getSelectionModel().getSelectedItem(), matchNumber, 0, getGameData()); + } + + protected abstract String getGameData(); +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/game_data/GenericGameDataController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/game_data/GenericGameDataController.java new file mode 100644 index 00000000..674ea40e --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/game_data/GenericGameDataController.java @@ -0,0 +1,17 @@ +package com.snobot.simulator.gui.game_data; + + +import javafx.fxml.FXML; +import javafx.scene.control.TextField; + +public class GenericGameDataController extends BaseGameDataController +{ + @FXML + protected TextField mGameData; + + @Override + protected String getGameData() + { + return mGameData.getText(); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/game_data/PowerUpGameDataController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/game_data/PowerUpGameDataController.java new file mode 100644 index 00000000..aaad7f5f --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/game_data/PowerUpGameDataController.java @@ -0,0 +1,24 @@ +package com.snobot.simulator.gui.game_data; + +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; + +public class PowerUpGameDataController extends BaseGameDataController +{ + @FXML + protected ComboBox mGameData; + + @Override + @FXML + public void initialize() + { + mGameData.getSelectionModel().select("LLL"); + super.initialize(); + } + + @Override + protected String getGameData() + { + return mGameData.getSelectionModel().getSelectedItem(); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/ConnectedInputConfigPanelController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/ConnectedInputConfigPanelController.java new file mode 100644 index 00000000..f4e5b294 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/ConnectedInputConfigPanelController.java @@ -0,0 +1,113 @@ +package com.snobot.simulator.gui.joysticks; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.snobot.simulator.gui.joysticks.sub_panels.RawPanelController; +import com.snobot.simulator.gui.joysticks.sub_panels.WrappedPanelController; +import com.snobot.simulator.gui.joysticks.sub_panels.XboxDisplayController; +import com.snobot.simulator.joysticks.ControllerConfiguration; +import com.snobot.simulator.joysticks.IMockJoystick; +import com.snobot.simulator.joysticks.JoystickDiscoverer; +import com.snobot.simulator.joysticks.JoystickFactory; +import com.snobot.simulator.joysticks.joystick_specializations.NullJoystick; + +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; +import net.java.games.input.Controller; +import net.java.games.input.Controller.Type; + +public class ConnectedInputConfigPanelController +{ + private static final Logger LOGGER = LogManager.getLogger(ConnectedInputConfigPanelController.class); + + @FXML + private RawPanelController mRawPanelController; + @FXML + private WrappedPanelController mWrappedPanelController; + @FXML + private XboxDisplayController mXboxPanelController; + @FXML + private ComboBox mInterpretAsComboBox; + + private String mJoystickName; + private Controller mController; + + public void update() + { + mRawPanelController.updateDisplay(); + mWrappedPanelController.updateDisplay(); + mXboxPanelController.updateDisplay(); + } + + public void setJoystick(String aControllerName, IMockJoystick aSelectedJoystick, ControllerConfiguration aConfig) + { + mJoystickName = aControllerName; + mController = aConfig.mController; + + initializeInterpretComboBox(aConfig); + // mXboxPanelController.setJoystick(aSelectedJoystick); + mRawPanelController.setController(aConfig.mController); + } + + private void initializeInterpretComboBox(ControllerConfiguration aConfig) + { + + if (aConfig.mController.getType() == Type.KEYBOARD) + { + mInterpretAsComboBox.getItems().add("Keyboard"); + } + else + { + for (String name : JoystickDiscoverer.getJoystickNames()) + { + mInterpretAsComboBox.getItems().add(name); + } + } + + if (JoystickDiscoverer.getSpecializationTypes().contains(aConfig.mSpecialization)) + { + mInterpretAsComboBox.getSelectionModel().select(JoystickDiscoverer.getSpecialization(aConfig.mSpecialization)); + } + handleWrapperSelected(mInterpretAsComboBox.getSelectionModel().getSelectedItem()); + + mInterpretAsComboBox.valueProperty().addListener((obsValue, oldValue, newValue) -> + { + System.out.println(obsValue + ", " + oldValue + ", " + newValue); + handleWrapperSelected(newValue); + }); + } + + private void handleWrapperSelected(String aType) + { + IMockJoystick wrappedJoystick = null; + + // Assuming values are unique as well as keys + for (Class specializationType : JoystickDiscoverer.getSpecializationTypes()) + { + String value = JoystickDiscoverer.getSpecialization(specializationType); + if (value.equals(aType)) + { + try + { + JoystickFactory.getInstance().setSpecialization(mJoystickName, specializationType); + wrappedJoystick = specializationType.getDeclaredConstructor(Controller.class).newInstance(mController); + } + catch (Exception e) + { + LOGGER.log(Level.ERROR, e); + } + break; + } + } + + if (wrappedJoystick == null) + { + wrappedJoystick = new NullJoystick(); + } + + mWrappedPanelController.setJoystick(wrappedJoystick); + mXboxPanelController.setJoystick(wrappedJoystick); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/CurrentSettingsPanelController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/CurrentSettingsPanelController.java new file mode 100644 index 00000000..d4e5fdb7 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/CurrentSettingsPanelController.java @@ -0,0 +1,47 @@ +package com.snobot.simulator.gui.joysticks; + +import java.util.Set; + +import com.snobot.simulator.joysticks.IMockJoystick; +import com.snobot.simulator.joysticks.JoystickFactory; +import com.snobot.simulator.joysticks.joystick_specializations.NullJoystick; + +import edu.wpi.first.wpilibj.DriverStation; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; + +public class CurrentSettingsPanelController +{ + @FXML + private GridPane mPane; + + public void setControllerConfig(Set aControllerNames, IMockJoystick[] aSelectedJoysticks) + { + System.out.println("HELLO"); + ObservableList controllerNames = FXCollections.observableArrayList(); + controllerNames.add(NullJoystick.sNAME); + controllerNames.addAll(aControllerNames); + + for (int i = 0; i < DriverStation.kJoystickPorts; ++i) + { + int joystickNum = i; + + ComboBox comboBox = new ComboBox<>(controllerNames); + comboBox.getSelectionModel().select(aSelectedJoysticks[i].getName()); + comboBox.valueProperty().addListener((obsValue, oldValue, newValue) -> + { + JoystickFactory.getInstance().setJoysticks(joystickNum, newValue); + }); + + mPane.add(new Label("Joystick " + i), 0, i); + mPane.add(comboBox, 1, i); + + } + + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/JoystickManagerController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/JoystickManagerController.java new file mode 100644 index 00000000..427b7c31 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/JoystickManagerController.java @@ -0,0 +1,118 @@ +package com.snobot.simulator.gui.joysticks; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.snobot.simulator.joysticks.ControllerConfiguration; +import com.snobot.simulator.joysticks.IMockJoystick; +import com.snobot.simulator.joysticks.JoystickFactory; + +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.layout.Pane; + +public class JoystickManagerController +{ + private static final Logger LOGGER = LogManager.getLogger(JoystickManagerController.class); + private static final int UPDATE_TIME = 20; + + @FXML + private CurrentSettingsPanelController mCurrentSettingsPanelController; + + @FXML + private TabPane mInputConfigTabbedPane; + + private final List mInputControllers; + private boolean mIsOpen; + + public JoystickManagerController() + { + mInputControllers = new ArrayList<>(); + } + + @FXML + public void initialize() + { + + JoystickFactory joystickFactory = JoystickFactory.getInstance(); + Map goodControllers = joystickFactory.getControllerConfiguration(); + + // + + for (Entry pair : goodControllers.entrySet()) + { + String controllerName = pair.getKey(); + ControllerConfiguration config = pair.getValue(); + createAndAddJoystickInput(controllerName, config, joystickFactory.getAll()[0]); + } + + mCurrentSettingsPanelController.setControllerConfig(goodControllers.keySet(), joystickFactory.getAll()); + setVisible(true); + } + + private void createAndAddJoystickInput(String aControllerName, ControllerConfiguration aConfig, IMockJoystick aSelectedJoystick) + { + try + { + FXMLLoader loader = new FXMLLoader( + JoystickManagerController.class.getResource("/com/snobot/simulator/gui/joysticks/connected_input_config_panel.fxml")); + + Pane widgetPane = loader.load(); + ConnectedInputConfigPanelController controller = loader.getController(); + controller.setJoystick(aControllerName, aSelectedJoystick, aConfig); + + Tab tab = new Tab(aControllerName, widgetPane); + mInputConfigTabbedPane.getTabs().add(tab); + mInputControllers.add(controller); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + public void setVisible(boolean aVisible) + { + if (aVisible && !mIsOpen) + { + mIsOpen = true; + Thread t = new Thread(mUpdateLooper); + t.setName("Joystick Updater"); + t.start(); + } + } + + private final Runnable mUpdateLooper = new Runnable() + { + + @Override + public void run() + { + while (mIsOpen) + { + for (ConnectedInputConfigPanelController controller : mInputControllers) + { + controller.update(); + } + + try + { + Thread.sleep(UPDATE_TIME); + } + catch (InterruptedException aEvent) + { + LOGGER.log(Level.ERROR, aEvent); + } + } + } + }; +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/AnalogInputPanelController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/AnalogInputPanelController.java new file mode 100644 index 00000000..229a2839 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/AnalogInputPanelController.java @@ -0,0 +1,25 @@ +package com.snobot.simulator.gui.joysticks.sub_panels; + + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.Slider; + +public class AnalogInputPanelController +{ + @FXML + private Label mLabel; + @FXML + private Slider mSlider; + + + public void setValue(double aValue) + { + mSlider.setValue(aValue); + } + + public void setName(String aText) + { + mLabel.setText(aText); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/BaseJoystickDisplayController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/BaseJoystickDisplayController.java new file mode 100644 index 00000000..3859cf14 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/BaseJoystickDisplayController.java @@ -0,0 +1,66 @@ +package com.snobot.simulator.gui.joysticks.sub_panels; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.snobot.simulator.gui.joysticks.JoystickManagerController; + +import javafx.fxml.FXMLLoader; +import javafx.scene.layout.Pane; + +public class BaseJoystickDisplayController +{ + protected final List mAnalogControllers; + protected final List mDigitalDisplays; + + protected BaseJoystickDisplayController() + { + mAnalogControllers = new ArrayList<>(); + mDigitalDisplays = new ArrayList<>(); + } + + protected Pane createAnalogDisplay(String aName) + { + try + { + FXMLLoader loader = new FXMLLoader( + JoystickManagerController.class.getResource("/com/snobot/simulator/gui/joysticks/sub_panels/analog_input_panel.fxml")); + + Pane widgetPane = loader.load(); + AnalogInputPanelController controller = loader.getController(); + controller.setName(aName); + mAnalogControllers.add(controller); + + return widgetPane; + } + catch (IOException e) + { + e.printStackTrace(); + } + + return null; + } + + protected Pane createDigitalDisplay(String aName) + { + try + { + FXMLLoader loader = new FXMLLoader( + JoystickManagerController.class.getResource("/com/snobot/simulator/gui/joysticks/sub_panels/digital_input_panel.fxml")); + + Pane widgetPane = loader.load(); + DigitalInputPanelController controller = loader.getController(); + controller.setName(aName); + mDigitalDisplays.add(controller); + + return widgetPane; + } + catch (IOException e) + { + e.printStackTrace(); + } + + return null; + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/DigitalInputPanelController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/DigitalInputPanelController.java new file mode 100644 index 00000000..ef2fb402 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/DigitalInputPanelController.java @@ -0,0 +1,20 @@ +package com.snobot.simulator.gui.joysticks.sub_panels; + +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; + +public class DigitalInputPanelController +{ + @FXML + protected CheckBox mCheckbox; + + public void setValue(boolean aValue) + { + mCheckbox.setSelected(aValue); + } + + public void setName(String aText) + { + mCheckbox.setText(aText); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/RawPanelController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/RawPanelController.java new file mode 100644 index 00000000..cc0811b3 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/RawPanelController.java @@ -0,0 +1,94 @@ +package com.snobot.simulator.gui.joysticks.sub_panels; + +import java.util.ArrayList; +import java.util.List; + +import javafx.fxml.FXML; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Pane; +import net.java.games.input.Component; +import net.java.games.input.Controller; + +public class RawPanelController extends BaseJoystickDisplayController +{ + private Controller mJoystick; + + private final List mAnalogComponents; + private final List mDigitalComponents; + + @FXML + private GridPane mAnalogPane; + @FXML + private GridPane mDigitalPane; + + public RawPanelController() + { + mAnalogComponents = new ArrayList<>(); + mDigitalComponents = new ArrayList<>(); + } + + public void updateDisplay() + { + if (mJoystick != null) + { + mJoystick.poll(); + } + + for (int i = 0; i < mAnalogComponents.size(); ++i) + { + float rawValue = mAnalogComponents.get(i).getPollData(); + + AnalogInputPanelController controller = mAnalogControllers.get(i); + controller.setValue((int) (rawValue * 127)); + } + for (int i = 0; i < mDigitalComponents.size(); ++i) + { + float rawValue = mDigitalComponents.get(i).getPollData(); + + DigitalInputPanelController controller = mDigitalDisplays.get(i); + controller.setValue(rawValue == 1); + } + } + + public void setController(Controller aJoystick) + { + mJoystick = aJoystick; + + if (mJoystick != null) + { + mAnalogControllers.clear(); + mDigitalDisplays.clear(); + mAnalogComponents.clear(); + mDigitalComponents.clear(); + + Component[] components = mJoystick.getComponents(); + for (int j = 0; j < components.length; j++) + { + Component component = components[j]; + + if (component.isAnalog()) + { + mAnalogComponents.add(component); + } + else + { + mDigitalComponents.add(component); + } + } + + int modulo = 5; + + for (int i = 0; i < mAnalogComponents.size(); ++i) + { + Pane pane = createAnalogDisplay("Analog " + i); + mAnalogPane.add(pane, i % modulo, i / modulo); + } + for (int i = 0; i < mDigitalComponents.size(); ++i) + { + Pane pane = createDigitalDisplay("Digital " + i); + mDigitalPane.add(pane, i % modulo, i / modulo); + } + } + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/WrappedPanelController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/WrappedPanelController.java new file mode 100644 index 00000000..5d8b5ce7 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/WrappedPanelController.java @@ -0,0 +1,73 @@ +package com.snobot.simulator.gui.joysticks.sub_panels; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.snobot.simulator.joysticks.IMockJoystick; + +import javafx.fxml.FXML; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Pane; + +public class WrappedPanelController extends BaseJoystickDisplayController +{ + private static final Logger LOGGER = LogManager.getLogger(WrappedPanelController.class); + + private IMockJoystick mJoystick; + + @FXML + private GridPane mAnalogPane; + @FXML + private GridPane mDigitalPane; + + public final void setJoystick(IMockJoystick aJoystick) + { + mJoystick = aJoystick; + // mAnalogPanel.removeAll(); + // mDigitalPanel.removeAll(); + + if (mJoystick != null) + { + mAnalogControllers.clear(); + mDigitalDisplays.clear(); + + for (int i = 0; i < mJoystick.getAxisCount(); ++i) + { + Pane pane = createAnalogDisplay("Analog " + i); + mAnalogPane.add(pane, 0, i); + } + for (int i = 0; i < mJoystick.getButtonCount(); ++i) + { + Pane pane = createDigitalDisplay("Digital " + i); + mDigitalPane.add(pane, 0, i); + } + } + } + + public void updateDisplay() + { + if (mJoystick == null) + { + LOGGER.log(Level.WARN, "Joystick is null"); + } + else + { + float[] axisValues = mJoystick.getAxisValues(); + int buttonMask = mJoystick.getButtonMask(); + + for (int i = 0; i < axisValues.length; ++i) + { + AnalogInputPanelController panel = mAnalogControllers.get(i); + panel.setValue(axisValues[i]); + } + for (int i = 0; i < mJoystick.getButtonCount(); ++i) + { + DigitalInputPanelController panel = mDigitalDisplays.get(i); + boolean active = (buttonMask & (1 << i)) != 0; + panel.setValue(active); + } + } + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/XboxDisplayController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/XboxDisplayController.java new file mode 100644 index 00000000..37411c6a --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/joysticks/sub_panels/XboxDisplayController.java @@ -0,0 +1,115 @@ +package com.snobot.simulator.gui.joysticks.sub_panels; + + +import com.snobot.simulator.joysticks.IMockJoystick; +import com.snobot.simulator.joysticks.joystick_specializations.XboxButtonMap; + +import javafx.fxml.FXML; +import javafx.scene.paint.Color; +import javafx.scene.shape.Circle; +import javafx.scene.shape.Line; +import javafx.scene.shape.Rectangle; +import javafx.scene.shape.Shape; + +public class XboxDisplayController +{ + private static final Color BTN_PRESSED_COLOR = new Color(0, 1, 0, .5); + private static final Color BTN_NOT_PRESSED_COLOR = Color.TRANSPARENT; + + @FXML + private Circle mXButton; + @FXML + private Circle mYButton; + @FXML + private Circle mBButton; + @FXML + private Circle mAButton; + @FXML + private Circle mBackButton; + @FXML + private Circle mStartButton; + @FXML + private Circle mXboxButton; + + @FXML + private Rectangle mLeftBumper; + @FXML + private Rectangle mRightBumper; + + @FXML + private Rectangle mL3; + @FXML + private Rectangle mR3; + + @FXML + private Circle mLeftJoystickCircle; + @FXML + private Circle mRightJoystickCircle; + + @FXML + private Line mLeftJoystickLine; + @FXML + private Line mRightJoystickLine; + + private IMockJoystick mJoystick; + + public void setJoystick(IMockJoystick aSelectedJoystick) + { + mJoystick = aSelectedJoystick; + } + + public void updateDisplay() + { + colorButton(mXButton, mJoystick.getRawButton(XboxButtonMap.X_BUTTON - 1)); + colorButton(mYButton, mJoystick.getRawButton(XboxButtonMap.Y_BUTTON - 1)); + colorButton(mBButton, mJoystick.getRawButton(XboxButtonMap.B_BUTTON - 1)); + colorButton(mAButton, mJoystick.getRawButton(XboxButtonMap.A_BUTTON - 1)); + colorButton(mLeftBumper, mJoystick.getRawButton(XboxButtonMap.LB_BUTTON - 1)); + colorButton(mRightBumper, mJoystick.getRawButton(XboxButtonMap.RB_BUTTON - 1)); + + colorButton(mL3, mJoystick.getRawButton(XboxButtonMap.L3_BUTTON - 1)); + colorButton(mR3, mJoystick.getRawButton(XboxButtonMap.R3_BUTTON - 1)); + + colorButton(mBackButton, mJoystick.getRawButton(XboxButtonMap.BACK_BUTTON - 1)); + colorButton(mStartButton, mJoystick.getRawButton(XboxButtonMap.START_BUTTON - 1)); + colorButton(mXboxButton, mJoystick.getRawButton(XboxButtonMap.XBOX_BUTTON)); + + drawJoystick(mLeftJoystickLine, mLeftJoystickCircle, mJoystick.getRawAxis(XboxButtonMap.LEFT_X_AXIS), + mJoystick.getRawAxis(XboxButtonMap.LEFT_Y_AXIS), 162, 270); + + drawJoystick(mRightJoystickLine, mRightJoystickCircle, mJoystick.getRawAxis(XboxButtonMap.RIGHT_X_AXIS), + mJoystick.getRawAxis(XboxButtonMap.RIGHT_Y_AXIS), 468, 372); + // + // drawTrigger(aGraphics, + // mJoystick.getRawAxis(XboxButtonMap.LEFT_TRIGGER), 155, 40); + // drawTrigger(aGraphics, + // mJoystick.getRawAxis(XboxButtonMap.RIGHT_TRIGGER), 530, 40); + // + // drawPOV(aGraphics, mJoystick.getPovValues()); + } + + private void drawJoystick(Line aJoystickVector, Circle aJoystickCircle, double aXAxis, double aYAxis, double aCircleHomeX, double aCircleHomeY) + { + double width = 98 / 2; + double height = 80 / 2; + + aJoystickVector.setEndX(aJoystickVector.getStartX() + aXAxis * width); + aJoystickVector.setEndY(aJoystickVector.getStartY() + aYAxis * height); + + aJoystickCircle.setCenterX(aCircleHomeX + aXAxis * width); + aJoystickCircle.setCenterY(aCircleHomeY + aYAxis * height); + + } + + private void colorButton(Shape aShape, boolean aPressed) + { + if (aPressed) + { + aShape.setFill(BTN_PRESSED_COLOR); + } + else + { + aShape.setFill(BTN_NOT_PRESSED_COLOR); + } + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/motor_graphs/MotorCurveDisplayController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/motor_graphs/MotorCurveDisplayController.java new file mode 100644 index 00000000..8162749c --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/motor_graphs/MotorCurveDisplayController.java @@ -0,0 +1,81 @@ +package com.snobot.simulator.gui.motor_graphs; + +import com.snobot.simulator.motor_sim.DcMotorModelConfig; + +import javafx.fxml.FXML; +import javafx.scene.chart.LineChart; +import javafx.scene.chart.XYChart; + +public class MotorCurveDisplayController +{ + protected static final int POINT_RESOLUTION = 600; + + @FXML + private LineChart mChart; + + private final XYChart.Series mCurrent = new XYChart.Series<>(); + private final XYChart.Series mTorque = new XYChart.Series<>(); + private final XYChart.Series mPower = new XYChart.Series<>(); + private final XYChart.Series mEfficiency = new XYChart.Series<>(); + + public MotorCurveDisplayController() + { + mCurrent.setName("Current"); + mTorque.setName("Torque"); + mPower.setName("Power"); + mEfficiency.setName("Efficiency"); + } + + @FXML + public void initialize() + { + mChart.setAnimated(false); + mChart.getData().addAll(mCurrent, mTorque, mPower, mEfficiency); + } + + public void setCurveParams(DcMotorModelConfig aModel) + { + setCurveParams(aModel.mFactoryParams.mMotorType, aModel.mMotorParams.mNominalVoltage, aModel.mMotorParams.mFreeSpeedRpm, + aModel.mMotorParams.mStallCurrent, aModel.mMotorParams.mFreeCurrent, aModel.mMotorParams.mStallTorque); + } + + public void setCurveParams(String aMotorName, double aNominalVoltage, double aFreeSpeedRpm, double aStallCurrent, double aFreeCurrent, + double aStallTorque) + { + mChart.setTitle(aMotorName); + + mCurrent.getData().clear(); + mTorque.getData().clear(); + mPower.getData().clear(); + mEfficiency.getData().clear(); + + double currentSlope = (aFreeCurrent - aStallCurrent) / aFreeSpeedRpm; + double torqueSlope = (0 - aStallTorque) / aFreeSpeedRpm; + + int dRpm = (int) Math.ceil(aFreeSpeedRpm / POINT_RESOLUTION); + + for (int rpm = 0; rpm < aFreeSpeedRpm; rpm += dRpm) + { + addPoint(aNominalVoltage, aStallCurrent, aStallTorque, rpm, currentSlope, torqueSlope); + } + + // Add the last point always + addPoint(aNominalVoltage, aStallCurrent, aStallTorque, (int) aFreeSpeedRpm, currentSlope, torqueSlope); + } + + private void addPoint(double aNominalVoltage, double aStallCurrent, double aStallTorque, int aRpm, double aCurrentSlope, double aTorqueSlope) + { + final double omega = 2 * aRpm * Math.PI / 60; + final double current = aStallCurrent + aRpm * aCurrentSlope; + final double torque = aStallTorque + aRpm * aTorqueSlope; + final double inputPower = aNominalVoltage * current; + final double outputPower = torque * omega; + final double efficiency = outputPower / inputPower * 100; + + mCurrent.getData().add(new XYChart.Data(aRpm, current)); + mTorque.getData().add(new XYChart.Data(aRpm, torque)); + mPower.getData().add(new XYChart.Data(aRpm, outputPower)); + mEfficiency.getData().add(new XYChart.Data(aRpm, efficiency)); + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AccelerometerWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AccelerometerWidgetController.java new file mode 100644 index 00000000..ad7f9c3c --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AccelerometerWidgetController.java @@ -0,0 +1,97 @@ +package com.snobot.simulator.gui.widgets; + +import java.text.DecimalFormat; + +import com.snobot.simulator.gui.widgets.settings.BasicSettingsDialog; +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.shape.Rectangle; + +public class AccelerometerWidgetController extends BaseWidgetController +{ + private static final double WIDTH = 80; + private static final double GRAVITY_FPS = 32.2; + private static final double GRAVITY_IPS = GRAVITY_FPS * 12; + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###"); + + @FXML + private Label mLabel; + + @FXML + private Rectangle mAccelerationBar; + + @FXML + private TextField mAccelerationText; + + private int mId; + + private final double mMaxAcceleration; + + public AccelerometerWidgetController() + { + mMaxAcceleration = 2 * GRAVITY_IPS; + } + + @Override + public void initialize(int aId) + { + mId = aId; + mLabel.setText(getName()); + } + + @Override + public void update() + { + set(DataAccessorFactory.getInstance().getAccelerometerAccessor().getAcceleration(mId)); + } + + private void set(double aAcceleration) + { + mAccelerationText.setText(DECIMAL_FORMAT.format(aAcceleration)); + + double acceleration = Math.min(mMaxAcceleration, aAcceleration); + acceleration = Math.max(-mMaxAcceleration, acceleration); + + double width = acceleration * WIDTH / 2 / mMaxAcceleration; + double x; + if (acceleration < 0) + { + x = WIDTH / 2 + width; + } + else + { + x = WIDTH / 2; + } + + mAccelerationBar.setWidth(Math.abs(width)); + mAccelerationBar.setX(x); + } + + @Override + public void openSettings() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/basic_settings.fxml"); + dialog.getController().setName(getName()); + if (dialog.showAndWait()) + { + setName(dialog.getController().getDisplayName()); + saveSettings(); + } + } + + private String getName() + { + return DataAccessorFactory.getInstance().getAccelerometerAccessor().getName(mId); + } + + private void setName(String aName) + { + DataAccessorFactory.getInstance().getAccelerometerAccessor().setName(mId, aName); + mLabel.setText(aName); + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AdvancedSettingsController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AdvancedSettingsController.java new file mode 100644 index 00000000..2fda29de --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AdvancedSettingsController.java @@ -0,0 +1,42 @@ +package com.snobot.simulator.gui.widgets; + +import java.util.function.Supplier; + +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.gui.widgets.settings.advanced.SpiI2cSettingsController; +import com.snobot.simulator.gui.widgets.settings.advanced.TankDriveSettingsController; + +import javafx.fxml.FXML; + +public class AdvancedSettingsController +{ + private Supplier mSaveFunction; + + @FXML + protected void handleSpiI2cButton() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/advanced/spi_i2c_settings.fxml"); + if (dialog.showAndWait()) + { + dialog.getController().onSubmit(); + mSaveFunction.get(); + } + } + + @FXML + protected void handleTankDriveButton() + { + DialogRunner dialog = new DialogRunner<>( + "/com/snobot/simulator/gui/widgets/settings/advanced/tank_drive_settings.fxml"); + if (dialog.showAndWait()) + { + dialog.getController().onSubmit(); + mSaveFunction.get(); + } + } + + public void setSaveCallback(Supplier aSaveFunction) + { + mSaveFunction = aSaveFunction; + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AnalogInWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AnalogInWidgetController.java new file mode 100644 index 00000000..60c660d7 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AnalogInWidgetController.java @@ -0,0 +1,101 @@ +package com.snobot.simulator.gui.widgets; + +import com.snobot.simulator.gui.Util; +import com.snobot.simulator.gui.widgets.settings.BasicSettingsDialog; +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.shape.Circle; + +public class AnalogInWidgetController extends BaseWidgetController +{ + @FXML + private Label mLabel; + + @FXML + private Circle mValueIcon; + + @FXML + private TextField mValueField; + + private int mId; + + private boolean mEditing; + + @Override + public void initialize(int aId) + { + mId = aId; + mLabel.setText(getName()); + + mValueField.focusedProperty().addListener((obs, oldVal, newVal) -> + { + System.out.println("Focus listener" + newVal); + if (newVal) + { + mEditing = true; + } + else + { + handleUserSetting(); + } + }); + } + + @Override + public void update() + { + if (!mEditing) + { + double voltage = DataAccessorFactory.getInstance().getAnalogInAccessor().getVoltage(mId); + + mValueIcon.setFill(Util.colorGetShadedColor(voltage, 5, 0)); + mValueField.setText(Double.toString(voltage)); + } + } + + @Override + public void openSettings() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/basic_settings.fxml"); + dialog.getController().setName(getName()); + if (dialog.showAndWait()) + { + setName(dialog.getController().getDisplayName()); + saveSettings(); + } + } + + private String getName() + { + return DataAccessorFactory.getInstance().getAnalogInAccessor().getName(mId); + } + + private void setName(String aName) + { + DataAccessorFactory.getInstance().getAnalogInAccessor().setName(mId, aName); + mLabel.setText(aName); + } + + @FXML + public void handleAction() + { + handleUserSetting(); + } + + private void handleUserSetting() + { + mEditing = false; + double newVoltage = Double.parseDouble(mValueField.getText()); + newVoltage = Math.min(5, newVoltage); + newVoltage = Math.max(0, newVoltage); + + DataAccessorFactory.getInstance().getAnalogInAccessor().setVoltage(mId, newVoltage); + + mLabel.requestFocus(); + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AnalogOutWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AnalogOutWidgetController.java new file mode 100644 index 00000000..2b9f327e --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/AnalogOutWidgetController.java @@ -0,0 +1,69 @@ +package com.snobot.simulator.gui.widgets; + +import java.text.DecimalFormat; + +import com.snobot.simulator.gui.Util; +import com.snobot.simulator.gui.widgets.settings.BasicSettingsDialog; +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.shape.Circle; + +public class AnalogOutWidgetController extends BaseWidgetController +{ + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###"); + + @FXML + private Label mLabel; + + @FXML + private Circle mValueIcon; + + @FXML + private TextField mValueField; + + private int mId; + + @Override + public void initialize(int aId) + { + mId = aId; + mLabel.setText(getName()); + mValueField.setEditable(false); + } + + @Override + public void update() + { + double voltage = DataAccessorFactory.getInstance().getAnalogOutAccessor().getVoltage(mId); + mValueIcon.setFill(Util.colorGetShadedColor(voltage, 5, 0)); + mValueField.setText(DECIMAL_FORMAT.format(voltage)); + + } + + @Override + public void openSettings() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/basic_settings.fxml"); + dialog.getController().setName(getName()); + if (dialog.showAndWait()) + { + setName(dialog.getController().getDisplayName()); + saveSettings(); + } + } + + private String getName() + { + return DataAccessorFactory.getInstance().getAnalogOutAccessor().getName(mId); + } + + private void setName(String aName) + { + DataAccessorFactory.getInstance().getAnalogOutAccessor().setName(mId, aName); + mLabel.setText(aName); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/BaseWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/BaseWidgetController.java new file mode 100644 index 00000000..b882795e --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/BaseWidgetController.java @@ -0,0 +1,21 @@ +package com.snobot.simulator.gui.widgets; + +import java.util.function.Supplier; + +public abstract class BaseWidgetController implements IWidgetController +{ + private Supplier mSaveSettingsFunction; + + @Override + public boolean saveSettings() + { + return mSaveSettingsFunction.get(); + } + + @Override + public void setSaveAction(Supplier aSaveFunction) + { + mSaveSettingsFunction = aSaveFunction; + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/DigitalIOWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/DigitalIOWidgetController.java new file mode 100644 index 00000000..54134b48 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/DigitalIOWidgetController.java @@ -0,0 +1,59 @@ +package com.snobot.simulator.gui.widgets; + + +import com.snobot.simulator.gui.widgets.settings.BasicSettingsDialog; +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.paint.Color; +import javafx.scene.shape.Circle; + +public class DigitalIOWidgetController extends BaseWidgetController +{ + @FXML + private Label mLabel; + + @FXML + private Circle mValueIcon; + + private int mId; + + @Override + public void initialize(int aId) + { + mId = aId; + mLabel.setText(getName()); + } + + @Override + public void update() + { + boolean value = DataAccessorFactory.getInstance().getDigitalAccessor().getState(mId); + mValueIcon.setFill(value ? Color.GREEN : Color.RED); + } + + @Override + public void openSettings() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/basic_settings.fxml"); + dialog.getController().setName(getName()); + if (dialog.showAndWait()) + { + setName(dialog.getController().getDisplayName()); + saveSettings(); + } + } + + private String getName() + { + return DataAccessorFactory.getInstance().getDigitalAccessor().getName(mId); + } + + private void setName(String aName) + { + DataAccessorFactory.getInstance().getDigitalAccessor().setName(mId, aName); + mLabel.setText(aName); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/EncoderWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/EncoderWidgetController.java new file mode 100644 index 00000000..1bec59a4 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/EncoderWidgetController.java @@ -0,0 +1,70 @@ +package com.snobot.simulator.gui.widgets; + +import java.text.DecimalFormat; + +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.gui.widgets.settings.EncoderSettingsDialog; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; + +public class EncoderWidgetController extends BaseWidgetController +{ + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###"); + + @FXML + private Label mLabel; + + @FXML + private TextField mDistanceField; + + private int mId; + + @Override + public void initialize(int aId) + { + mId = aId; + mLabel.setText(getName()); + } + + @Override + public void update() + { + boolean isConnected = DataAccessorFactory.getInstance().getEncoderAccessor().isHookedUp(mId); + if (isConnected) + { + mDistanceField.setText(DECIMAL_FORMAT.format(DataAccessorFactory.getInstance().getEncoderAccessor().getDistance(mId))); + } + else + { + mDistanceField.setText("No SC Connected"); + } + } + + @Override + public void openSettings() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/encoder_settings.fxml"); + dialog.getController().setName(getName()); + dialog.getController().setEncoderHandle(mId); + if (dialog.showAndWait()) + { + setName(dialog.getController().getDisplayName()); + DataAccessorFactory.getInstance().getEncoderAccessor().connectSpeedController(mId, dialog.getController().getSelectedId()); + saveSettings(); + } + } + + private String getName() + { + return DataAccessorFactory.getInstance().getEncoderAccessor().getName(mId); + } + + private void setName(String aName) + { + DataAccessorFactory.getInstance().getEncoderAccessor().setName(mId, aName); + mLabel.setText(aName); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/GyroWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/GyroWidgetController.java new file mode 100644 index 00000000..3bde8bed --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/GyroWidgetController.java @@ -0,0 +1,78 @@ +package com.snobot.simulator.gui.widgets; + +import java.text.DecimalFormat; + +import com.snobot.simulator.gui.widgets.settings.BasicSettingsDialog; +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.shape.Circle; +import javafx.scene.shape.Line; +import javafx.scene.transform.Rotate; + +public class GyroWidgetController extends BaseWidgetController +{ + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###"); + + @FXML + private Label mLabel; + + @FXML + private Circle mAngleIndicator; + + @FXML + private Line mAngleArm; + + @FXML + private TextField mAngleText; + + private Rotate mAngleArmRotation; + + private int mId; + + @Override + public void initialize(int aId) + { + mId = aId; + mLabel.setText(getName()); + + mAngleArmRotation = new Rotate(); + mAngleArm.getTransforms().add(mAngleArmRotation); + } + + @Override + public void update() + { + double angle = DataAccessorFactory.getInstance().getGyroAccessor().getAngle(mId); + mAngleText.setText(DECIMAL_FORMAT.format(angle)); + + mAngleArmRotation.setAngle(angle); + + } + + @Override + public void openSettings() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/basic_settings.fxml"); + dialog.getController().setName(getName()); + if (dialog.showAndWait()) + { + setName(dialog.getController().getDisplayName()); + saveSettings(); + } + } + + private String getName() + { + return DataAccessorFactory.getInstance().getGyroAccessor().getName(mId); + } + + private void setName(String aName) + { + DataAccessorFactory.getInstance().getGyroAccessor().setName(mId, aName); + mLabel.setText(aName); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/IWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/IWidgetController.java new file mode 100644 index 00000000..fb11ea2e --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/IWidgetController.java @@ -0,0 +1,18 @@ +package com.snobot.simulator.gui.widgets; + +import java.util.function.Supplier; + +public interface IWidgetController +{ + + void initialize(int aId); + + void update(); + + void openSettings(); + + boolean saveSettings(); + + void setSaveAction(Supplier aSaveFunction); + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/RelayWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/RelayWidgetController.java new file mode 100644 index 00000000..ba1a3391 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/RelayWidgetController.java @@ -0,0 +1,64 @@ +package com.snobot.simulator.gui.widgets; + +import com.snobot.simulator.gui.widgets.settings.BasicSettingsDialog; +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.paint.Color; +import javafx.scene.shape.Rectangle; + +public class RelayWidgetController extends BaseWidgetController +{ + @FXML + private Label mLabel; + + @FXML + private Rectangle mForwardIndicator; + + @FXML + private Rectangle mReverseIndicator; + + private int mId; + + @Override + public void initialize(int aId) + { + mId = aId; + mLabel.setText(getName()); + } + + @Override + public void update() + { + boolean forward = DataAccessorFactory.getInstance().getRelayAccessor().getFowardValue(mId); + boolean reverse = DataAccessorFactory.getInstance().getRelayAccessor().getReverseValue(mId); + + mForwardIndicator.setFill(forward ? Color.GREEN : Color.RED); + mReverseIndicator.setFill(reverse ? Color.GREEN : Color.RED); + } + + @Override + public void openSettings() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/basic_settings.fxml"); + dialog.getController().setName(getName()); + if (dialog.showAndWait()) + { + setName(dialog.getController().getDisplayName()); + saveSettings(); + } + } + + private String getName() + { + return DataAccessorFactory.getInstance().getRelayAccessor().getName(mId); + } + + private void setName(String aName) + { + DataAccessorFactory.getInstance().getRelayAccessor().setName(mId, aName); + mLabel.setText(aName); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/SolenoidWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/SolenoidWidgetController.java new file mode 100644 index 00000000..b79ed8ef --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/SolenoidWidgetController.java @@ -0,0 +1,75 @@ +package com.snobot.simulator.gui.widgets; + +import com.snobot.simulator.gui.widgets.settings.BasicSettingsDialog; +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.shape.Rectangle; + +public class SolenoidWidgetController extends BaseWidgetController +{ + @FXML + private Label mLabel; + + @FXML + private Rectangle mPole; + + @FXML + private Rectangle mPlunger; + + private int mId; + + @Override + public void initialize(int aId) + { + mId = aId; + mLabel.setText(getName()); + } + + @Override + public void update() + { + boolean state = DataAccessorFactory.getInstance().getSolenoidAccessor().get(mId); + set(state); + } + + @Override + public void openSettings() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/basic_settings.fxml"); + dialog.getController().setName(getName()); + if (dialog.showAndWait()) + { + setName(dialog.getController().getDisplayName()); + saveSettings(); + } + } + + private String getName() + { + return DataAccessorFactory.getInstance().getSolenoidAccessor().getName(mId); + } + + private void setName(String aName) + { + DataAccessorFactory.getInstance().getSolenoidAccessor().setName(mId, aName); + mLabel.setText(aName); + } + + private void set(boolean aState) + { + if (aState) + { + mPole.setX(30); + mPlunger.setX(80); + } + else + { + mPole.setX(0); + mPlunger.setX(50); + } + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/SpeedControllerWidgetController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/SpeedControllerWidgetController.java new file mode 100644 index 00000000..c3b4f0b1 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/SpeedControllerWidgetController.java @@ -0,0 +1,73 @@ +package com.snobot.simulator.gui.widgets; + +import java.text.DecimalFormat; + +import com.snobot.simulator.gui.Util; +import com.snobot.simulator.gui.widgets.settings.DialogRunner; +import com.snobot.simulator.gui.widgets.settings.SpeedControllerSettingsDialog; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; +import com.snobot.simulator.wrapper_accessors.SpeedControllerWrapperAccessor.MotorSimType; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.shape.Circle; + +public class SpeedControllerWidgetController extends BaseWidgetController +{ + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###"); + + @FXML + private Label mLabel; + + @FXML + private Circle mMotorSpeedIndicator; + + @FXML + private TextField mValueField; + + private int mId; + + @Override + public void initialize(int aId) + { + mId = aId; + mLabel.setText(getName()); + } + + @Override + public void update() + { + double speed = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getVoltagePercentage(mId); + mMotorSpeedIndicator.setFill(Util.getMotorColor(speed)); + mValueField.setText(DECIMAL_FORMAT.format(speed)); + } + + @Override + public void openSettings() + { + DialogRunner dialog = new DialogRunner<>("/com/snobot/simulator/gui/widgets/settings/speed_controller_settings.fxml"); + dialog.getController().setName(getName()); + + MotorSimType mode = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getMotorSimType(mId); + dialog.getController().initialize(mId, mode); + + if (dialog.showAndWait()) + { + setName(dialog.getController().getDisplayName()); + dialog.getController().saveMotorSim(mId); + saveSettings(); + } + } + + private String getName() + { + return DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(mId); + } + + private void setName(String aName) + { + DataAccessorFactory.getInstance().getSpeedControllerAccessor().setName(mId, aName); + mLabel.setText(aName); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/BasicSettingsDialog.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/BasicSettingsDialog.java new file mode 100644 index 00000000..f2c86bd4 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/BasicSettingsDialog.java @@ -0,0 +1,24 @@ +package com.snobot.simulator.gui.widgets.settings; + +import javafx.fxml.FXML; +import javafx.scene.control.TextField; + +public class BasicSettingsDialog +{ + @FXML + private TextField mNameField; + + public BasicSettingsDialog() + { + } + + public void setName(String aName) + { + mNameField.setText(aName); + } + + public String getDisplayName() + { + return mNameField.getText(); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/DialogRunner.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/DialogRunner.java new file mode 100644 index 00000000..786d318c --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/DialogRunner.java @@ -0,0 +1,57 @@ +package com.snobot.simulator.gui.widgets.settings; + +import java.io.IOException; + +import javafx.fxml.FXMLLoader; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.ButtonType; +import javafx.scene.layout.Pane; + +public class DialogRunner +{ + private boolean mOkSelected; + private DialogController mDialogController; + private Alert mAlert; + + public DialogRunner(String aFxmlPath) + { + try + { + mAlert = new Alert(AlertType.NONE); + mAlert.setTitle("Error alert"); + + mAlert.getDialogPane().getButtonTypes().add(ButtonType.OK); + mAlert.getDialogPane().getButtonTypes().add(ButtonType.CANCEL); + + FXMLLoader loader = new FXMLLoader(DialogRunner.class.getResource(aFxmlPath)); + Pane widgetPane = loader.load(); + mDialogController = loader.getController(); + + mAlert.getDialogPane().setContent(widgetPane); + } + catch (IOException ex) + { + throw new RuntimeException("Could not load dialog", ex); + } + } + + public boolean showAndWait() + { + mAlert.showAndWait().ifPresent(response -> + { + if (response == ButtonType.OK) + { + mOkSelected = true; + } + }); + + return mOkSelected; + } + + public DialogController getController() + { + return mDialogController; + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/EncoderSettingsDialog.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/EncoderSettingsDialog.java new file mode 100644 index 00000000..b3928fea --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/EncoderSettingsDialog.java @@ -0,0 +1,55 @@ +package com.snobot.simulator.gui.widgets.settings; + +import java.util.List; + +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; + +public class EncoderSettingsDialog extends BasicSettingsDialog +{ + @FXML + private ComboBox mSpeedControllerComboBox; + + @FXML + public void initialize() + { + List speedControllers = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getPortList(); + for (int handle : speedControllers) + { + SensorHandleOption option = new SensorHandleOption(handle, + DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(handle)); + mSpeedControllerComboBox.getItems().add(option); + } + } + + public void setEncoderHandle(int aEncoderHandle) + { + int connectedSc = -1; + if (DataAccessorFactory.getInstance().getEncoderAccessor().isHookedUp(aEncoderHandle)) + { + connectedSc = DataAccessorFactory.getInstance().getEncoderAccessor().getHookedUpId(aEncoderHandle); + } + + for (int i = 0; i < mSpeedControllerComboBox.getItems().size(); ++i) + { + SensorHandleOption option = mSpeedControllerComboBox.getItems().get(i); + + if (option.mHandle == connectedSc) + { + mSpeedControllerComboBox.getSelectionModel().select(i); + } + if (option.mHandle != -1) + { + option.mName = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(option.mHandle); + } + } + } + + public int getSelectedId() + { + SensorHandleOption option = (SensorHandleOption) mSpeedControllerComboBox.getSelectionModel().getSelectedItem(); + return option == null ? -1 : option.mHandle; + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/SensorHandleOption.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/SensorHandleOption.java new file mode 100644 index 00000000..f9858453 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/SensorHandleOption.java @@ -0,0 +1,19 @@ +package com.snobot.simulator.gui.widgets.settings; + +public class SensorHandleOption +{ + public int mHandle; + public String mName; + + public SensorHandleOption(int aHandle, String aName) + { + mHandle = aHandle; + mName = aName; + } + + @Override + public String toString() + { + return mName + "(" + mHandle + ")"; + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/SpeedControllerSettingsDialog.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/SpeedControllerSettingsDialog.java new file mode 100644 index 00000000..7da425b1 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/SpeedControllerSettingsDialog.java @@ -0,0 +1,100 @@ +package com.snobot.simulator.gui.widgets.settings; + +import com.snobot.simulator.gui.widgets.settings.motor_sim.GravitationalLoadMotorSimController; +import com.snobot.simulator.gui.widgets.settings.motor_sim.IMotorSimController; +import com.snobot.simulator.gui.widgets.settings.motor_sim.RotationalLoadMotorSimController; +import com.snobot.simulator.gui.widgets.settings.motor_sim.SimpleMotorSimController; +import com.snobot.simulator.gui.widgets.settings.motor_sim.StaticLoadMotorSimController; +import com.snobot.simulator.wrapper_accessors.SpeedControllerWrapperAccessor.MotorSimType; + +import javafx.fxml.FXML; +import javafx.scene.Node; +import javafx.scene.control.ComboBox; +import javafx.scene.layout.StackPane; + +public class SpeedControllerSettingsDialog extends BasicSettingsDialog +{ + @FXML + private ComboBox mSelectionBox; + + @FXML + private StackPane mLayoutManager; + + @FXML + private Node mSimpleConfigPanel; + + @FXML + private SimpleMotorSimController mSimpleConfigPanelController; + + @FXML + private Node mStaticLoadConfigPanel; + + @FXML + private StaticLoadMotorSimController mStaticLoadConfigPanelController; + + @FXML + private Node mRotationalLoadConfigPanel; + + @FXML + private RotationalLoadMotorSimController mRotationalLoadConfigPanelController; + + @FXML + private Node mGravitationalLoadConfigPanel; + + @FXML + private GravitationalLoadMotorSimController mGravitationalLoadConfigPanelController; + + private IMotorSimController mActiveController; + + @FXML + public void initialize() + { + mSelectionBox.getItems().addAll(MotorSimType.values()); + } + + public void initialize(int aSpeedControllerHandle, MotorSimType aMode) + { + mSelectionBox.getSelectionModel().select(aMode); + handleSimType(aMode); + mActiveController.populate(aSpeedControllerHandle); + } + + @FXML + public void handleSimType() + { + MotorSimType selectedType = mSelectionBox.getSelectionModel().getSelectedItem(); + handleSimType(selectedType); + } + + public void handleSimType(MotorSimType aSelectedType) + { + mLayoutManager.getChildren().clear(); + + switch (aSelectedType) + { + case Simple: + mLayoutManager.getChildren().add(mSimpleConfigPanel); + mActiveController = mSimpleConfigPanelController; + break; + case StaticLoad: + mLayoutManager.getChildren().add(mStaticLoadConfigPanel); + mActiveController = mStaticLoadConfigPanelController; + break; + case RotationalLoad: + mLayoutManager.getChildren().add(mRotationalLoadConfigPanel); + mActiveController = mRotationalLoadConfigPanelController; + break; + case GravitationalLoad: + mLayoutManager.getChildren().add(mGravitationalLoadConfigPanel); + mActiveController = mGravitationalLoadConfigPanelController; + break; + default: + throw new IllegalArgumentException("Unknown type " + aSelectedType); + } + } + + public void saveMotorSim(int aSpeedControllerHandle) + { + mActiveController.saveSettings(aSpeedControllerHandle); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/advanced/SpiI2cSettingsController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/advanced/SpiI2cSettingsController.java new file mode 100644 index 00000000..4d669c49 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/advanced/SpiI2cSettingsController.java @@ -0,0 +1,128 @@ +package com.snobot.simulator.gui.widgets.settings.advanced; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import edu.wpi.first.wpilibj.I2C; +import edu.wpi.first.wpilibj.SPI; +import javafx.collections.FXCollections; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; + +public class SpiI2cSettingsController +{ + private static final String DEFAULT_ITEM = "None"; + + private final Map mSpiSettings; + private final Map mI2CSettings; + + @FXML + private GridPane mSpiPane; + + @FXML + private GridPane mI2CPane; + + public SpiI2cSettingsController() + { + mSpiSettings = new HashMap<>(); + mI2CSettings = new HashMap<>(); + } + + @FXML + public void initialize() + { + Map defaultSpiMapping = DataAccessorFactory.getInstance().getSpiAccessor().getSpiWrapperTypes(); + Map defaultI2CMapping = DataAccessorFactory.getInstance().getI2CAccessor().getI2CWrapperTypes(); + Collection availableSpiOptions = new ArrayList<>(); + Collection availableI2COptions = new ArrayList<>(); + + availableSpiOptions.add(DEFAULT_ITEM); + availableSpiOptions.addAll(DataAccessorFactory.getInstance().getSpiAccessor().getAvailableSpiSimulators()); + + availableI2COptions.add(DEFAULT_ITEM); + availableI2COptions.addAll(DataAccessorFactory.getInstance().getI2CAccessor().getAvailableI2CSimulators()); + + int rowCtr = 0; + for (SPI.Port port : SPI.Port.values()) + { + String selectedValue = defaultSpiMapping.get(port.value); + + ComponentRow row = new ComponentRow(port.name(), "(" + port.ordinal() + ")", availableSpiOptions, selectedValue); + mSpiSettings.put(port.value, row); + + mSpiPane.add(row.mNameLabel, 0, rowCtr); + mSpiPane.add(row.mIndexLabel, 1, rowCtr); + mSpiPane.add(row.mSimType, 2, rowCtr); + ++rowCtr; + } + + rowCtr = 0; + for (I2C.Port port : I2C.Port.values()) + { + String selectedValue = defaultI2CMapping.get(port.value); + + ComponentRow row = new ComponentRow(port.name(), "(" + port.ordinal() + ")", availableSpiOptions, selectedValue); + mI2CSettings.put(port.value, row); + + mI2CPane.add(row.mNameLabel, 0, rowCtr); + mI2CPane.add(row.mIndexLabel, 1, rowCtr); + mI2CPane.add(row.mSimType, 2, rowCtr); + ++rowCtr; + } + + } + + public void onSubmit() + { + for (Entry pair : mSpiSettings.entrySet()) + { + Object selected = pair.getValue().mSimType.getSelectionModel().getSelectedItem(); + String value = null; + if (selected != null && !DEFAULT_ITEM.equals(selected)) + { + value = selected.toString(); + } + DataAccessorFactory.getInstance().getSpiAccessor().createSpiSimulator(pair.getKey(), value); + } + + for (Entry pair : mI2CSettings.entrySet()) + { + Object selected = pair.getValue().mSimType.getSelectionModel().getSelectedItem(); + String value = null; + if (selected != null && !DEFAULT_ITEM.equals(selected)) + { + value = selected.toString(); + } + DataAccessorFactory.getInstance().getI2CAccessor().createI2CSimulator(pair.getKey(), value); + } + + Alert closeAlert = new Alert(AlertType.WARNING, + "Most SPI and I2C simulators are required to be initialized on startup, so it is recommended that you save your updates and restart the simulator"); + closeAlert.showAndWait(); + } + + private static class ComponentRow + { + private final Label mNameLabel; + private final Label mIndexLabel; + private final ComboBox mSimType; + + private ComponentRow(String aName, String aIndex, Collection aOptions, String aSelectedValue) + { + mNameLabel = new Label(aName); + mIndexLabel = new Label(aIndex); + mSimType = new ComboBox<>(FXCollections.observableArrayList(aOptions)); + mSimType.getSelectionModel().select(aSelectedValue); + } + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/advanced/TankDriveSettingsController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/advanced/TankDriveSettingsController.java new file mode 100644 index 00000000..d1e15444 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/advanced/TankDriveSettingsController.java @@ -0,0 +1,197 @@ +package com.snobot.simulator.gui.widgets.settings.advanced; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.snobot.simulator.gui.widgets.settings.SensorHandleOption; +import com.snobot.simulator.simulator_components.config.TankDriveConfig; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.collections.FXCollections; +import javafx.fxml.FXML; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.control.TitledPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.VBox; + +public class TankDriveSettingsController +{ + private static final Logger LOGGER = LogManager.getLogger(TankDriveSettingsController.class); + + private final List mWidgetPanels; + + @FXML + private GridPane mSpiPane; + + @FXML + private VBox mPane; + + public TankDriveSettingsController() + { + mWidgetPanels = new ArrayList<>(); + } + + @FXML + public void initialize() + { + Collection simulatorComponents = DataAccessorFactory.getInstance().getSimulatorDataAccessor().getSimulatorComponentConfigs(); + for (Object comp : simulatorComponents) + { + if (comp instanceof TankDriveConfig) + { + addPanel((TankDriveConfig) comp); + } + } + + } + + @FXML + public void handleAddButton() + { + addPanel(new TankDriveConfig()); + } + + private void addPanel(TankDriveConfig aConfig) + { + SingleSettingWidget panel = new SingleSettingWidget(aConfig); + mWidgetPanels.add(panel); + + TitledPane titledPane = new TitledPane("Tank Drive Config", panel); + mPane.getChildren().add(titledPane); + } + + public void onSubmit() + { + Collection toRemove = new ArrayList<>(); + Collection simulatorComponents = DataAccessorFactory.getInstance().getSimulatorDataAccessor().getSimulatorComponentConfigs(); + + for (Object comp : simulatorComponents) + { + if (comp instanceof TankDriveConfig) + { + toRemove.add(comp); + } + } + + for (Object comp : toRemove) + { + DataAccessorFactory.getInstance().getSimulatorDataAccessor().removeSimulatorComponent(comp); + } + + for (SingleSettingWidget panel : mWidgetPanels) + { + TankDriveConfig config = panel.getConfig(); + if (config == null) + { + throw new IllegalArgumentException("Could not create tank drive simulator"); + } + DataAccessorFactory.getInstance().getSimulatorDataAccessor().connectTankDriveSimulator(config.getmLeftMotorHandle(), + config.getmRightMotorHandle(), config.getmGyroHandle(), config.getmTurnKp()); + } + } + + private static class SingleSettingWidget extends GridPane + { + private final ComboBox mLeftMotorSelection; + private final ComboBox mRightMotorSelection; + private final ComboBox mGyroSelection; + private final TextField mKpField; + + private SingleSettingWidget(TankDriveConfig aConfig) + { + SensorHandleOption leftSelection = null; + SensorHandleOption rightSelection = null; + SensorHandleOption gyroSelection = null; + + List speedControllerOptions = new ArrayList<>(); + List speedControllers = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getPortList(); + for (int handle : speedControllers) + { + SensorHandleOption option = new SensorHandleOption(handle, + DataAccessorFactory.getInstance().getSpeedControllerAccessor().getName(handle)); + speedControllerOptions.add(option); + + if (option.mHandle == aConfig.getmLeftMotorHandle()) + { + leftSelection = option; + } + + if (option.mHandle == aConfig.getmRightMotorHandle()) + { + rightSelection = option; + } + } + + List gyroOptions = new ArrayList<>(); + List gyros = DataAccessorFactory.getInstance().getGyroAccessor().getPortList(); + for (int handle : gyros) + { + SensorHandleOption option = new SensorHandleOption(handle, DataAccessorFactory.getInstance().getGyroAccessor().getName(handle)); + gyroOptions.add(option); + + if (option.mHandle == aConfig.getmGyroHandle()) + { + gyroSelection = option; + } + } + + mLeftMotorSelection = new ComboBox<>(FXCollections.observableList(speedControllerOptions)); + mRightMotorSelection = new ComboBox<>(FXCollections.observableList(speedControllerOptions)); + mGyroSelection = new ComboBox<>(FXCollections.observableList(gyroOptions)); + + mLeftMotorSelection.getSelectionModel().select(leftSelection == null ? speedControllerOptions.get(0) : leftSelection); + mRightMotorSelection.getSelectionModel().select(rightSelection == null ? speedControllerOptions.get(0) : rightSelection); + mGyroSelection.getSelectionModel().select(gyroSelection == null ? gyroOptions.get(0) : gyroSelection); + + mKpField = new TextField(Double.toString(aConfig.getmTurnKp())); + + add(new Label("Left Motor"), 0, 0); + add(mLeftMotorSelection, 1, 0); + + add(new Label("Right Motor"), 0, 1); + add(mRightMotorSelection, 1, 1); + + add(new Label("Gyroscope"), 0, 2); + add(mGyroSelection, 1, 2); + + add(new Label("Turning kP"), 0, 3); + add(mKpField, 1, 3); + } + + public TankDriveConfig getConfig() + { + SensorHandleOption left = mLeftMotorSelection.getSelectionModel().getSelectedItem(); + SensorHandleOption right = mRightMotorSelection.getSelectionModel().getSelectedItem(); + SensorHandleOption gyro = mGyroSelection.getSelectionModel().getSelectedItem(); + + if (left == null || right == null || gyro == null) + { + return null; + } + + int leftHandle = left.mHandle; + int rightHanle = right.mHandle; + int gyroHandle = gyro.mHandle; + double kp = 1; + + try + { + kp = Double.parseDouble(mKpField.getText()); + } + catch (NumberFormatException e) + { + LOGGER.log(Level.ERROR, e); + } + + return new TankDriveConfig(leftHandle, rightHanle, gyroHandle, kp); + } + } + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/BaseMotorSimWithDcMotorModelController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/BaseMotorSimWithDcMotorModelController.java new file mode 100644 index 00000000..95b461dd --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/BaseMotorSimWithDcMotorModelController.java @@ -0,0 +1,10 @@ +package com.snobot.simulator.gui.widgets.settings.motor_sim; + +import javafx.fxml.FXML; + +public abstract class BaseMotorSimWithDcMotorModelController implements IMotorSimController // NOPMD.AbstractClassWithoutAnyMethod +{ + @FXML + protected DcMotorModelParamsController mMotorPanelController; + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/DcMotorModelParamsController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/DcMotorModelParamsController.java new file mode 100644 index 00000000..d3af4818 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/DcMotorModelParamsController.java @@ -0,0 +1,116 @@ +package com.snobot.simulator.gui.widgets.settings.motor_sim; + +import java.text.DecimalFormat; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.snobot.simulator.gui.motor_graphs.MotorCurveDisplayController; +import com.snobot.simulator.motor_sim.DcMotorModelConfig; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Spinner; +import javafx.scene.control.TextField; + +public class DcMotorModelParamsController +{ + private static final Logger sLOGGER = LogManager.getLogger(DcMotorModelParamsController.class); + + @FXML + private ComboBox mMotorType; + + @FXML + private Spinner mNumMotors; + + @FXML + private TextField mGearRatio; + + @FXML + private TextField mEfficiency; + + @FXML + private CheckBox mInverted; + + @FXML + private CheckBox mBrake; + + @FXML + private TextField mNominalVoltage; + + @FXML + private TextField mFreeSpeedRpm; + + @FXML + private TextField mNominalCurrent; + + @FXML + private TextField mStallTorque; + + @FXML + private TextField mStallCurrent; + + @FXML + private MotorCurveDisplayController mMotorChartController; + + private final DecimalFormat mDecimalFormat; + + public DcMotorModelParamsController() + { + mDecimalFormat = new DecimalFormat("0.000"); + } + + @FXML + protected void handleMotorType() + { + updateMotorConfig(); + } + + public DcMotorModelConfig getMotorConfig() + { + DcMotorModelConfig output = null; + + try + { + String selectedMotor = mMotorType.getSelectionModel().getSelectedItem(); + int numMotors = (Integer) (mNumMotors.getValue()); + double gearReduction = Double.parseDouble(mGearRatio.getText()); + double efficiency = Double.parseDouble(mEfficiency.getText()); + + output = DataAccessorFactory.getInstance().getSimulatorDataAccessor().createMotor(selectedMotor, numMotors, gearReduction, efficiency, + mInverted.isSelected(), mBrake.isSelected()); + } + catch (NumberFormatException e) + { + sLOGGER.log(Level.ERROR, e); + } + + return output; + } + + private void updateMotorConfig() + { + setModelConfig(getMotorConfig()); + } + + public void setModelConfig(DcMotorModelConfig aConfig) + { + mMotorType.getSelectionModel().select(aConfig.mFactoryParams.mMotorType); + mNumMotors.getValueFactory().setValue(aConfig.mFactoryParams.mNumMotors); + mGearRatio.setText(Double.toString(aConfig.mFactoryParams.mGearReduction)); + mEfficiency.setText(Double.toString(aConfig.mFactoryParams.mGearboxEfficiency)); + + mNominalVoltage.setText(mDecimalFormat.format(aConfig.mMotorParams.mNominalVoltage)); + mFreeSpeedRpm.setText(mDecimalFormat.format(aConfig.mMotorParams.mFreeSpeedRpm)); + mNominalCurrent.setText(mDecimalFormat.format(aConfig.mMotorParams.mFreeCurrent)); + mStallTorque.setText(mDecimalFormat.format(aConfig.mMotorParams.mStallTorque)); + mStallCurrent.setText(mDecimalFormat.format(aConfig.mMotorParams.mStallCurrent)); + mInverted.setSelected(aConfig.mFactoryParams.ismInverted()); + mBrake.setSelected(aConfig.mFactoryParams.ismHasBrake()); + + mMotorChartController.setCurveParams(aConfig); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/GravitationalLoadMotorSimController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/GravitationalLoadMotorSimController.java new file mode 100644 index 00000000..4a4f4495 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/GravitationalLoadMotorSimController.java @@ -0,0 +1,34 @@ +package com.snobot.simulator.gui.widgets.settings.motor_sim; + +import com.snobot.simulator.motor_sim.DcMotorModelConfig; +import com.snobot.simulator.motor_sim.GravityLoadMotorSimulationConfig; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.TextField; + +public class GravitationalLoadMotorSimController extends BaseMotorSimWithDcMotorModelController +{ + @FXML + private TextField mLoad; + + @Override + public void saveSettings(int aHandle) + { + double load = Double.parseDouble(mLoad.getText()); + DataAccessorFactory.getInstance().getSimulatorDataAccessor().setSpeedControllerModel_Gravitational(aHandle, + mMotorPanelController.getMotorConfig(), + new GravityLoadMotorSimulationConfig(load)); + } + + @Override + public void populate(int aHandle) + { + DcMotorModelConfig modelConfig = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getMotorConfig(aHandle); + mMotorPanelController.setModelConfig(modelConfig); + + GravityLoadMotorSimulationConfig config = DataAccessorFactory.getInstance().getSpeedControllerAccessor() + .getMotorSimGravitationalModelConfig(aHandle); + mLoad.setText(Double.toString(config.getLoad())); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/IMotorSimController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/IMotorSimController.java new file mode 100644 index 00000000..d0f36f12 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/IMotorSimController.java @@ -0,0 +1,10 @@ +package com.snobot.simulator.gui.widgets.settings.motor_sim; + +public interface IMotorSimController +{ + + void saveSettings(int aHandle); + + void populate(int aHandle); + +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/RotationalLoadMotorSimController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/RotationalLoadMotorSimController.java new file mode 100644 index 00000000..41bcef9a --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/RotationalLoadMotorSimController.java @@ -0,0 +1,30 @@ +package com.snobot.simulator.gui.widgets.settings.motor_sim; + +import com.snobot.simulator.motor_sim.DcMotorModelConfig; +import com.snobot.simulator.motor_sim.RotationalLoadMotorSimulationConfig; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.TextField; + +public class RotationalLoadMotorSimController extends BaseMotorSimWithDcMotorModelController +{ + @FXML + private TextField mLoad; + + @Override + public void saveSettings(int aHandle) + { + DataAccessorFactory.getInstance().getSimulatorDataAccessor().setSpeedControllerModel_Rotational(aHandle, + mMotorPanelController.getMotorConfig(), + new RotationalLoadMotorSimulationConfig(0, 0)); + } + + @Override + public void populate(int aHandle) + { + DcMotorModelConfig modelConfig = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getMotorConfig(aHandle); + mMotorPanelController.setModelConfig(modelConfig); + + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/SimpleMotorSimController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/SimpleMotorSimController.java new file mode 100644 index 00000000..e8c0b82b --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/SimpleMotorSimController.java @@ -0,0 +1,28 @@ +package com.snobot.simulator.gui.widgets.settings.motor_sim; + +import com.snobot.simulator.motor_sim.SimpleMotorSimulationConfig; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.TextField; + +public class SimpleMotorSimController implements IMotorSimController +{ + @FXML + private TextField mMaxSpeed; + + @Override + public void saveSettings(int aHandle) + { + double maxSpeed = Double.parseDouble(mMaxSpeed.getText()); + DataAccessorFactory.getInstance().getSimulatorDataAccessor().setSpeedControllerModel_Simple(aHandle, + new SimpleMotorSimulationConfig(maxSpeed)); + } + + @Override + public void populate(int aHandle) + { + SimpleMotorSimulationConfig config = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getMotorSimSimpleModelConfig(aHandle); + mMaxSpeed.setText(Double.toString(config.mMaxSpeed)); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/StaticLoadMotorSimController.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/StaticLoadMotorSimController.java new file mode 100644 index 00000000..4c2bc5a0 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/gui/widgets/settings/motor_sim/StaticLoadMotorSimController.java @@ -0,0 +1,32 @@ +package com.snobot.simulator.gui.widgets.settings.motor_sim; + +import com.snobot.simulator.motor_sim.DcMotorModelConfig; +import com.snobot.simulator.motor_sim.StaticLoadMotorSimulationConfig; +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +import javafx.fxml.FXML; +import javafx.scene.control.TextField; + +public class StaticLoadMotorSimController extends BaseMotorSimWithDcMotorModelController +{ + @FXML + private TextField mLoad; + + @Override + public void saveSettings(int aHandle) + { + double load = Double.parseDouble(mLoad.getText()); + DataAccessorFactory.getInstance().getSimulatorDataAccessor().setSpeedControllerModel_Static(aHandle, mMotorPanelController.getMotorConfig(), + new StaticLoadMotorSimulationConfig(load)); + } + + @Override + public void populate(int aHandle) + { + DcMotorModelConfig modelConfig = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getMotorConfig(aHandle); + mMotorPanelController.setModelConfig(modelConfig); + + StaticLoadMotorSimulationConfig config = DataAccessorFactory.getInstance().getSpeedControllerAccessor().getMotorSimStaticModelConfig(aHandle); + mLoad.setText(Double.toString(config.mLoad)); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/robot_container/CppRobotContainer.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/robot_container/CppRobotContainer.java new file mode 100644 index 00000000..26e784c7 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/robot_container/CppRobotContainer.java @@ -0,0 +1,55 @@ +package com.snobot.simulator.robot_container; + +import java.lang.reflect.Method; + +import com.snobot.simulator.JniLibraryResourceLoader; + +/** + * Wrapper class around a C++ robot's code + * + * @author PJ + * + */ +public class CppRobotContainer implements IRobotClassContainer +{ + private final String mRobotClassName; + private Class mJniClass; + + public CppRobotContainer(String aRobotClassName) + { + mRobotClassName = aRobotClassName; + } + + @Override + public void constructRobot() + throws ReflectiveOperationException + { + mJniClass = Class.forName(mRobotClassName); + + String libraryName = (String) mJniClass.getMethod("getLibraryName").invoke(null); + + String openCvVersion = "343"; + + JniLibraryResourceLoader.loadLibrary("ntcore"); + JniLibraryResourceLoader.loadLibrary("opencv_core" + openCvVersion); + JniLibraryResourceLoader.loadLibrary("opencv_imgproc" + openCvVersion); + JniLibraryResourceLoader.loadLibrary("opencv_imgcodecs" + openCvVersion); + JniLibraryResourceLoader.loadLibrary("cscore"); + JniLibraryResourceLoader.loadLibrary("wpiutil"); + JniLibraryResourceLoader.loadLibrary("cameraserver"); + JniLibraryResourceLoader.loadLibrary("wpilibc"); + JniLibraryResourceLoader.loadLibrary("snobot_sim"); + JniLibraryResourceLoader.loadLibrary(libraryName); + + Method method = mJniClass.getMethod("createRobot"); + method.invoke(null); + } + + @Override + public void startCompetition() + throws ReflectiveOperationException + { + Method method = mJniClass.getMethod("startCompetition"); + method.invoke(null); + } +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/robot_container/IRobotClassContainer.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/robot_container/IRobotClassContainer.java new file mode 100644 index 00000000..76a795f2 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/robot_container/IRobotClassContainer.java @@ -0,0 +1,16 @@ +package com.snobot.simulator.robot_container; + +/** + * Interface that provides a wrapper around a robot class + * + * @author PJ + * + */ +public interface IRobotClassContainer +{ + public void constructRobot() + throws ReflectiveOperationException; + + public void startCompetition() + throws ReflectiveOperationException; +} diff --git a/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/robot_container/JavaRobotContainer.java b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/robot_container/JavaRobotContainer.java new file mode 100644 index 00000000..50932f80 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/java/com/snobot/simulator/robot_container/JavaRobotContainer.java @@ -0,0 +1,37 @@ +package com.snobot.simulator.robot_container; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Wrapper class around a Java robot + * + * @author PJ + * + */ +public class JavaRobotContainer implements IRobotClassContainer +{ + private final String mRobotClassName; + private RobotBase mRobot; + + public JavaRobotContainer(String aRobotClassName) + { + mRobotClassName = aRobotClassName; + } + + @Override + public void constructRobot() throws ReflectiveOperationException + { + mRobot = (RobotBase) Class.forName(mRobotClassName).newInstance(); + } + + @Override + public void startCompetition() + { + mRobot.startCompetition(); + } + + public RobotBase getJavaRobot() + { + return mRobot; + } +} diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/configuration_panel.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/configuration_panel.fxml new file mode 100644 index 00000000..33069158 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/configuration_panel.fxml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/enable_panel.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/enable_panel.fxml new file mode 100644 index 00000000..df2cae8a --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/enable_panel.fxml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/game_data/generic_game_data.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/game_data/generic_game_data.fxml new file mode 100644 index 00000000..1eb7d975 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/game_data/generic_game_data.fxml @@ -0,0 +1,20 @@ + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/game_data/power_up_game_data.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/game_data/power_up_game_data.fxml new file mode 100644 index 00000000..4e682b30 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/game_data/power_up_game_data.fxml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/connected_input_config_panel.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/connected_input_config_panel.fxml new file mode 100644 index 00000000..e21c4c97 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/connected_input_config_panel.fxml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+
diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/current_settings.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/current_settings.fxml new file mode 100644 index 00000000..34753b18 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/current_settings.fxml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/joystick_manager_controller.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/joystick_manager_controller.fxml new file mode 100644 index 00000000..fcb1c1ad --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/joystick_manager_controller.fxml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+
+
diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/analog_input_panel.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/analog_input_panel.fxml new file mode 100644 index 00000000..8d0c08ec --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/analog_input_panel.fxml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/digital_input_panel.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/digital_input_panel.fxml new file mode 100644 index 00000000..a203a079 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/digital_input_panel.fxml @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/raw_controller.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/raw_controller.fxml new file mode 100644 index 00000000..40ec0f17 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/raw_controller.fxml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/wrapped_controller.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/wrapped_controller.fxml new file mode 100644 index 00000000..f2ef25f1 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/wrapped_controller.fxml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/xbox_controller.png b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/xbox_controller.png new file mode 100644 index 00000000..2756d16a Binary files /dev/null and b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/xbox_controller.png differ diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/xbox_display.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/xbox_display.fxml new file mode 100644 index 00000000..568fa35b --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/joysticks/sub_panels/xbox_display.fxml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/motor_graphs/motor_curve_display.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/motor_graphs/motor_curve_display.fxml new file mode 100644 index 00000000..40ab5b57 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/motor_graphs/motor_curve_display.fxml @@ -0,0 +1,22 @@ + + + + + + + + + + + +
+ + + + + + + + +
+
diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/simulator_frame.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/simulator_frame.fxml new file mode 100644 index 00000000..d69c9ce5 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/simulator_frame.fxml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + +
diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/advanced_settings_widget.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/advanced_settings_widget.fxml new file mode 100644 index 00000000..71821b0e --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/advanced_settings_widget.fxml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/analog_out_widget.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/analog_out_widget.fxml new file mode 100644 index 00000000..dd109cb4 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/analog_out_widget.fxml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/digital_io_controller_widget.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/digital_io_controller_widget.fxml new file mode 100644 index 00000000..54729f12 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/digital_io_controller_widget.fxml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/encoder_widget.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/encoder_widget.fxml new file mode 100644 index 00000000..e2f625d1 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/encoder_widget.fxml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/gear.png b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/gear.png new file mode 100644 index 00000000..b84d8ec9 Binary files /dev/null and b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/gear.png differ diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/gyro_widget.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/gyro_widget.fxml new file mode 100644 index 00000000..701eee23 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/gyro_widget.fxml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/relay_widget.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/relay_widget.fxml new file mode 100644 index 00000000..e4beda70 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/relay_widget.fxml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/settings/advanced/spi_i2c_settings.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/settings/advanced/spi_i2c_settings.fxml new file mode 100644 index 00000000..4da57ab8 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/settings/advanced/spi_i2c_settings.fxml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/settings/advanced/tank_drive_settings.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/settings/advanced/tank_drive_settings.fxml new file mode 100644 index 00000000..21cf502d --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/settings/advanced/tank_drive_settings.fxml @@ -0,0 +1,15 @@ + + + + + + + +
+ + +
+ + + + + +
diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/speed_controller_widget.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/speed_controller_widget.fxml new file mode 100644 index 00000000..ff7dd22b --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/gui/widgets/speed_controller_widget.fxml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/preloader.fxml b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/preloader.fxml new file mode 100644 index 00000000..6cdc0ad8 --- /dev/null +++ b/snobot_sim_gui_javafx/src/main/resources/com/snobot/simulator/preloader.fxml @@ -0,0 +1,29 @@ + + + + + + + + + + + +
+ + + + +
+ + + + +
diff --git a/snobot_sim_gui_javafx/src/main/resources/themes/snobot_sim.css b/snobot_sim_gui_javafx/src/main/resources/themes/snobot_sim.css new file mode 100644 index 00000000..e69de29b diff --git a/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/IJoystickInterface.java b/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/IJoystickInterface.java new file mode 100644 index 00000000..f36a1269 --- /dev/null +++ b/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/IJoystickInterface.java @@ -0,0 +1,9 @@ +package com.snobot.simulator.joysticks; + +public interface IJoystickInterface +{ + + void sendJoystickUpdate(); + + void waitForLoop(); +} diff --git a/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/JoystickConfigurationReader.java b/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/JoystickConfigurationReader.java new file mode 100644 index 00000000..175b2430 --- /dev/null +++ b/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/JoystickConfigurationReader.java @@ -0,0 +1,88 @@ +//package com.snobot.simulator.joysticks; +// +//import java.io.File; +//import java.io.FileInputStream; +//import java.io.FileOutputStream; +//import java.io.IOException; +//import java.io.InputStream; +//import java.nio.file.Files; +//import java.nio.file.Paths; +//import java.util.Map; +//import java.util.Map.Entry; +//import java.util.Properties; +// +//import org.apache.logging.log4j.Level; +// +//import edu.wpi.first.wpilibj.DriverStation; +// +//public class JoystickConfigurationReader +//{ +// +// private final Map mControllerConfig; +// +// private void writeJoystickFile() +// { +// try +// { +// Properties p = new Properties(); +// for (int i = 0; i < DriverStation.kJoystickPorts; ++i) +// { +// String joystickName = mJoystickMap[i].getName(); +// +// ControllerConfiguration config = mControllerConfig.get(joystickName); +// String specializationName = config == null ? null : config.mSpecialization.getName(); +// +// p.put(sKEY + i, joystickName + "---" + specializationName); +// } +// +// try (FileOutputStream stream = new FileOutputStream(sJOYSTICK_CONFIG_FILE)) +// { +// p.store(stream, ""); +// } +// +// sLOGGER.log(Level.INFO, "Wrote joystick config file to " + new File(sJOYSTICK_CONFIG_FILE).getAbsolutePath()); +// } +// catch (Exception ex) +// { +// sLOGGER.log(Level.ERROR, ex); +// } +// } +// +// private void readLegacyFile(String aConfigFile) +// { +// if (!Files.exists(Paths.get(aConfigFile))) +// { +// writeJoystickFile(); +// return; +// } +// +// try +// { +// InputStream inputStream = new FileInputStream(aConfigFile); +// Properties properties = new Properties(); +// properties.load(inputStream); +// inputStream.close(); +// +// for (Entry i : properties.entrySet()) +// { +// int number = Integer.parseInt(i.getKey().toString().substring(sKEY.length())); +// +// String config = i.getValue().toString(); +// String[] parts = config.split("---"); +// +// String joystickName = parts[0]; +// String specialization = parts[1]; +// +// if (!"null".equals(specialization)) +// { +// setSpecialization(joystickName, (Class) Class.forName(specialization), false); +// } +// setJoysticks(number, joystickName, false); +// } +// } +// catch (IOException | ClassNotFoundException ex) +// { +// sLOGGER.log(Level.ERROR, ex); +// } +// } +//} diff --git a/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/NullJoystickInterface.java b/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/NullJoystickInterface.java new file mode 100644 index 00000000..2227e211 --- /dev/null +++ b/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/NullJoystickInterface.java @@ -0,0 +1,17 @@ +package com.snobot.simulator.joysticks; + +public class NullJoystickInterface implements IJoystickInterface +{ + @Override + public void sendJoystickUpdate() + { + + } + + @Override + public void waitForLoop() + { + + } + +} diff --git a/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/SnobotSimJoystickInterface.java b/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/SnobotSimJoystickInterface.java new file mode 100644 index 00000000..43f4cea6 --- /dev/null +++ b/snobot_sim_joysticks/src/main/java/com/snobot/simulator/joysticks/SnobotSimJoystickInterface.java @@ -0,0 +1,25 @@ +package com.snobot.simulator.joysticks; + +import com.snobot.simulator.wrapper_accessors.DataAccessorFactory; + +public class SnobotSimJoystickInterface implements IJoystickInterface +{ + @Override + public void sendJoystickUpdate() + { + IMockJoystick[] joysticks = JoystickFactory.getInstance().getAll(); + for (int i = 0; i < joysticks.length; ++i) + { + IMockJoystick joystick = joysticks[i]; + DataAccessorFactory.getInstance().getDriverStationAccessor().setJoystickInformation(i, joystick.getAxisValues(), joystick.getPovValues(), + joystick.getButtonCount(), joystick.getButtonMask()); + } + } + + @Override + public void waitForLoop() + { + DataAccessorFactory.getInstance().getDriverStationAccessor().waitForNextUpdateLoop(); + } + +} diff --git a/styleguide/pmd-ruleset.xml b/styleguide/pmd-ruleset.xml index b3c84365..755ea55d 100644 --- a/styleguide/pmd-ruleset.xml +++ b/styleguide/pmd-ruleset.xml @@ -83,6 +83,7 @@ +