├── vers.bat ├── src └── main │ ├── resources │ └── assets │ │ └── toast │ │ ├── toast.version │ │ ├── toast.git_info │ │ ├── gui │ │ └── darkRIOsmall.png │ │ ├── script │ │ └── js │ │ │ ├── PostLoad.js │ │ │ ├── Util.js │ │ │ ├── Map.js │ │ │ ├── Motor.js │ │ │ └── Filesystem.js │ │ ├── ascii │ │ ├── crash.txt │ │ └── splash.txt │ │ └── patches │ │ └── patches.txt │ └── java │ └── jaci │ └── openrio │ └── toast │ ├── core │ ├── loader │ │ ├── simulation │ │ │ ├── jni │ │ │ │ ├── DummyJoystick.java │ │ │ │ ├── InterruptContainer.java │ │ │ │ └── SimulatedJoystick.java │ │ │ ├── CommonGUI.java │ │ │ ├── GuiScrollbar.java │ │ │ ├── GuiProgress.java │ │ │ ├── GuiRelay.java │ │ │ ├── PneumaticsGUI.java │ │ │ ├── srx │ │ │ │ ├── SRX_Reg.java │ │ │ │ ├── GuiSRX.java │ │ │ │ └── TalonSRX_GUI.java │ │ │ ├── GuiPCM.java │ │ │ └── GuiRobotState.java │ │ ├── annotation │ │ │ ├── NoLoad.java │ │ │ ├── Priority.java │ │ │ └── Branch.java │ │ ├── module │ │ │ └── ModuleManager.java │ │ ├── EnvJars.java │ │ └── verification │ │ │ └── VerificationWorker.java │ ├── command │ │ ├── IHelpable.java │ │ ├── UsageException.java │ │ ├── FuzzyCommand.java │ │ ├── AbstractCommand.java │ │ └── cmd │ │ │ ├── CommandExit.java │ │ │ ├── CommandInvokeCrash.java │ │ │ ├── CommandReloadConfigs.java │ │ │ ├── CommandEnvironment.java │ │ │ ├── CommandList.java │ │ │ ├── CommandThreadPool.java │ │ │ ├── CommandJScript.java │ │ │ └── CommandHelp.java │ ├── shared │ │ ├── GlobalBlackboard.java │ │ ├── ModuleEventListener.java │ │ ├── ModuleEventBus.java │ │ └── OptionParser.java │ ├── thread │ │ ├── AsyncTask.java │ │ ├── HeartbeatListener.java │ │ ├── NonVitalLoadTask.java │ │ └── Async.java │ ├── script │ │ └── js │ │ │ └── proxy │ │ │ └── FileProxy.java │ ├── security │ │ └── SecurityPolicy.java │ ├── network │ │ ├── SocketManager.java │ │ ├── ToastSessionJoiner.java │ │ └── CommandDelegate.java │ ├── io │ │ └── usb │ │ │ └── MassStorageDevice.java │ └── ToastConfiguration.java │ └── lib │ ├── device │ ├── POV.java │ └── SimpleRelay.java │ ├── state │ ├── RobotState.java │ ├── StateListener.java │ └── ConcurrentVector.java │ ├── log │ ├── LogHandler.java │ ├── ColorPrint.java │ ├── LogLevel.java │ ├── SysLogProxy.java │ └── SplitStream.java │ ├── crash │ ├── CrashInfoProvider.java │ ├── CrashInfoEnvironment.java │ ├── CrashInfoToast.java │ └── CrashInfoModules.java │ ├── Assets.java │ ├── FRCHooks.java │ ├── math │ └── MathHelper.java │ ├── module │ ├── ToastStateModule.java │ └── ToastModule.java │ ├── EvictingQueue.java │ ├── util │ ├── JSONUtil.java │ └── ToastUtil.java │ └── profiler │ └── ProfilerEntity.java ├── tools ├── setup.rb ├── Documentation.jar ├── inspector.rb └── imports.rb ├── release ├── .gitignore ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── .travis.yml ├── Credits.txt ├── build.gradle ├── ToastGradle4Dummies.txt └── gradlew.bat ├── doc ├── wiki │ └── stf │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 11.png │ │ ├── 12.png │ │ ├── 13.png │ │ ├── 14.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ └── 9.png ├── resources │ ├── Pipeline.png │ ├── lifecycle.png │ ├── ds_connect.png │ ├── SimulationGUI.png │ ├── logo_tiny_text.png │ └── logo_christmas_tiny_text.png └── manuals │ └── NETWORK.MD ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── patches ├── gradle │ ├── libs │ │ └── GradleRIO.jar │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── main │ │ └── java │ │ └── edu │ │ └── wpi │ │ └── first │ │ └── wpilibj │ │ └── hal │ │ ├── ConstantsJNI.java │ │ ├── JNIWrapper.java │ │ ├── AccelerometerJNI.java │ │ ├── DigitalGlitchFilterJNI.java │ │ ├── RelayJNI.java │ │ ├── PDPJNI.java │ │ ├── NotifierJNI.java │ │ ├── HALUtil.java │ │ ├── PortsJNI.java │ │ ├── SolenoidJNI.java │ │ ├── DIOJNI.java │ │ ├── PowerJNI.java │ │ ├── CompressorJNI.java │ │ └── InterruptJNI.java ├── settings.gradle ├── build.gradle └── gradlew.bat ├── patches_full ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle ├── build.gradle └── gradlew.bat ├── .editorconfig ├── appveyor.yml ├── unix_gradle.rb ├── .gitignore ├── .travis.yml ├── examples ├── config │ └── Configuration.java ├── basic │ ├── BasicToastModule.java │ └── DrivingModule.java ├── command │ └── CommandDemo.java ├── states │ ├── StateInterfaces.java │ └── StateModule.java ├── heartbeat │ └── Heartbeat.java ├── threads │ └── ThreadPoolWorker.java └── network │ └── EchoDelegate.java ├── dirs.md ├── LICENSE ├── LICENSE_WPI_BSD ├── vers └── gradlew.bat /vers.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | ruby vers %* 3 | -------------------------------------------------------------------------------- /src/main/resources/assets/toast/toast.version: -------------------------------------------------------------------------------- 1 | 2.4.14 2 | -------------------------------------------------------------------------------- /tools/setup.rb: -------------------------------------------------------------------------------- 1 | ` gem install gist ` 2 | ` gem install json ` 3 | -------------------------------------------------------------------------------- /release/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | build/ 3 | run/ 4 | *.iml 5 | *.ipr 6 | *.iws 7 | -------------------------------------------------------------------------------- /doc/wiki/stf/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/1.png -------------------------------------------------------------------------------- /doc/wiki/stf/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/10.png -------------------------------------------------------------------------------- /doc/wiki/stf/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/11.png -------------------------------------------------------------------------------- /doc/wiki/stf/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/12.png -------------------------------------------------------------------------------- /doc/wiki/stf/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/13.png -------------------------------------------------------------------------------- /doc/wiki/stf/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/14.png -------------------------------------------------------------------------------- /doc/wiki/stf/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/2.png -------------------------------------------------------------------------------- /doc/wiki/stf/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/3.png -------------------------------------------------------------------------------- /doc/wiki/stf/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/4.png -------------------------------------------------------------------------------- /doc/wiki/stf/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/5.png -------------------------------------------------------------------------------- /doc/wiki/stf/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/6.png -------------------------------------------------------------------------------- /doc/wiki/stf/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/7.png -------------------------------------------------------------------------------- /doc/wiki/stf/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/8.png -------------------------------------------------------------------------------- /doc/wiki/stf/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/wiki/stf/9.png -------------------------------------------------------------------------------- /src/main/resources/assets/toast/toast.git_info: -------------------------------------------------------------------------------- 1 | 6ef917b09459a7f2a304d72e7b87567fccf1abb1 2 | 6ef917b 3 | -------------------------------------------------------------------------------- /tools/Documentation.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/tools/Documentation.jar -------------------------------------------------------------------------------- /doc/resources/Pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/resources/Pipeline.png -------------------------------------------------------------------------------- /doc/resources/lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/resources/lifecycle.png -------------------------------------------------------------------------------- /doc/resources/ds_connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/resources/ds_connect.png -------------------------------------------------------------------------------- /doc/resources/SimulationGUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/resources/SimulationGUI.png -------------------------------------------------------------------------------- /doc/resources/logo_tiny_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/resources/logo_tiny_text.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /patches/gradle/libs/GradleRIO.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/patches/gradle/libs/GradleRIO.jar -------------------------------------------------------------------------------- /doc/resources/logo_christmas_tiny_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/doc/resources/logo_christmas_tiny_text.png -------------------------------------------------------------------------------- /patches/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/patches/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /release/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/release/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /patches_full/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/patches_full/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/assets/toast/gui/darkRIOsmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-RIO/ToastAPI/HEAD/src/main/resources/assets/toast/gui/darkRIOsmall.png -------------------------------------------------------------------------------- /src/main/resources/assets/toast/script/js/PostLoad.js: -------------------------------------------------------------------------------- 1 | $.command("eval", function() { 2 | var fcmd = [].slice.call(arguments).join(" "); 3 | eval(fcmd); 4 | }); -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.java] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 4 11 | -------------------------------------------------------------------------------- /release/.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | install: 4 | - "./gradlew assemble" 5 | 6 | script: 7 | - "./gradlew verify" 8 | jdk: 9 | - oraclejdk8 10 | 11 | notifications: 12 | email: false 13 | -------------------------------------------------------------------------------- /release/Credits.txt: -------------------------------------------------------------------------------- 1 | Credits for GradleRIO: 2 | -Jaci (@JacisNonsense): coding the plugin 3 | -WPILib Team: providing WPILib and the eclipse plugin 4 | -FIRST Robotics: For the awesome competition and Kit of Parts 5 | 6 | <3 7 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/ConstantsJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | public class ConstantsJNI { 4 | public static int getSystemClockTicksPerMicrosecond() { 5 | return 40; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/resources/assets/toast/ascii/crash.txt: -------------------------------------------------------------------------------- 1 | ________ __ ____ ____ __ 2 | (( ) / / / / /_ / __ \/ /_ 3 | || x x | / / / / __ \ / / / / __ \ 4 | || ^ | / /_/ / / / / / /_/ / / / / 5 | \\_______/ \____/_/ /_/ \____/_/ /_/ -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/jni/DummyJoystick.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation.jni; 2 | 3 | public class DummyJoystick extends SimulatedJoystick { 4 | 5 | public DummyJoystick() { 6 | super(12, 5, 1); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jan 13 09:50:12 WST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-bin.zip 7 | -------------------------------------------------------------------------------- /patches/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Feb 17 08:55:01 WST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip 7 | -------------------------------------------------------------------------------- /release/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jan 16 23:27:58 WST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip 7 | -------------------------------------------------------------------------------- /patches_full/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Feb 17 08:55:01 WST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip 7 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | branches: 2 | only: 3 | - master 4 | - development 5 | 6 | skip_tags: true 7 | 8 | install: 9 | - "gradlew.bat build" 10 | - "gradlew.bat generateExternalPatches" 11 | - "gradlew.bat build" 12 | 13 | build_script: 14 | - "gradlew.bat verify" 15 | 16 | artifacts: 17 | - path: build\libs\*.* 18 | -------------------------------------------------------------------------------- /src/main/resources/assets/toast/ascii/splash.txt: -------------------------------------------------------------------------------- 1 | ________ ______ __ 2 | (( ) /_ __/___ ____ ______/ /_ 3 | || o o | / / / __ \/ __ `/ ___/ __/ 4 | || 3 | / / / /_/ / /_/ (__ ) /_ 5 | \\_______/ /_/ \____/\__,_/____/\__/ -------------------------------------------------------------------------------- /unix_gradle.rb: -------------------------------------------------------------------------------- 1 | 2 | files = ['gradlew', 'build.gradle', 'release/gradlew', 'release/build.gradle', 'patches/gradlew', 'patches/build.gradle'] 3 | 4 | files.each do |filename| 5 | file_content = File.read(filename) 6 | new_content = file_content.gsub(/\r\n?/, "\n") 7 | 8 | File.open(filename, "w") { |file| file.puts new_content } 9 | end 10 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/device/POV.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.device; 2 | 3 | /** 4 | * An enumeration of possible POV directions. 5 | * 6 | * @author Jaci 7 | */ 8 | public enum POV { 9 | NONE(-1), UP(0), UP_RIGHT(45), RIGHT(90), DOWN_RIGHT(135), DOWN(180), DOWN_LEFT(225), LEFT(270), UP_LEFT(315); 10 | 11 | public int direction; 12 | 13 | POV(int direction) { 14 | this.direction = direction; 15 | } 16 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | Toast.ipr 3 | Toast.iws 4 | .gradle/ 5 | out/ 6 | build/ 7 | patches/build/ 8 | *.psd 9 | toast/crash/crash-2015-03-07_05-45-15.txt 10 | toast/crash/ 11 | toast/log/recent.txt 12 | toast/log/ 13 | toast/groovy/ 14 | toast/preferences/ 15 | run/ 16 | libs/groovy-2.4.1.jar 17 | releases/ 18 | deploymentScripts/gradle/gradle/wrapper/gradle-wrapper.properties 19 | patches_full/gradle/libs/GradleRIO.jar 20 | tools/stats/ 21 | /bin/ 22 | .classpath 23 | .settings/ 24 | .project 25 | gradle/.launch 26 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/state/RobotState.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.state; 2 | 3 | /** 4 | * An enumeration of all the states a robot can be in. Used in the 5 | * {@link jaci.openrio.toast.core.StateTracker} class 6 | * 7 | * @author Jaci 8 | */ 9 | public enum RobotState { 10 | DISABLED("Disabled"), 11 | TELEOP("Teleop"), 12 | AUTONOMOUS("Autonomous"), 13 | TEST("Test"); 14 | 15 | public String state; 16 | 17 | RobotState(String state) { 18 | this.state = state; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/assets/toast/script/js/Util.js: -------------------------------------------------------------------------------- 1 | var $EXEC = function() { 2 | var builder = new java.lang.ProcessBuilder(arr_to_vector([].slice.call(arguments))); 3 | builder.redirectErrorStream(true); 4 | var process = builder.start(); 5 | var reader = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream())); 6 | var line = ""; 7 | var out = ""; 8 | while ((line = reader.readLine()) != null) { 9 | out += line + "\n"; 10 | } 11 | process.waitFor(); 12 | reader.close(); 13 | return out; 14 | }; -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/log/LogHandler.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.log; 2 | 3 | /** 4 | * An interface that attaches to all instances of {@link jaci.openrio.toast.lib.log.Logger} 5 | * 6 | * This class is notified when a message is logged 7 | * 8 | * @author Jaci 9 | */ 10 | public interface LogHandler { 11 | 12 | /** 13 | * Called after a message is logged. Use this to send data to your driver-station or whatever else 14 | */ 15 | public void onLog(String level, String message, String formatted, Logger logger); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | # Make NetworkTables happy 4 | addons: 5 | apt: 6 | sources: 7 | - ubuntu-toolchain-r-test 8 | packages: 9 | - libstdc++6 10 | 11 | install: 12 | - "./gradlew build" 13 | - "./gradlew generateExternalPatches" 14 | - "./gradlew build" 15 | - "./gradlew genMetrics" 16 | - ruby tools/setup.rb 17 | - ruby tools/inspector.rb 18 | - ruby tools/imports.rb 19 | - "./gradlew verify" 20 | jdk: 21 | - oraclejdk8 22 | notifications: 23 | email: false 24 | cards: 25 | enabled: 26 | - master 27 | - development 28 | title: Toast 29 | -------------------------------------------------------------------------------- /examples/config/Configuration.java: -------------------------------------------------------------------------------- 1 | package toast.examples; 2 | 3 | import jaci.openrio.toast.lib.module.ModuleConfig; 4 | 5 | public class Configuration { 6 | 7 | ModuleConfig preferences; 8 | 9 | public void register() { // This would be called from your Main module 10 | preferences = new ModuleConfig("my_module_name"); 11 | int my_int = preferences.getInt("my_int", 0); 12 | String my_str = preferences.getString("my_str", "Hello World"); 13 | 14 | int nested_int = preferences.getInt("nested.my_int", 1); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/JNIWrapper.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | public class JNIWrapper { 6 | 7 | public static int getPort(byte port) { 8 | return getPortWithModule((byte)0, port); 9 | } 10 | 11 | public static int getPortWithModule(byte module, byte channel) { 12 | byte[] data = { module, channel }; 13 | return (int)ByteBuffer.wrap(data).getShort(); 14 | } 15 | 16 | public static byte[] getPortAndModuleFromHandle(int handle) { 17 | return ByteBuffer.allocate(2).putShort((short)handle).array(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/annotation/NoLoad.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.annotation; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | /** 7 | * Placing this annotation on a {@link jaci.openrio.toast.lib.module.ToastModule} class will cause the loader to not 8 | * recognize the module as a valid candidate. This is used for ToastModules that are used as abstract classes or designed 9 | * to be extended by other classes. This should be placed above the class definition. 10 | * 11 | * @author Jaci 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface NoLoad { } 15 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/IHelpable.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command; 2 | 3 | /** 4 | * Provider for the 'Help' command. Commands implementing this interface provide a 'help' message 5 | * to allow the user to know what exactly the command does, as well as it's arguments. 6 | * 7 | * @author Jaci 8 | */ 9 | public interface IHelpable { 10 | 11 | /** 12 | * Get the command name 13 | * e.g. 'cmd' for a command such as 'cmd 14 | */ 15 | public String getCommandName(); 16 | 17 | /** 18 | * Returns a help message to display with the 'help' command 19 | */ 20 | public String getHelp(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /dirs.md: -------------------------------------------------------------------------------- 1 | Dir Mappings 2 | ==== 3 | 4 | - deploymentScripts 5 | - Used in the Toast Deployment Utility, contains the gradle bindings and shell scripts 6 | - doc 7 | - Contains documentation resources 8 | - examples 9 | - Basic examples without the wrapping gradle files or java projects. Kind of like a 'quick reference'. 10 | - manuals 11 | - Contains things like Delegate Mappings and such 12 | - patches 13 | - Simulation Patches sub-project (.sim) 14 | - patches_full 15 | - Global Patches sub-project (.pat) 16 | - release 17 | - Template files for the .zip release of Toast 18 | - runnableScripts 19 | - Scripts for the ToastRunnable .jar 20 | - src 21 | - Toast Source Files 22 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/shared/GlobalBlackboard.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.shared; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * The GlobalBlackboard is a {@link java.util.HashMap} with a single instance that allows 7 | * for data to be shared globally among all Modules and Toast itself. This is used to store 8 | * data throughout the entire Toast session that can be read at any time. 9 | * 10 | * @author Jaci 11 | */ 12 | public class GlobalBlackboard extends HashMap { 13 | 14 | public static GlobalBlackboard INSTANCE; 15 | 16 | public GlobalBlackboard() { 17 | super(); 18 | INSTANCE = this; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /examples/basic/BasicToastModule.java: -------------------------------------------------------------------------------- 1 | package toast.examples; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.lib.module.ToastModule; 5 | 6 | public class BasicToastModule extends ToastModule { 7 | 8 | @Override 9 | public String getModuleName() { 10 | return "Basic_Toast_Module"; 11 | } 12 | 13 | @Override 14 | public String getModuleVersion() { 15 | return "1.0.0"; // Recommended to follow the standard Toast Versioning System (major.minor.build-prebuild) 16 | } 17 | 18 | @Override 19 | public void prestart() { 20 | Toast.log().info("Hi from Module!"); 21 | } 22 | 23 | @Override 24 | public void start() { 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /patches/settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This settings file was auto generated by the Gradle buildInit task 3 | * by 'jaci' at '17/02/15 8:55 AM' with Gradle 2.2.1 4 | * 5 | * The settings file is used to specify which projects to include in your build. 6 | * In a single project build this file can be empty or even removed. 7 | * 8 | * Detailed information about configuring a multi-project build in Gradle can be found 9 | * in the user guide at http://gradle.org/docs/2.2.1/userguide/multi_project_builds.html 10 | */ 11 | 12 | /* 13 | // To declare projects as part of a multi-project build use the 'include' method 14 | include 'shared' 15 | include 'api' 16 | include 'services:webservice' 17 | */ 18 | 19 | rootProject.name = 'patches' 20 | -------------------------------------------------------------------------------- /patches_full/settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This settings file was auto generated by the Gradle buildInit task 3 | * by 'jaci' at '17/02/15 8:55 AM' with Gradle 2.2.1 4 | * 5 | * The settings file is used to specify which projects to include in your build. 6 | * In a single project build this file can be empty or even removed. 7 | * 8 | * Detailed information about configuring a multi-project build in Gradle can be found 9 | * in the user guide at http://gradle.org/docs/2.2.1/userguide/multi_project_builds.html 10 | */ 11 | 12 | /* 13 | // To declare projects as part of a multi-project build use the 'include' method 14 | include 'shared' 15 | include 'api' 16 | include 'services:webservice' 17 | */ 18 | 19 | rootProject.name = 'patchesfull' 20 | -------------------------------------------------------------------------------- /patches/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | } 6 | 7 | apply plugin: 'java' 8 | apply plugin: 'idea' 9 | 10 | ext.settings = file "../build.settings" 11 | settings.withReader { 12 | def prop = new Properties() 13 | prop.load(it) 14 | project.ext.settings = new ConfigSlurper().parse prop 15 | } 16 | 17 | dependencies { 18 | compile fileTree(dir: "../build/libs", include: "*${settings.toast.version}.jar") 19 | } 20 | 21 | task genPatches << { 22 | try { 23 | ant.delete(dir: "build/patches") 24 | } catch (Exception e) {} 25 | ant.copy(todir: "build/patches") { 26 | ant.fileset(dir: "build/classes/main") 27 | ant.mapper(type: "glob", from: "*.class", to: "*.sim") 28 | } 29 | } 30 | 31 | build.finalizedBy genPatches 32 | -------------------------------------------------------------------------------- /examples/command/CommandDemo.java: -------------------------------------------------------------------------------- 1 | package toast.examples; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.command.AbstractCommand; 5 | import jaci.openrio.toast.core.command.CommandBus; 6 | 7 | import java.util.Arrays; 8 | 9 | public class CommandDemo extends AbstractCommand { 10 | 11 | public void register() { // This would be called by your Main module class 12 | CommandBus.registerCommand(new CommandDemo()); 13 | } 14 | 15 | @Override 16 | public String getCommandName() { 17 | return "demo"; 18 | } 19 | 20 | @Override 21 | public void invokeCommand(int argLength, String[] args, String command) { 22 | Toast.log().info("Hello world! I was told to: " + Arrays.toString(args)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/assets/toast/script/js/Map.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Converts a HashMap to a JavaScript object that can be sent through to JSON.stringify() or other methods. 3 | * This implementation supports Map<>, List<>, Object[] and Object types 4 | */ 5 | var hash_to_object = function(hash) { 6 | var object = {}; 7 | for (var obj in hash) { 8 | if (java.util.Map.class.isAssignableFrom(hash[obj].class)) { 9 | object[obj] = hash_to_object(hash[obj]); 10 | } else if (hash[obj].class.isArray() || java.util.List.class.isAssignableFrom(hash[obj].class)) { 11 | var arr = []; 12 | for (var objin in hash[obj]) 13 | arr.push(hash[obj][objin]); 14 | object[obj] = arr; 15 | } else 16 | object[obj] = hash[obj]; 17 | } 18 | return object; 19 | }; -------------------------------------------------------------------------------- /patches_full/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | } 6 | 7 | apply plugin: 'java' 8 | apply plugin: 'idea' 9 | 10 | ext.settings = file "../build.settings" 11 | settings.withReader { 12 | def prop = new Properties() 13 | prop.load(it) 14 | project.ext.settings = new ConfigSlurper().parse prop 15 | } 16 | 17 | dependencies { 18 | compile fileTree(dir: "../build/libs", include: "*${settings.toast.version}.jar") 19 | } 20 | 21 | task genPatches << { 22 | try { 23 | ant.delete(dir: "build/patches") 24 | } catch (Exception e) {} 25 | try { 26 | ant.copy(todir: "build/patches") { 27 | ant.fileset(dir: "build/classes/main") 28 | ant.mapper(type: "glob", from: "*.class", to: "*.pat") 29 | } 30 | } catch (Exception e) {} 31 | } 32 | 33 | build.finalizedBy genPatches 34 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/AccelerometerJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 4 | 5 | public class AccelerometerJNI extends JNIWrapper { 6 | 7 | public static void setAccelerometerActive(boolean active) { 8 | SimulationData.accelerometerEnabled = active; 9 | } 10 | 11 | public static void setAccelerometerRange(int range) { 12 | SimulationData.accelerometerRange = range; 13 | } 14 | 15 | public static double getAccelerometerX() { 16 | return SimulationData.accelerometer[0]; 17 | } 18 | 19 | public static double getAccelerometerY() { 20 | return SimulationData.accelerometer[1]; 21 | } 22 | 23 | public static double getAccelerometerZ() { 24 | return SimulationData.accelerometer[2]; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/UsageException.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command; 2 | 3 | /** 4 | * An exception for a Command to Throw if the usage of the command (the args) is not satisfactory. This will cause a console 5 | * log of the error. 6 | * 7 | * @author Jaci 8 | */ 9 | public class UsageException extends RuntimeException { 10 | 11 | String usage; 12 | 13 | public UsageException(String usage) { 14 | super(); 15 | this.usage = usage; 16 | } 17 | 18 | /** 19 | * Get the usage of the command related to the Exception 20 | */ 21 | public String getUsage() { 22 | return usage; 23 | } 24 | 25 | /** 26 | * Get the message of the exception used in logging. 27 | */ 28 | public String getMessage() { 29 | return "Invalid command usage. " + usage; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/FuzzyCommand.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command; 2 | 3 | /** 4 | * The base, abstract class for commands registered on the {@link jaci.openrio.toast.core.command.CommandBus}, but 5 | * do not follow the standard command type. For example, FuzzyCommands may search for a string in a message instead 6 | * of checking if it begins with the command name. 7 | * 8 | * @author Jaci 9 | */ 10 | public abstract class FuzzyCommand { 11 | 12 | /** 13 | * Should this Command be invoked with the given message? 14 | */ 15 | public abstract boolean shouldInvoke(String message); 16 | 17 | /** 18 | * Invokes the command if {@link #shouldInvoke} returns true. 19 | * @param message The full command message. This is left un-parsed so you can handle 20 | * it yourself 21 | */ 22 | public abstract void invokeCommand(String message); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/log/ColorPrint.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.log; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintStream; 5 | 6 | /** 7 | * An instance of a PrintStream that helps escape ANSI color control characters for a SplitStream. Color codes are just ignored for FileOutputs, 8 | * while on System.out they retain their color. This makes sure you don't get weird characters in your files. 9 | * 10 | * @author Jaci 11 | */ 12 | public class ColorPrint extends PrintStream { 13 | 14 | SplitStream spl; 15 | 16 | public ColorPrint(SplitStream out) { 17 | super(out); 18 | spl = out; 19 | } 20 | 21 | /** 22 | * Print a string. Escapes ANSI characters. 23 | */ 24 | public void print(String s) { 25 | try { 26 | spl.color(s); 27 | } catch (IOException e) { } 28 | } 29 | 30 | public static interface ColorStream {} 31 | 32 | } 33 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/DigitalGlitchFilterJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 4 | 5 | public class DigitalGlitchFilterJNI extends JNIWrapper { 6 | 7 | //TODO implement this into the DIOJNI 8 | 9 | public static void setFilterSelect(long digital_port_pointer, int filter_index) { 10 | SimulationData.glitchFilters[(int)digital_port_pointer] = filter_index; 11 | } 12 | 13 | public static int getFilterSelect(long digital_port_pointer) { 14 | return SimulationData.glitchFilters[(int) digital_port_pointer]; 15 | } 16 | 17 | public static void setFilterPeriod(int filter_index, int fpga_cycles) { 18 | SimulationData.filterDurations[filter_index] = fpga_cycles; 19 | } 20 | 21 | public static int getFilterPeriod(int filter_index) { 22 | return SimulationData.filterDurations[filter_index]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/crash/CrashInfoProvider.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.crash; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * An interface for classes that wish to add custom information to crash logs. 7 | * Registered in {@link jaci.openrio.toast.lib.crash.CrashHandler} 8 | * 9 | * @author Jaci 10 | */ 11 | public interface CrashInfoProvider { 12 | 13 | /** 14 | * The name of the provider 15 | */ 16 | public String getName(); 17 | 18 | /** 19 | * The same as {@link #getCrashInfo}, but is done before the crash is logged. 20 | * Keep in mind this data is not appended with {@link #getName} 21 | * 22 | * @param t The exception encountered 23 | */ 24 | public String getCrashInfoPre(Throwable t); 25 | 26 | /** 27 | * The information to append to the crash log 28 | * 29 | * @param t The exception encountered 30 | */ 31 | public List getCrashInfo(Throwable t); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/Assets.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib; 2 | 3 | import jaci.openrio.toast.lib.util.Pretty; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.InputStreamReader; 7 | 8 | /** 9 | * The helper class for fetching Assets inside of the classpath 10 | * 11 | * @author Jaci 12 | */ 13 | public class Assets { 14 | 15 | /** 16 | * Get an ASCII resource. This is used for getting the Splash Screen as well as the 'uh oh' screen when the Robot crashes. 17 | */ 18 | public static String getAscii(String name) { 19 | try(BufferedReader reader = new BufferedReader(new InputStreamReader(Assets.class.getResourceAsStream("/assets/toast/ascii/" + name + ".txt")))) { 20 | String ln; 21 | String total = ""; 22 | while ((ln = reader.readLine()) != null) { 23 | total += ln + "\n"; 24 | } 25 | return Pretty.format(total); 26 | } catch (Exception e) { 27 | return ""; 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /tools/inspector.rb: -------------------------------------------------------------------------------- 1 | # Reports information about FileSize and File Locations 2 | require 'json' 3 | require 'zlib' 4 | require 'base64' 5 | begin 6 | exported_libs = Dir["build/libs/Toast-*.jar"] 7 | @data = { :files => {} } 8 | exported_libs.each do |file_name| 9 | if file_name =~ /.*Toast-(.*)-raw.jar/ 10 | @data[:files][:raw] = file_name 11 | elsif file_name =~ /.*Toast-(.*)-sources.jar/ 12 | @data[:files][:sources] = file_name 13 | elsif file_name =~ /.*Toast-(.*).jar/ 14 | @data[:files][:jar] = file_name 15 | end 16 | end 17 | @data[:sizes] = @data[:files].map { |type, name| {type => File.size(name)} }.reduce(:merge) 18 | puts "-- METRICS --" 19 | puts Base64.encode64 Zlib::Deflate.deflate(File.read("tools/stats/metrics.json").split("\n").map {|x| x.gsub(/\s*/, "")}.join()) 20 | puts "-- END METRICS --" 21 | puts "-- INSPECTOR --" 22 | puts Base64.encode64 Zlib::Deflate.deflate(JSON.generate(@data)) 23 | puts "-- END INSPECTOR --" 24 | rescue => e 25 | puts "Could not Upload Metrics :c" 26 | raise e 27 | end 28 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/shared/ModuleEventListener.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.shared; 2 | 3 | /** 4 | * Implement this on classes you wish to act as listeners on the {@link jaci.openrio.toast.core.shared.ModuleEventBus} 5 | * 6 | * These classes are simple listeners for the events broadcast to all modules. This allows for optional dependencies 7 | * to trigger/listen for method invocations by other modules or Toast itself 8 | * 9 | * @author Jaci 10 | */ 11 | public interface ModuleEventListener { 12 | 13 | /** 14 | * Invoked when an event is broadcast to this listener 15 | * @param sender The sender of the event. This is usually the Name of a Module 16 | * @param event_type The type of event that was raised. These are unique. See module 17 | * documentation for more details 18 | * @param data The data passed with the event. Keep in mind this can be null if no data 19 | * was provided. See module documentation for more details 20 | */ 21 | public void onModuleEvent(String sender, String event_type, Object... data); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/thread/AsyncTask.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.thread; 2 | 3 | import java.util.concurrent.Future; 4 | 5 | /** 6 | * The default interface for AsyncTasks to be submitted to {@link Async}. This can be created anonymously or can 7 | * have a dedicated class if you so desire. 8 | * 9 | * @author Jaci 10 | */ 11 | public interface AsyncTask extends Runnable { 12 | 13 | /** 14 | * Called when the task is submitted to the queue. By default this is left blank 15 | */ 16 | default public void onAddedToQueue(Async pool, Future future) {} 17 | 18 | /** 19 | * Called when the task has been scheduled to run. Do not override this, instead use {@link #runTask()} 20 | */ 21 | default public void run() { 22 | runTask(); 23 | done(); 24 | }; 25 | 26 | /** 27 | * Called when the task has been scheduled to run. 28 | */ 29 | public void runTask(); 30 | 31 | /** 32 | * Called when the task has completed the {@link #runTask()} method. This is left blank by default. 33 | */ 34 | default public void done() {}; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/thread/HeartbeatListener.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.thread; 2 | 3 | /** 4 | * A listening interface for the {@link jaci.openrio.toast.core.thread.Heartbeat} service. Classes or Anonymous 5 | * Functions that implement this will be ticked on the Heartbeat every beat, assuming they are registered with 6 | * {@link jaci.openrio.toast.core.thread.Heartbeat#add} 7 | * 8 | * Functions inside of this interface should be Thread-Safe 9 | * 10 | * Also known as the 'Stethoscope' class 11 | * 12 | * @author Jaci 13 | */ 14 | public interface HeartbeatListener { 15 | 16 | /** 17 | * Called when the Heartbeat ticks 18 | * 19 | * @param skipped The number of skipped beats. If the Heartbeat takes too long 20 | * to execute, the Heartbeat will purposefully 'skip' a beat and 21 | * move on to the next one to ensure timing stays correct. This 22 | * parameter will give you the amount of skipped beats since the last 23 | * successful beat. 24 | */ 25 | public void onHeartbeat(int skipped); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 OpenRIO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/device/SimpleRelay.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.device; 2 | 3 | import edu.wpi.first.wpilibj.Relay; 4 | 5 | /** 6 | * A simple Relay wrapper class to set both Forward and Reverse simultaneously. 7 | */ 8 | public class SimpleRelay extends Relay { 9 | 10 | public SimpleRelay(int channel, Direction direction) { 11 | super(channel, direction); 12 | } 13 | 14 | public SimpleRelay(final int channel) { 15 | super(channel); 16 | } 17 | 18 | /** 19 | * Set the FWD and REV directions of the Relay independently 20 | */ 21 | public void set(boolean forward, boolean reverse) { 22 | if (forward && reverse) { 23 | setDirection(Direction.kBoth); 24 | set(Value.kOn); 25 | } else if (!forward && !reverse) { 26 | setDirection(Direction.kBoth); 27 | set(Value.kOff); 28 | } else if (forward) { 29 | setDirection(Direction.kBoth); 30 | set(Value.kForward); 31 | } else { 32 | setDirection(Direction.kBoth); 33 | set(Value.kReverse); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/states/StateInterfaces.java: -------------------------------------------------------------------------------- 1 | package toast.examples; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.lib.module.ToastModule; 5 | import jaci.openrio.toast.lib.state.RobotState; 6 | import jaci.openrio.toast.lib.state.StateListener; 7 | 8 | public class StateInterfaces extends ToastModule { 9 | 10 | @Override 11 | public String getModuleName() { 12 | return "State_Interfaces_Module"; 13 | } 14 | 15 | @Override 16 | public String getModuleVersion() { 17 | return "1.0.0"; // Recommended to follow the standard Toast Versioning System (major.minor.build-prebuild) 18 | } 19 | 20 | @Override 21 | public void prestart() { 22 | StateTracker.addTicker(new MyTickingClass()) // This can link to any class implementing StateListener.Ticker 23 | } 24 | 25 | @Override 26 | public void start() { 27 | 28 | } 29 | 30 | public static class MyTickingClass implements StateListener.Ticker { // This can be in a new file, but we keep it in the same file for organisation's sake 31 | @Override 32 | public void tickState(RobotState state) { 33 | Toast.log().info("Hello from my other ticking class!") 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /release/build.gradle: -------------------------------------------------------------------------------- 1 | /** 2 | This is the default build.gradle for Toast modules 3 | @author Jaci 4 | */ 5 | 6 | buildscript { 7 | repositories { 8 | mavenCentral() 9 | maven { 10 | name = "GradleRIO" 11 | url = "http://dev.imjac.in/maven" 12 | } 13 | } 14 | dependencies { 15 | classpath group: 'jaci.openrio.gradle', name: 'GradleRIO', version: '+', classifier: 'Toast' //Change this line if you wish to Update GradleRIO 16 | } 17 | } 18 | 19 | apply plugin: 'java' 20 | apply plugin: 'idea' 21 | apply plugin: 'eclipse' 22 | apply plugin: 'maven' 23 | apply plugin: 'GradleRIO' //Apply the GradleRIO plugin 24 | 25 | repositories { 26 | maven { 27 | name = "Toast" 28 | url = "http://dev.imjac.in/maven" 29 | } 30 | } 31 | 32 | gradlerio.team = "5333" //Your FRC team number (e.g. 5333 for team 'Can't C#', or 47 for Chief Delphi) 33 | //gradlerio.rioIP = "10.53.33.20" //Uncomment to specify the IP address of the RIO 34 | gradlerio.deployFile = "toast/modules/${archivesBaseName}" 35 | 36 | dependencies { 37 | compile group: 'jaci.openrio.toast', name: 'Toast', version: '+' //Change this line to update Toast 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/assets/toast/patches/patches.txt: -------------------------------------------------------------------------------- 1 | edu/wpi/first/wpilibj/hal/JNIWrapper.sim 2 | edu/wpi/first/wpilibj/RobotBase.sim 3 | edu/wpi/first/wpilibj/communication/FRCNetworkCommunicationsLibrary$tInstances.sim 4 | edu/wpi/first/wpilibj/communication/FRCNetworkCommunicationsLibrary$tModuleType.sim 5 | edu/wpi/first/wpilibj/communication/FRCNetworkCommunicationsLibrary$tResourceType.sim 6 | edu/wpi/first/wpilibj/communication/FRCNetworkCommunicationsLibrary$tTargetClass.sim 7 | edu/wpi/first/wpilibj/communication/FRCNetworkCommunicationsLibrary.sim 8 | edu/wpi/first/wpilibj/hal/AccelerometerJNI.sim 9 | edu/wpi/first/wpilibj/hal/AnalogJNI.sim 10 | edu/wpi/first/wpilibj/hal/DIOJNI.sim 11 | edu/wpi/first/wpilibj/hal/HALUtil.sim 12 | edu/wpi/first/wpilibj/hal/InterruptJNI$InterruptJNIHandlerFunction.sim 13 | edu/wpi/first/wpilibj/hal/InterruptJNI.sim 14 | edu/wpi/first/wpilibj/hal/PDPJNI.sim 15 | edu/wpi/first/wpilibj/hal/PowerJNI.sim 16 | edu/wpi/first/wpilibj/hal/PWMJNI.sim 17 | edu/wpi/first/wpilibj/hal/CompressorJNI.sim 18 | edu/wpi/first/wpilibj/hal/RelayJNI.sim 19 | edu/wpi/first/wpilibj/hal/SolenoidJNI.sim 20 | edu/wpi/first/wpilibj/hal/CanTalonJNI.sim 21 | edu/wpi/first/wpilibj/hal/DigitalGlitchFilterJNI.sim 22 | edu/wpi/first/wpilibj/hal/NotifierJNI.sim -------------------------------------------------------------------------------- /src/main/resources/assets/toast/script/js/Motor.js: -------------------------------------------------------------------------------- 1 | var _imports = {}; 2 | jimport("edu.wpi.first.wpilibj.SpeedController", "_imports['SpeedController']"); 3 | jimport("edu.wpi.first.wpilibj.RobotDrive", "_imports['RobotDrive']"); 4 | jimport("jaci.openrio.toast.lib.registry.Registrar", "_imports['Registrar']"); 5 | var _motor_types = {Talon: "talon", TalonSRX: "talonSRX", CANTalon: "canTalon", Victor: "victor", Jaguar: "jaguar", CANJaguar: "canJaguar", VictorSP: "victorSP", Spark: 'spark', SD540: 'sd540'}; 6 | 7 | $.drive = function() { 8 | if (arguments.length == 2) { 9 | return new _imports['RobotDrive'](arguments[0], arguments[1]); 10 | } else if (arguments.length == 4) { 11 | return new _imports['RobotDrive'](arguments[0], arguments[1], arguments[2], arguments[3]); 12 | } else throw new Error("Invalid arguments -- Expecting 2 || 4"); 13 | }; 14 | 15 | $.motor = function() { 16 | var type = "Talon"; 17 | var port = 0; 18 | if (arguments.length == 1) { 19 | port = arguments[0]; 20 | } else if (arguments.length == 2) { 21 | type = arguments[0]; 22 | port = arguments[1]; 23 | } else throw new Error("Invalid arguments -- Expecting 1..2"); 24 | return _imports['Registrar'][_motor_types[type]](port); 25 | }; -------------------------------------------------------------------------------- /examples/states/StateModule.java: -------------------------------------------------------------------------------- 1 | package toast.examples; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.lib.module.ToastStateModule; 5 | import jaci.openrio.toast.lib.state.RobotState; 6 | 7 | public class StateModule extends ToastStateModule { 8 | 9 | @Override 10 | public String getModuleName() { 11 | return "State_Toast_Module"; 12 | } 13 | 14 | @Override 15 | public String getModuleVersion() { 16 | return "1.0.0"; // Recommended to follow the standard Toast Versioning System (major.minor.build-prebuild) 17 | } 18 | 19 | @Override 20 | public void prestart() { 21 | } 22 | 23 | @Override 24 | public void start() { 25 | } 26 | 27 | @Override 28 | public void tickState(RobotState state) { 29 | Toast.log().info("Ticking Periodic: " + state) //Ticks every 20ms (or every control packet) with the 'state' {Autonomous, Teleoperated, Disabled, Test} 30 | if (state == RobotState.AUTONOMOUS) { 31 | // Your Autonomous Code 32 | } 33 | } 34 | 35 | @Override 36 | public void transitionState(RobotState state, RobotState oldState) { 37 | Toast.log().info("I went from " + state + " to " + oldState) //Called when we move from 1 state to another {Autonomous, Teleoperated, Disabled, Test} 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/AbstractCommand.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command; 2 | 3 | /** 4 | * The base, abstract class for Commands to be registered on the {@link jaci.openrio.toast.core.command.CommandBus} 5 | * 6 | * Commands are processed and invoked if they match. This allows for actions to be triggered on the Robot remotely 7 | * or locally 8 | * 9 | * @author Jaci 10 | */ 11 | public abstract class AbstractCommand { 12 | 13 | /** 14 | * Get the command name 15 | * e.g. 'cmd' for a command such as 'cmd 16 | */ 17 | public abstract String getCommandName(); 18 | 19 | /** 20 | * Returns the 'alias' for the command (other names) 21 | */ 22 | public String[] getAlias() {return null;} 23 | 24 | /** 25 | * Invoke the command if the name matches the one to be triggered 26 | * @param argLength The amount of arguments in the 'args' param 27 | * @param args The arguments the command was invoked with. This can be empty if 28 | * none were provided. Keep in mind this does NOT include the Command Name. 29 | * Args are separated by spaces 30 | * @param command The full command message 31 | */ 32 | public abstract void invokeCommand(int argLength, String[] args, String command); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/FRCHooks.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib; 2 | 3 | import edu.wpi.first.wpilibj.hal.HAL; 4 | 5 | /** 6 | * Common hooks to the FRC methods with ridiculously long method names. WPI pls. 7 | * 8 | * @author Jaci 9 | */ 10 | public class FRCHooks { 11 | 12 | /** 13 | * Called when the robot is ready to be enabled (pre-init phase complete) 14 | */ 15 | public static void robotReady() { 16 | HAL.observeUserProgramStarting(); 17 | } 18 | 19 | /** 20 | * Observe the input from the driver station for the 'disabled' mode 21 | */ 22 | public static void observeDisabled() { 23 | HAL.observeUserProgramDisabled(); 24 | } 25 | 26 | /** 27 | * Observe the input from the driver station for the 'test' mode 28 | */ 29 | public static void observeTest() { 30 | HAL.observeUserProgramTest(); 31 | } 32 | 33 | /** 34 | * Observe the input from the driver station for the 'teleop' mode 35 | */ 36 | public static void observeTeleop() { 37 | HAL.observeUserProgramTeleop(); 38 | } 39 | 40 | /** 41 | * Observe the input from the driver station for the 'autonomous' mode 42 | */ 43 | public static void observeAutonomous() { 44 | HAL.observeUserProgramAutonomous(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/math/MathHelper.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.math; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * A utility class to help with Math 7 | * 8 | * @author Jaci 9 | */ 10 | public class MathHelper { 11 | 12 | /** 13 | * Round a number (d) to the specified amount of decimal places (res) 14 | */ 15 | public static double round(double d, int res) { 16 | BigDecimal bd = new BigDecimal(d).setScale(res, BigDecimal.ROUND_HALF_UP); 17 | return bd.doubleValue(); 18 | } 19 | 20 | /** 21 | * Clamp an angle (in degrees) to 360, and transform negative angles into their positive counterparts. 22 | */ 23 | public static double clampAngle(double angle) { 24 | double newAngle = angle % 360; 25 | if (newAngle < 0) newAngle = 360 + newAngle; 26 | return newAngle; 27 | } 28 | 29 | public static double r2d(double angleInRads) { 30 | return angleInRads * 180 / Math.PI; 31 | } 32 | 33 | public static double d2r(double angleInDegrees) { 34 | return angleInDegrees * Math.PI / 180; 35 | } 36 | 37 | public static double radial(double angleInDegrees) { 38 | double radialMod = angleInDegrees % 360; 39 | if (radialMod < 0) { 40 | radialMod = radialMod + 360; 41 | } 42 | return radialMod; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/cmd/CommandExit.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command.cmd; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.command.AbstractCommand; 5 | 6 | /** 7 | * Simply exits Toast and stops the Simulation GUI 8 | * 9 | * @author Jaci 10 | */ 11 | public class CommandExit extends AbstractCommand { 12 | 13 | /** 14 | * Get the command name 15 | * e.g. 'cmd' for a command such as 'cmd 16 | */ 17 | @Override 18 | public String getCommandName() { 19 | return "exit"; 20 | } 21 | 22 | /** 23 | * Returns the 'alias' for the command (other names) 24 | */ 25 | public String[] getAlias() { 26 | return new String[] {"quit", ":q"}; 27 | } 28 | 29 | /** 30 | * Invoke the command if the name matches the one to be triggered 31 | * @param argLength The amount of arguments in the 'args' param 32 | * @param args The arguments the command was invoked with. This can be empty if 33 | * none were provided. Keep in mind this does NOT include the Command Name. 34 | * Args are separated by spaces 35 | * @param command The full command message 36 | */ 37 | @Override 38 | public void invokeCommand(int argLength, String[] args, String command) { 39 | Toast.getToast().shutdownSafely(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/RelayJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 4 | 5 | public class RelayJNI extends DIOJNI { 6 | public static int initializeRelayPort(int halPortHandle, boolean forward) { 7 | return halPortHandle * 2 + (forward ? 1 : 0); // Rvs = 0, 2, 4, 6 Fwd = 1, 3, 5, 7 8 | } 9 | 10 | public static void freeRelayPort(int relayPortHandle) { } 11 | 12 | public static boolean checkRelayChannel(int channel) { 13 | return true; 14 | } 15 | 16 | public static void setRelay(int relayPortHandle, boolean on) { 17 | int port = relayPortHandle; 18 | boolean fwd = false; 19 | if (port % 2 != 0) { 20 | port -= 1; 21 | fwd = true; 22 | } 23 | port /= 2; 24 | if (fwd) { 25 | SimulationData.relay_fwd[port] = on; 26 | } else { 27 | SimulationData.relay_rvs[port] = on; 28 | } 29 | } 30 | 31 | public static boolean getRelay(int relayPortHandle) { 32 | int port = relayPortHandle; 33 | boolean fwd = false; 34 | if (port % 2 != 0) { 35 | port -= 1; 36 | fwd = true; 37 | } 38 | port /= 2; 39 | return fwd ? SimulationData.relay_fwd[port] : SimulationData.relay_rvs[port]; 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/annotation/Priority.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * List a priority for a standard module method to be triggered in. This allows for you to predict when a method 10 | * will be executed instead of them being seemingly random per method. The default is NORMAL (0) 11 | * 12 | * @author Jaci 13 | */ 14 | @Target(ElementType.METHOD) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Priority { 17 | 18 | /** 19 | * The priority level to execute on. This can be any double value, MIN_VALUE being the lowest priority and MAX_VALUE 20 | * being the highest, with 0 being indifferent. The highest priority values will be executed First, and the lowest 21 | * executed last. 22 | */ 23 | double level(); 24 | 25 | public static class Level { 26 | public static final double LOWEST = -1; 27 | public static final double LOWER = -0.5; 28 | public static final double LOW = -0.25; 29 | public static final double NORMAL = 0; 30 | public static final double HIGH = 0.25; 31 | public static final double HIGHER = 0.5; 32 | public static final double HIGHEST = 1; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/state/StateListener.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.state; 2 | 3 | /** 4 | * A super-class for interfaces wanting to trigger methods when the robot ticks or transitions between states 5 | * 6 | * @author Jaci 7 | */ 8 | public interface StateListener { 9 | 10 | /** 11 | * An interface for classes wanting to trigger when the Robot 'ticks' a state, either when new data is available 12 | * or once every 20ms. 13 | */ 14 | public static interface Ticker { 15 | /** 16 | * Called when a state is 'ticked' (periodically called). This is called once every 20ms, or once every contol 17 | * packet, whichever comes first. 18 | */ 19 | public void tickState(RobotState state); 20 | } 21 | 22 | /** 23 | * An interface for classes wanting to trigger when the Robot 'transitions' between states 24 | */ 25 | public static interface Transition { 26 | /** 27 | * Called when a transition between 2 states occurs. This involves the robot migrating from a state (such as disabled) 28 | * to another state (such as autonomous). 29 | * @param state The new state the robot is in 30 | * @param oldState The state the robot was in before the transition (may be null) 31 | */ 32 | public void transitionState(RobotState state, RobotState oldState); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /examples/heartbeat/Heartbeat.java: -------------------------------------------------------------------------------- 1 | package toast.examples; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.thread.Heartbeat; 5 | import jaci.openrio.toast.core.thread.HeartbeatListener; 6 | import jaci.openrio.toast.lib.module.ToastModule; 7 | 8 | public class HeartbeatModule extends ToastModule { 9 | 10 | @Override 11 | public String getModuleName() { 12 | return "Heartbeat_Toast_Module"; 13 | } 14 | 15 | @Override 16 | public String getModuleVersion() { 17 | return "1.0.0"; // Recommended to follow the standard Toast Versioning System (major.minor.build-prebuild) 18 | } 19 | 20 | @Override 21 | public void prestart() { 22 | } 23 | 24 | @Override 25 | public void start() { 26 | Heartbeat.add(new HeartbeatListener() { // Adds a listener to the Heartbeat 27 | @Override 28 | public void onHeartbeat(int skipped) { 29 | Toast.log().info("Duh-Dunk, Duh-Dunk"); 30 | } 31 | }); 32 | 33 | Heartbeat.add(new MyOtherClass()); // You can also do this for classes implementing 'Heartbeat Listener; 34 | } 35 | 36 | public static class MyOtherClass implements HeartbeatListener { 37 | 38 | @Override 39 | public void onHeartbeat(int skipped) { 40 | Toast.log().info("Other Duh-Dunk, other Duh-Dunk"); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/script/js/proxy/FileProxy.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.script.js.proxy; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | 8 | /** 9 | * A proxy class for the {@link java.io.File} class into JavaScript. This provides methods relating to reading and writing 10 | * to the file without creating a new reader/writer instance. 11 | * 12 | * @author Jaci 13 | */ 14 | public class FileProxy extends File { 15 | 16 | /** 17 | * Create a new FileProxy object, with the given Filename. 18 | */ 19 | public FileProxy(String pathname) { 20 | super(pathname); 21 | } 22 | 23 | /** 24 | * Call the callback with the writer object as an argument 25 | */ 26 | public void withWriter(Object cb) { } 27 | 28 | /** 29 | * Call the callback with the reader object as an argument 30 | */ 31 | public void withReader(Object cb) { } 32 | 33 | /** 34 | * Read the file fully and return the contents. 35 | */ 36 | public String readFully() { return ""; } 37 | 38 | /** 39 | * Read the file fully and return the contents as a byte array. 40 | */ 41 | public byte[] readBytes() { 42 | try { 43 | return Files.readAllBytes(Paths.get(this.toString())); 44 | } catch (IOException e) { } 45 | return new byte[] {}; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/crash/CrashInfoEnvironment.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.crash; 2 | 3 | import jaci.openrio.toast.core.Environment; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * A CrashInfoProvider that contains information about the Environment. This includes things like 9 | * Toast Version, OS Version/Arch, Environment Type (sim, verification, robot), Java details and 10 | * FMS connectivity. 11 | * 12 | * @author Jaci 13 | */ 14 | public class CrashInfoEnvironment implements CrashInfoProvider { 15 | 16 | /** 17 | * The name of the provider 18 | */ 19 | @Override 20 | public String getName() { 21 | return "Environment"; 22 | } 23 | 24 | /** 25 | * The same as {@link #getCrashInfo}, but is done before the crash is logged. 26 | * Keep in mind this data is not appended with {@link #getName} 27 | * 28 | * @param t The exception encountered 29 | */ 30 | @Override 31 | public String getCrashInfoPre(Throwable t) { 32 | return null; 33 | } 34 | 35 | /** 36 | * The information to append to the crash log 37 | * 38 | * In this case, the information includes data gathered from the {@link jaci.openrio.toast.core.Environment} class 39 | * 40 | * @param t The exception encountered 41 | */ 42 | @Override 43 | public List getCrashInfo(Throwable t) { 44 | return Environment.toLines(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /doc/manuals/NETWORK.MD: -------------------------------------------------------------------------------- 1 | # Network Delegate Bindings 2 | A list of the default Network Delegates made available by Toast for you to connect to. 3 | 4 | ## Delegates 5 | 6 | ### Logger 7 | 8 | **DelegateID:** TOAST_logger 9 | **Connection:** One Way (Send to Client) 10 | **Password:** Optional (Set in Toast config) 11 | 12 | The Logger Delegate will simply accept connections from any client that wishes to connect. Upon connection, the Logger Delegate will echo the entire backlog of the Console Output from the robot. Additionally, any further logging messages sent from the 'Logger' class will also be broadcast to any connected clients. This functions as a remote console for the logging output of Toast and it's modules. 13 | 14 | ### Command Bus 15 | 16 | **DelegateID:** TOAST_command 17 | **Connection:** One Way (Receive from Client) 18 | **Password:** Optional (Set in Toast config) 19 | 20 | The Command Delegate will simply accept connections from any client that wishes to connect. The Command Delegate will listen for incoming messages from clients and will interpret the message as a Command to be sent to the command bus. The incoming message must create a new line per command. The new line must follow the '\\n' standard (not '\\r\\n'). Commands will not be interpreted if they do not end in a new line. The command response will not be sent back to the client, but instead will be sent to the [Logger Delegate](#del_logger) 21 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/PDPJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 4 | 5 | public class PDPJNI extends JNIWrapper { 6 | 7 | // Yes, these all link to a single index in SimulationData. No team in their right mind would attach 8 | // multiple Power Distribution Panels to their Robot. Is that even allowed? 9 | 10 | public static void initializePDP(int module) { } 11 | 12 | public static boolean checkPDPModule(int module) { return true; } 13 | 14 | public static boolean checkPDPChannel(int channel) { return true; } 15 | 16 | public static double getPDPTemperature(int module) { 17 | return SimulationData.pdpTemperature; 18 | } 19 | 20 | public static double getPDPVoltage(int module) { 21 | return SimulationData.pdpVoltage; 22 | } 23 | 24 | public static double getPDPChannelCurrent(byte channel, int module) { 25 | return SimulationData.pdpChannelCurrent[channel]; 26 | } 27 | 28 | public static double getPDPTotalCurrent(int module) { 29 | double total = 0D; 30 | for (double d : SimulationData.pdpChannelCurrent) 31 | total += d; 32 | return total; 33 | } 34 | 35 | public static double getPDPTotalPower(int module) { 36 | return 0; 37 | } 38 | 39 | public static double getPDPTotalEnergy(int module) { 40 | return 0; 41 | } 42 | 43 | public static void resetPDPTotalEnergy(int module) { } 44 | 45 | public static void clearPDPStickyFaults(int module) { } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/NotifierJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import edu.wpi.first.wpilibj.Utility; 4 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 5 | 6 | public class NotifierJNI extends JNIWrapper { 7 | 8 | public interface NotifierJNIHandlerFunction { 9 | void apply(long curTime); 10 | } 11 | 12 | public static long initializeNotifier(NotifierJNI.NotifierJNIHandlerFunction func) { 13 | for (int i = 0; i < 10; i++) { 14 | if (SimulationData.notifiers[i] == null) { 15 | SimulationData.notifiers[i] = func; 16 | SimulationData.notifierTriggerTimes[i] = -1; 17 | return i; 18 | } 19 | } 20 | return 0; 21 | } 22 | 23 | public static void cleanNotifier(long notifierPtr) { 24 | SimulationData.notifiers[(int)notifierPtr] = null; 25 | SimulationData.notifierTriggerTimes[(int)notifierPtr] = -1; 26 | } 27 | 28 | public static void updateNotifierAlarm(long notifierPtr, long triggerTime) { 29 | SimulationData.notifierTriggerTimes[(int)notifierPtr] = triggerTime / 1000; // Why microseconds? It's such an awkward unit of measurement 30 | SimulationData.notifierUpdate(); 31 | } 32 | 33 | public static void stopNotifierAlarm(long notifierPtr) { 34 | SimulationData.notifiers[(int)notifierPtr] = null; 35 | SimulationData.notifierTriggerTimes[(int)notifierPtr] = -1; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/HALUtil.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.ToastBootstrap; 4 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 5 | 6 | public class HALUtil extends JNIWrapper { 7 | public static final int NULL_PARAMETER = -1005; 8 | public static final int SAMPLE_RATE_TOO_HIGH = 1001; 9 | public static final int VOLTAGE_OUT_OF_RANGE = 1002; 10 | public static final int LOOP_TIMING_ERROR = 1004; 11 | public static final int INCOMPATIBLE_STATE = 1015; 12 | public static final int ANALOG_TRIGGER_PULSE_OUTPUT_ERROR = -1011; 13 | public static final int NO_AVAILABLE_RESOURCES = -104; 14 | public static final int PARAMETER_OUT_OF_RANGE = -1028; 15 | 16 | public static short getFPGAVersion() { 17 | return 2009; 18 | } 19 | 20 | public static int getFPGARevision() { 21 | return 0; 22 | } 23 | 24 | public static long getFPGATime() { 25 | return (System.nanoTime() - ToastBootstrap.startTimeNS) / 1000; 26 | } 27 | 28 | public static int getHALRuntimeType() { 29 | return 0; 30 | } 31 | 32 | public static boolean getFPGAButton() { 33 | return SimulationData.userButtonPressed; 34 | } 35 | 36 | public static String getHALErrorMessage(int code) { 37 | return ""; 38 | } 39 | 40 | public static int getHALErrno() { 41 | return 0; 42 | } 43 | 44 | public static String getHALstrerror(int errno) { 45 | return ""; 46 | } 47 | 48 | public static String getHALstrerror() { 49 | return getHALstrerror(getHALErrno()); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/threads/ThreadPoolWorker.java: -------------------------------------------------------------------------------- 1 | package toast.examples; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.thread.Async; 5 | import jaci.openrio.toast.lib.module.ToastModule; 6 | 7 | import java.util.concurrent.Callable; 8 | import java.util.concurrent.Future; 9 | 10 | public class ThreadWorker extends ToastModule { 11 | @Override 12 | public String getModuleName() { 13 | return "Heartbeat_Worker"; 14 | } 15 | 16 | @Override 17 | public String getModuleVersion() { 18 | return "1.0.0"; // Recommended to follow the standard Toast Versioning System (major.minor.build-prebuild) 19 | } 20 | 21 | @Override 22 | public void prestart() { 23 | 24 | } 25 | 26 | @Override 27 | public void start() { 28 | Async.INSTANCE.addWorker(new Runnable() { // Add a new, void return type method to the Thread Pool 29 | @Override 30 | public void run() { 31 | Toast.log().info("Hello from the threadpool!"); 32 | } 33 | }); 34 | 35 | Future future = Async.INSTANCE.addWorker(new Callable() { // Add a new, non-void return type method to the Thread Pool 36 | @Override 37 | public Integer call() throws Exception { 38 | return 5 * 2; 39 | } 40 | }); 41 | 42 | Toast.log().info("Thread complete! Result: " + future.get()); // => 10 (blocks/waits until result is complete) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/crash/CrashInfoToast.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.crash; 2 | 3 | import jaci.openrio.toast.core.loader.module.ModuleContainer; 4 | import jaci.openrio.toast.core.loader.module.ModuleManager; 5 | import jaci.openrio.toast.lib.Version; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * A CrashInfoProvider that gives data about Toast and modules loaded. 12 | * 13 | * @link Jaci 14 | */ 15 | public class CrashInfoToast implements CrashInfoProvider { 16 | 17 | /** 18 | * The name of the provider 19 | */ 20 | @Override 21 | public String getName() { 22 | return "Toast"; 23 | } 24 | 25 | /** 26 | * The same as {@link #getCrashInfo}, but is done before the crash is logged. 27 | * Keep in mind this data is not appended with {@link #getName} 28 | * 29 | * @param t The exception encountered 30 | */ 31 | @Override 32 | public String getCrashInfoPre(Throwable t) { 33 | return null; 34 | } 35 | 36 | /** 37 | * The information to append to the crash log 38 | * 39 | * @param t The exception encountered 40 | */ 41 | @Override 42 | public List getCrashInfo(Throwable t) { 43 | ArrayList list = new ArrayList<>(); 44 | list.add("Toast Version: " + Version.version().get()); 45 | list.add("Loaded Modules:"); 46 | for (ModuleContainer module : ModuleManager.getContainers()) 47 | list.add("\t" + module.getDetails()); 48 | 49 | return list; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/basic/DrivingModule.java: -------------------------------------------------------------------------------- 1 | package toast.examples; 2 | 3 | import edu.wpi.first.wpilibj.GenericHID; 4 | import edu.wpi.first.wpilibj.Joystick; 5 | import edu.wpi.first.wpilibj.RobotDrive; 6 | import jaci.openrio.toast.lib.module.ToastStateModule; 7 | import jaci.openrio.toast.lib.state.RobotState; 8 | 9 | public class DrivingModule extends ToastStateModule { 10 | 11 | static RobotDrive robot_drive; 12 | static Joystick joystick; 13 | 14 | @Override 15 | public String getModuleName() { 16 | return "Driving_Toast_Module"; 17 | } 18 | 19 | @Override 20 | public String getModuleVersion() { 21 | return "1.0.0"; // Recommended to follow the standard Toast Versioning System (major.minor.build-prebuild) 22 | } 23 | 24 | @Override 25 | public void prestart() { 26 | robot_drive = new RobotDrive(0, 1, 2, 3); // You can replace these channels for anything you want, or even your own motor controller 27 | joystick = new Joystick(0); 28 | } 29 | 30 | @Override 31 | public void start() { } 32 | 33 | @Override 34 | public void tickState(RobotState state) { 35 | if (state == RobotState.TELEOP) { 36 | robot_drive.tankDrive(joystick.getZ(GenericHID.Hand.kLeft), joystick.getZ(GenericHID.Hand.kRight)); // Drives the robot using the left and right triggers 37 | } else if (state == RobotState.AUTONOMOUS) 38 | robot_drive.stopMotor(); // Feed the WatchDog 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LICENSE_WPI_BSD: -------------------------------------------------------------------------------- 1 | * Copyright (c) 2009 FIRST 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of the FIRST nor the 12 | * names of its contributors may be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY FIRST AND CONTRIBUTORS``AS IS'' AND ANY 16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR 18 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR 19 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/PortsJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | public class PortsJNI extends JNIWrapper { 4 | public static int getNumAccumulators() { return 0; } // Unused 5 | 6 | public static int getNumAnalogTriggers() { return 0; } // Unused 7 | 8 | public static int getNumAnalogInputs() { return 8; } // 4 Onboard, 4 MXP 9 | 10 | public static int getNumAnalogOutputs() { return 2; } // 2 MXP 11 | 12 | public static int getNumCounters() { return 0; } // Unused 13 | 14 | public static int getNumDigitalHeaders() { return 0; } // Unused 15 | 16 | public static int getNumPWMHeaders() { return 0; } // Unused 17 | 18 | public static int getNumDigitalChannels() { return 26; } // 10 Onboard, 16 MXP 19 | 20 | public static int getNumPWMChannels() { return 20; } // 10 Onboard, 10 MXP 21 | 22 | public static int getNumDigitalPWMOutputs() { return 0; } // Unused 23 | 24 | public static int getNumEncoders() { return 0; } // Unused 25 | 26 | public static int getNumInterrupts() { return 0; } // Unused 27 | 28 | public static int getNumRelayChannels() { return 0; } // Unused 29 | 30 | public static int getNumRelayHeaders() { return 4; } // 4 Onboard 31 | 32 | public static int getNumPCMModules() { return 1; } // 1 (??) PCM 33 | 34 | public static int getNumSolenoidChannels() { return 8; } // 8 Solenoids for PCM 35 | 36 | public static int getNumPDPModules() { return 1; } // 1 PDP 37 | 38 | public static int getNumPDPChannels() { return 16; } // 16 Motor Channels 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/module/ToastStateModule.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.module; 2 | 3 | import jaci.openrio.toast.core.StateTracker; 4 | import jaci.openrio.toast.core.loader.annotation.NoLoad; 5 | import jaci.openrio.toast.lib.state.RobotState; 6 | import jaci.openrio.toast.lib.state.StateListener; 7 | 8 | /** 9 | * An implementation of {@link jaci.openrio.toast.lib.module.ToastModule} that includes StateListeners for both 10 | * Ticking and Transitioning. Implement this if you're used to {@link edu.wpi.first.wpilibj.IterativeRobot} 11 | * 12 | * @see jaci.openrio.toast.lib.state.StateListener 13 | * @see jaci.openrio.toast.core.StateTracker 14 | * 15 | * @author Jaci 16 | */ 17 | @NoLoad 18 | public abstract class ToastStateModule extends ToastModule implements StateListener.Ticker, StateListener.Transition { 19 | 20 | /** 21 | * Called when this Module has been discovered and constructed. This method isn't usually used for much, but 22 | * can be useful for triggering things before the robot is in Pre-Initialization. 23 | */ 24 | public void onConstruct() { 25 | StateTracker.addTicker(this); 26 | StateTracker.addTransition(this); 27 | } 28 | 29 | /** 30 | * Called when a transition between 2 states occurs. This involves the robot migrating from a state (such as disabled) 31 | * to another state (such as autonomous). 32 | * @param state The new state the robot is in 33 | * @param oldState The state the robot was in before the transition (may be null) 34 | */ 35 | public void transitionState(RobotState state, RobotState oldState) {} 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/cmd/CommandInvokeCrash.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command.cmd; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.command.AbstractCommand; 5 | import jaci.openrio.toast.core.command.IHelpable; 6 | import jaci.openrio.toast.lib.crash.CrashHandler; 7 | 8 | /** 9 | * Invokes a Debug Crash. Useful for testing things like custom Crash Handlers 10 | * 11 | * @author Jaci 12 | */ 13 | public class CommandInvokeCrash extends AbstractCommand implements IHelpable { 14 | 15 | /** 16 | * Get the command name 17 | * e.g. 'cmd' for a command such as 'cmd 18 | */ 19 | @Override 20 | public String getCommandName() { 21 | return "crash"; 22 | } 23 | 24 | /** 25 | * Invoke the command if the name matches the one to be triggered 26 | * @param argLength The amount of arguments in the 'args' param 27 | * @param args The arguments the command was invoked with. This can be empty if 28 | * none were provided. Keep in mind this does NOT include the Command Name. 29 | * Args are separated by spaces 30 | * @param command The full command message 31 | */ 32 | @Override 33 | public void invokeCommand(int argLength, String[] args, String command) { 34 | Toast.log().error("Goodbye cruel world!"); 35 | CrashHandler.handle(new Exception("Invoked Debug Crash")); 36 | } 37 | 38 | /** 39 | * Returns a help message to display with the 'help' command 40 | */ 41 | @Override 42 | public String getHelp() { 43 | return "Invokes a debugging crash"; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/SolenoidJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 4 | 5 | public class SolenoidJNI extends JNIWrapper { 6 | 7 | public static int initializeSolenoidPort(int halPortHandle) { 8 | return halPortHandle; 9 | } 10 | 11 | public static boolean checkSolenoidModule(int module) { 12 | return true; 13 | } 14 | 15 | public static boolean checkSolenoidChannel(int channel) { 16 | return true; 17 | } 18 | 19 | public static void freeSolenoidPort(int portHandle) { } 20 | 21 | public static void setSolenoid(int portHandle, boolean on) { 22 | byte[] pm = getPortAndModuleFromHandle(portHandle); 23 | SimulationData.setSolenoid(pm[0], pm[1], on); 24 | } 25 | 26 | public static boolean getSolenoid(int portHandle) { 27 | byte[] pm = getPortAndModuleFromHandle(portHandle); 28 | return SimulationData.solenoids[pm[0]][pm[1]]; 29 | } 30 | 31 | public static byte getAllSolenoids(byte module) { 32 | byte data = 0; 33 | for (int i = 0; i < 8; i++) 34 | if (SimulationData.solenoids[module][i]) data |= 1 << i; 35 | return data; 36 | } 37 | 38 | public static int getPCMSolenoidBlackList(byte module) { 39 | return 0; 40 | } 41 | 42 | public static boolean getPCMSolenoidVoltageStickyFault(byte module) { 43 | return false; 44 | } 45 | 46 | public static boolean getPCMSolenoidVoltageFault(byte module) { 47 | return false; 48 | } 49 | 50 | public static void clearAllPCMStickyFaults(byte module) { } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/CommonGUI.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation; 2 | 3 | import javax.swing.*; 4 | import java.awt.event.ActionEvent; 5 | 6 | /** 7 | * Sets up operations that are common throughout all Simulation GUIs 8 | * 9 | * @author Jaci 10 | */ 11 | public class CommonGUI { 12 | 13 | /** 14 | * Setup keyboard shortcuts for the panel 15 | */ 16 | public static void setup_keys(JPanel panel, Runnable reinit) { 17 | panel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ctrl R"), "repaint"); 18 | panel.getActionMap().put("repaint", new AbstractAction() { 19 | @Override 20 | public void actionPerformed(ActionEvent e) { 21 | panel.repaint(); 22 | } 23 | }); 24 | 25 | panel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ctrl shift R"), "reinit"); 26 | panel.getActionMap().put("reinit", new AbstractAction() { 27 | @Override 28 | public void actionPerformed(ActionEvent e) { 29 | reinit.run(); 30 | panel.repaint(); 31 | } 32 | }); 33 | } 34 | 35 | /** 36 | * Add a key command to the GUI 37 | */ 38 | public static void registerKeyCommand(JPanel panel, String keyset, Runnable run) { 39 | panel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(keyset), keyset); 40 | panel.getActionMap().put(keyset, new AbstractAction() { 41 | @Override 42 | public void actionPerformed(ActionEvent e) { 43 | run.run(); 44 | } 45 | }); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/module/ModuleManager.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.module; 2 | 3 | import java.util.List; 4 | import java.util.Vector; 5 | 6 | /** 7 | * The ModuleManager is a static class that stores the loaded {@link ModuleCandidate} and 8 | * {@link ModuleContainer} for use later. These can be accessed by any module and by Toast 9 | * itself. 10 | * 11 | * @author Jaci 12 | */ 13 | public class ModuleManager { 14 | 15 | static Vector candidates = new Vector(); 16 | static Vector containers = new Vector(); 17 | 18 | /** 19 | * Get a list of loaded {@link ModuleCandidate} 20 | */ 21 | public static List getCandidates() { 22 | return candidates; 23 | } 24 | 25 | /** 26 | * Get a list of loaded {@link ModuleContainer} 27 | */ 28 | public static List getContainers() { 29 | return containers; 30 | } 31 | 32 | /** 33 | * Returns a {@link ModuleContainer} matching the given name, or null if it is not found 34 | */ 35 | public static ModuleContainer getContainerForName(String name) { 36 | for (ModuleContainer container : getContainers()) 37 | if (container.getName() != null && container.getName().equalsIgnoreCase(name)) 38 | return container; 39 | return null; 40 | } 41 | 42 | /** 43 | * Returns whether or not a module with the given name exists (a != null check on {@link #getContainerForName} 44 | */ 45 | public static boolean moduleExists(String name) { 46 | return getContainerForName(name) != null; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/DIOJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 4 | 5 | import java.nio.IntBuffer; 6 | 7 | public class DIOJNI extends JNIWrapper { 8 | 9 | public static int initializeDigitalPort(int port_pointer, boolean input) { 10 | SimulationData.setDIODir((byte)port_pointer, input); 11 | return port_pointer; 12 | } 13 | 14 | public static boolean checkDIOChannel(int channel) { 15 | return true; 16 | } 17 | 18 | public static void freeDIO(int dioPortHandle) { } 19 | 20 | public static void setDIO(int digital_port_pointer, short value) { 21 | SimulationData.setDIO((byte)digital_port_pointer, (byte)value); 22 | } 23 | 24 | public static boolean getDIO(int digital_port_pointer) { 25 | return SimulationData.dioValues[digital_port_pointer] == 1; 26 | } 27 | 28 | public static boolean getDIODirection(int digital_port_pointer, IntBuffer status) { 29 | return SimulationData.dioDirections[digital_port_pointer] == 1; 30 | } 31 | 32 | public static void pulse(int dioPortHandle, double pulseLength) { 33 | } 34 | 35 | public static boolean isPulsing(int dioPortHandle) { 36 | return false; 37 | } 38 | 39 | public static boolean isAnyPulsing() { 40 | return false; 41 | } 42 | 43 | public static short getLoopTiming() { 44 | return 80; 45 | } 46 | 47 | public static int allocateDigitalPWM() { return 0; } 48 | 49 | public static void freeDigitalPWM(int pwmGenerator) { } 50 | 51 | public static void setDigitalPWMRate(double rate) { } 52 | 53 | public static void setDigitalPWMDutyCycle(int pwmGenerator, double dutyCycle) { } 54 | 55 | public static void setDigitalPWMOutputChannel(int pwmGenerator, int channel) { } 56 | } 57 | -------------------------------------------------------------------------------- /examples/network/EchoDelegate.java: -------------------------------------------------------------------------------- 1 | package toast.examples; 2 | 3 | import jaci.openrio.delegate.BoundDelegate; 4 | import jaci.openrio.delegate.Security; 5 | import jaci.openrio.toast.core.network.SocketManager; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.DataOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStreamReader; 11 | import java.net.Socket; 12 | 13 | public class EchoDelegate implements BoundDelegate.ConnectionCallback { 14 | 15 | BoundDelegate delegate_instance; 16 | 17 | public void register() { // This would be called from your Main module class 18 | delegate_instance = SocketManager.register("MyEchoDelegate"); 19 | delegate_instance.callback(this); 20 | delegate_instance.setPassword("hunter2", Security.HashType.SHA1); 21 | } 22 | 23 | @Override 24 | public void onClientConnect(Socket clientSocket, BoundDelegate delegate) { // This is called when a client is connected, has entered the correct password (if one exists) and is on the right port 25 | Thread echoThread = new Thread(new Runnable() { 26 | @Override 27 | public void run() { // Just echos what the client said 28 | try { 29 | BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 30 | DataOutputStream output = new DataOutputStream(clientSocket.getOutputStream()); 31 | 32 | while (true) { 33 | String line = reader.readLine(); 34 | output.writeBytes(line); 35 | } 36 | } catch (IOException e) { } 37 | } 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/GuiScrollbar.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation; 2 | 3 | import javax.swing.*; 4 | import javax.swing.plaf.basic.BasicScrollBarUI; 5 | import java.awt.*; 6 | 7 | /** 8 | * Custom Scroll Bar GUI Painter 9 | */ 10 | public class GuiScrollbar extends BasicScrollBarUI { 11 | 12 | static Color color = new Color(30, 30, 30); 13 | static Color bg = new Color(11, 11, 11); 14 | 15 | @Override 16 | protected JButton createDecreaseButton(int orientation) { 17 | JButton button = new JButton(); 18 | button.setPreferredSize(new Dimension()); 19 | return button; 20 | } 21 | 22 | @Override 23 | protected JButton createIncreaseButton(int orientation) { 24 | JButton button = new JButton(); 25 | button.setPreferredSize(new Dimension()); 26 | return button; 27 | } 28 | 29 | @Override 30 | protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) { } 31 | 32 | @Override 33 | protected void paintThumb(Graphics g, JComponent c, Rectangle r) { 34 | Graphics2D g2 = (Graphics2D)g.create(); 35 | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 36 | RenderingHints.VALUE_ANTIALIAS_ON); 37 | JScrollBar sb = (JScrollBar)c; 38 | c.setBackground(bg); 39 | if(!sb.isEnabled() || r.width>r.height) { 40 | return; 41 | } 42 | g2.setPaint(color); 43 | g2.fillRoundRect(r.x-1,r.y,r.width,r.height,10,10); 44 | g2.dispose(); 45 | } 46 | 47 | @Override 48 | protected void setThumbBounds(int x, int y, int width, int height) { 49 | super.setThumbBounds(x, y, width, height); 50 | scrollbar.repaint(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/PowerJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 4 | 5 | public class PowerJNI extends JNIWrapper { 6 | 7 | public static double getVinVoltage() { 8 | return (double) SimulationData.powerVinVoltage; 9 | } 10 | 11 | public static double getVinCurrent() { 12 | return (double) SimulationData.powerVinCurrent; 13 | } 14 | 15 | public static double getUserVoltage6V() { 16 | return (double) SimulationData.powerUserVoltage6V; 17 | } 18 | 19 | public static double getUserCurrent6V() { 20 | return (double) SimulationData.powerUserCurrent6V; 21 | } 22 | 23 | public static boolean getUserActive6V() { 24 | return SimulationData.powerUserActive6V; 25 | } 26 | 27 | public static int getUserCurrentFaults6V() { 28 | return SimulationData.powerUserFaults6V; 29 | } 30 | 31 | public static double getUserVoltage5V() { 32 | return (double) SimulationData.powerUserVoltage5V; 33 | } 34 | 35 | public static double getUserCurrent5V() { 36 | return (double) SimulationData.powerUserCurrent5V; 37 | } 38 | 39 | public static boolean getUserActive5V() { 40 | return SimulationData.powerUserActive5V; 41 | } 42 | 43 | public static int getUserCurrentFaults5V() { 44 | return SimulationData.powerUserFaults5V; 45 | } 46 | 47 | public static double getUserVoltage3V3() { 48 | return (double) SimulationData.powerUserVoltage3V3; 49 | } 50 | 51 | public static double getUserCurrent3V3() { 52 | return (double) SimulationData.powerUserCurrent3V3; 53 | } 54 | 55 | public static boolean getUserActive3V3() { 56 | return SimulationData.powerUserActive3V3; 57 | } 58 | 59 | public static int getUserCurrentFaults3V3() { 60 | return SimulationData.powerUserFaults3V3; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/cmd/CommandReloadConfigs.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command.cmd; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.command.AbstractCommand; 5 | import jaci.openrio.toast.core.command.IHelpable; 6 | import jaci.openrio.toast.lib.module.ModuleConfig; 7 | 8 | /** 9 | * The Command to reload all configuration files. This will re-read all the configs from file. 10 | * 11 | * @author Jaci 12 | */ 13 | public class CommandReloadConfigs extends AbstractCommand implements IHelpable { 14 | 15 | /** 16 | * Get the command name 17 | * e.g. 'cmd' for a command such as 'cmd 18 | */ 19 | @Override 20 | public String getCommandName() { 21 | return "reloadcfg"; 22 | } 23 | 24 | /** 25 | * Returns a help message to display with the 'help' command 26 | */ 27 | @Override 28 | public String getHelp() { 29 | return "Reload all ModuleConfig files"; 30 | } 31 | 32 | /** 33 | * Invoke the command if the name matches the one to be triggered 34 | * @param argLength The amount of arguments in the 'args' param 35 | * @param args The arguments the command was invoked with. This can be empty if 36 | * none were provided. Keep in mind this does NOT include the Command Name. 37 | * Args are separated by spaces 38 | * @param command The full command message 39 | */ 40 | @Override 41 | public void invokeCommand(int argLength, String[] args, String command) { 42 | int cnt = 0; 43 | for (ModuleConfig config : ModuleConfig.allConfigs) { 44 | config.reload(); 45 | cnt++; 46 | } 47 | Toast.log().info("All ModuleConfigs reloaded (" + cnt + " reloaded)"); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /vers: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | first_arg = ARGV.shift 3 | 4 | VERSION_MATCH = /^(\d+)\.(\d+)\.(\d+)(-(\d+)([a-z]))?$/ 5 | VERSION_ENTRY = /(toast.version=)(.*)/ 6 | 7 | SETTINGS_FILE = 'build.settings' 8 | 9 | def like a, target 10 | (a =~ target) != nil 11 | end 12 | 13 | def vers_match 14 | File.read(SETTINGS_FILE).match(VERSION_ENTRY) 15 | end 16 | 17 | def replace_version vers 18 | unless like vers, VERSION_MATCH 19 | puts "Not a valid version string!" 20 | exit 1 21 | end 22 | content = File.read(SETTINGS_FILE) 23 | content = content.gsub VERSION_ENTRY, "\\1#{vers}" 24 | File.write(SETTINGS_FILE, content) 25 | end 26 | 27 | if like first_arg, /^version$/ 28 | version = vers_match 29 | puts "Current Version: #{version[2]}" 30 | print "New Version? " 31 | newvers = gets.chop! 32 | replace_version newvers 33 | end 34 | 35 | if like first_arg, /^(in|de)c(rement)?$/ 36 | second_arg = ARGV.shift 37 | version = vers_match 38 | puts "Current Version: \t#{version[2]}" 39 | match = version[2].match(VERSION_MATCH) 40 | 41 | mod = like(first_arg, /inc/) ? 1 : -1 42 | 43 | newv = [match[1].to_i, match[2].to_i, match[3].to_i, match[5].to_i, match[6].ord] 44 | if like second_arg, /^maj/ 45 | newv[0] += mod 46 | elsif like second_arg, /^min/ 47 | newv[1] += mod 48 | elsif like second_arg, /^build/ 49 | newv[2] += mod 50 | elsif like second_arg, /^pre/ 51 | newv[4] += mod 52 | if mod == 1 53 | if newv[4] > "z".ord 54 | newv[4] = "a".ord 55 | newv[3] += 1 56 | end 57 | else 58 | if newv[4] < "a".ord 59 | newv[4] = "z".ord 60 | newv[3] -= 1 61 | end 62 | end 63 | end 64 | newv = "#{newv[0]}.#{newv[1]}.#{newv[2]}-#{newv[3]}#{newv[4].chr}" 65 | puts "New Version: \t\t#{newv}" 66 | replace_version newv 67 | end 68 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/GuiProgress.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | 6 | public class GuiProgress extends JComponent { 7 | 8 | int x,y,width,height; 9 | double val; 10 | 11 | JComponent parent; 12 | 13 | static Color grey = new Color(80, 80, 80); 14 | 15 | public GuiProgress(int x, int y, int width, int height, JComponent parent) { 16 | this.x = x; 17 | this.y = y; 18 | this.width = width; 19 | this.height = height; 20 | this.parent = parent; 21 | 22 | this.setBounds(x, y, width, height); 23 | parent.add(this); 24 | 25 | this.setBackground(new Color(180, 20, 20)); 26 | this.setForeground(new Color(20, 180, 20)); 27 | } 28 | 29 | /** 30 | * Set value 31 | */ 32 | public void setValue(double value) { 33 | val = value; 34 | repaint(); 35 | } 36 | 37 | /** 38 | * Paint the component on the GUI 39 | */ 40 | public void paintComponent(Graphics g) { 41 | super.paintComponent(g); 42 | paint((Graphics2D) g); 43 | } 44 | 45 | /** 46 | * Paints the component with the Graphics2D instance. This is used to paint our graphics manually. 47 | * This is called once per refresh 48 | */ 49 | public void paint(Graphics2D g) { 50 | g.setColor(val > 0 ? this.getForeground() : this.getBackground()); 51 | 52 | if (val >= 0) 53 | g.fillRect(width / 2, 0, (int) (val * width / 2), height); 54 | else // OS X Can't draw negative rectangles, so we need to shift it over 55 | g.fillRect(width / 2 + (int)(val * width / 2), 0, (int)(-val * width / 2), height); 56 | 57 | g.setColor(grey); 58 | g.fillRect(width / 2 - 1, 0, 2, height); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/CompressorJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 4 | 5 | public class CompressorJNI extends JNIWrapper { 6 | public static int initializeCompressor(byte module) { 7 | SimulationData.setCompressor(module); 8 | return getPort(module); 9 | } 10 | 11 | public static boolean checkCompressorModule(byte module) { return true; } 12 | 13 | public static boolean getCompressor(int pcm_pointer) { 14 | return SimulationData.compressorRunning((byte)pcm_pointer); 15 | } 16 | 17 | public static void setClosedLoopControl(int pcm_pointer, boolean value) { 18 | SimulationData.setCompressorLoop((byte)pcm_pointer, value); 19 | } 20 | 21 | public static boolean getClosedLoopControl(int pcm_pointer) { 22 | return SimulationData.loop_compressors[pcm_pointer]; 23 | } 24 | 25 | public static boolean getPressureSwitch(int pcm_pointer) { 26 | return SimulationData.compressor_pressure[pcm_pointer]; 27 | } 28 | 29 | public static double getCompressorCurrent(int pcm_pointer) { 30 | return SimulationData.compressor_current[pcm_pointer]; 31 | } 32 | 33 | public static boolean getCompressorCurrentTooHighFault(int pcm_pointer) { return false; } 34 | public static boolean getCompressorCurrentTooHighStickyFault(int pcm_pointer) { return false; } 35 | public static boolean getCompressorShortedStickyFault(int pcm_pointer) { return false; } 36 | public static boolean getCompressorShortedFault(int pcm_pointer) { return false; } 37 | public static boolean getCompressorNotConnectedStickyFault(int pcm_pointer) { return false; } 38 | public static boolean getCompressorNotConnectedFault(int pcm_pointer) { return false; } 39 | public static void clearAllPCMStickyFaults(int pcm_pointer) {} 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/EvictingQueue.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib; 2 | 3 | import java.lang.reflect.Array; 4 | 5 | /** 6 | * A Queue that will evict the oldest element when a new one is added 7 | * 8 | * @author Jaci 9 | */ 10 | public class EvictingQueue { 11 | 12 | Object[] array; 13 | int size; 14 | 15 | /** 16 | * Create a new FIFO buffer. 17 | * @param i The size of the array 18 | */ 19 | public EvictingQueue(int i) { 20 | this.size = i; 21 | array = new Object[size]; 22 | } 23 | 24 | /** 25 | * Add a new value to the array 26 | */ 27 | public void add(T value) { 28 | pushBack(); 29 | array[0] = value; 30 | } 31 | 32 | /** 33 | * Clear the array 34 | */ 35 | public void clear() { 36 | array = new Object[size]; 37 | } 38 | 39 | /** 40 | * Push values back 41 | */ 42 | void pushBack() { 43 | 44 | for (int i = array.length - 1; i > 0; i--) { 45 | if (array[i - 1] != null) { 46 | array[i] = null; 47 | array[i] = array[i - 1]; 48 | } 49 | } 50 | array[0] = null; 51 | } 52 | 53 | /** 54 | * Get the contents of the array 55 | * @param contents A 'base' array to convert to. e.g. new String[0]; 56 | * @return The array 57 | */ 58 | public T[] toArray(T[] contents) { 59 | int s = size; 60 | if (contents.length < s) { 61 | @SuppressWarnings("unchecked") T[] newArray 62 | = (T[]) Array.newInstance(contents.getClass().getComponentType(), s); 63 | contents = newArray; 64 | } 65 | System.arraycopy(this.array, 0, contents, 0, s); 66 | if (contents.length > s) { 67 | contents[s] = null; 68 | } 69 | return contents; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/GuiRelay.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | 6 | public class GuiRelay extends JComponent { 7 | 8 | boolean isForward; 9 | boolean isReverse; 10 | 11 | int x,y,width,height; 12 | 13 | JPanel parent; 14 | 15 | public GuiRelay(int x, int y, int width, int height, JPanel parent) { 16 | this.x = x; 17 | this.y = y; 18 | this.width = width; 19 | this.height = height; 20 | this.parent = parent; 21 | 22 | this.setBounds(x, y, width, height); 23 | parent.add(this); 24 | 25 | this.setBackground(new Color(180, 20, 20)); 26 | this.setForeground(new Color(20, 180, 20)); 27 | } 28 | 29 | /** 30 | * Set to true if this relay is in forward mode 31 | */ 32 | public void setForward(boolean on) { 33 | this.isForward = on; 34 | this.repaint(); 35 | } 36 | 37 | /** 38 | * Set to true if this relay is in Reverse Mode 39 | */ 40 | public void setReverse(boolean on) { 41 | this.isReverse = on; 42 | this.repaint(); 43 | } 44 | 45 | /** 46 | * Paint the component on the GUI 47 | */ 48 | public void paintComponent(Graphics g) { 49 | super.paintComponent(g); 50 | paint((Graphics2D) g); 51 | } 52 | 53 | /** 54 | * Paints the component with the Graphics2D instance. This is used to paint our graphics manually. 55 | * This is called once per refresh 56 | */ 57 | public void paint(Graphics2D g) { 58 | g.setColor(this.getBackground()); 59 | g.fillRect(0, 0, width, height); 60 | g.setColor(this.getForeground()); 61 | if (isForward) 62 | g.fillRect(0, 0, width, height / 2); 63 | if (isReverse) 64 | g.fillRect(0, height/2, width, height / 2); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/annotation/Branch.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.annotation; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | /** 7 | * Branches are classes that are loaded as optionals. Branches specify a Module name or a Class name. If that 8 | * module or class exists, the Branch class is loaded and the method defined called. If not, the branch is ignored. 9 | * 10 | * This allows for modules to have 'optional' dependencies. Classes can have multiple Branch annotations on them, allowing 11 | * for one class to be responsible for all optional loading. 12 | * 13 | * This annotation, Branch, is placed on your Main Module class. If the dependency() class or module exists, then the branch() 14 | * class is invoked with the method() method. 15 | * 16 | * @author Jaci 17 | */ 18 | @Retention(RetentionPolicy.RUNTIME) 19 | public @interface Branch { 20 | 21 | /** 22 | * The fully quantified class name of the branch class to use in loading. 23 | * 24 | * This is the class to be loaded if the dependency() argument is met 25 | */ 26 | String branch(); 27 | 28 | /** 29 | * Either: 30 | * a) A module name. 31 | * or 32 | * b) A fully quantified class name. 33 | * 34 | * If the module or class defined is found in the Toast classpath, this class is loaded and the public static 35 | * method defined in {@link #method()} is invoked. 36 | */ 37 | String dependency(); 38 | 39 | /** 40 | * The name of a public static method in this class that will be invoked if the dependency is found. This 41 | * method should take no arguments. 42 | */ 43 | String method(); 44 | 45 | /** 46 | * Should the method be immediately executed? If true, the method won't be hit at prestart, but will, however, be executed 47 | * as soon as the annotation is constructed 48 | */ 49 | boolean immediate() default false; 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/cmd/CommandEnvironment.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command.cmd; 2 | 3 | import jaci.openrio.toast.core.Environment; 4 | import jaci.openrio.toast.core.Toast; 5 | import jaci.openrio.toast.core.command.AbstractCommand; 6 | import jaci.openrio.toast.core.command.IHelpable; 7 | import jaci.openrio.toast.lib.util.ToastUtil; 8 | 9 | /** 10 | * Prints out a bunch of details about the Robotics Environment 11 | * 12 | * @author Jaci 13 | */ 14 | public class CommandEnvironment extends AbstractCommand implements IHelpable { 15 | 16 | /** 17 | * Get the command name 18 | * e.g. 'cmd' for a command such as 'cmd 19 | */ 20 | @Override 21 | public String getCommandName() { 22 | return "environment"; 23 | } 24 | 25 | /** 26 | * Returns the 'alias' for the command (other names) 27 | */ 28 | public String[] getAlias() { 29 | return new String[] {"env"}; 30 | } 31 | 32 | /** 33 | * Invoke the command if the name matches the one to be triggered 34 | * @param argLength The amount of arguments in the 'args' param 35 | * @param args The arguments the command was invoked with. This can be empty if 36 | * none were provided. Keep in mind this does NOT include the Command Name. 37 | * Args are separated by spaces 38 | * @param command The full command message 39 | */ 40 | @Override 41 | public void invokeCommand(int argLength, String[] args, String command) { 42 | boolean raw = false; 43 | if (ToastUtil.contains(args, "-raw")) 44 | raw = true; 45 | for (String line : Environment.toLines()) 46 | if (raw) System.out.println(line); 47 | else Toast.log().info(line); 48 | } 49 | 50 | /** 51 | * Returns a help message to display with the 'help' command 52 | */ 53 | @Override 54 | public String getHelp() { 55 | return "Prints details about the Robot Environment"; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/util/JSONUtil.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.util; 2 | 3 | import com.grack.nanojson.JsonArray; 4 | import com.grack.nanojson.JsonObject; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * Utilities related to JSON operations. Due to the switching from Google GSON to Nanojson, some utilities are no longer available, 11 | * and as such, we're implementing them here. 12 | * 13 | * @author Jaci 14 | */ 15 | public class JSONUtil { 16 | 17 | /** 18 | * Convert a JSON Object to a Java Object. This converts JSON Objects to String-Object HashMaps and 19 | * JSON Arrays to standard Object[] arrays. This method will recurse deeply. 20 | * @return The Java Version of a JSON Object 21 | */ 22 | public static Object jsonToJava(Object obj) { 23 | if (obj instanceof JsonObject) { 24 | return jsonToHash((JsonObject) obj); 25 | } else if (obj instanceof JsonArray) { 26 | JsonArray arr = (JsonArray) obj; 27 | Object[] objs = new Object[arr.size()]; 28 | for (int i = 0; i < arr.size(); i++) { 29 | objs[i] = jsonToJava(arr.get(i)); 30 | } 31 | return objs; 32 | } 33 | return obj; 34 | } 35 | 36 | /** 37 | * Convert a JSON Object to a String - Object HashMap. This function will recurse deeply. 38 | */ 39 | public static HashMap jsonToHash(JsonObject object) { 40 | HashMap hash = new HashMap<>(); 41 | for (Map.Entry entry : object.entrySet()) { 42 | String key = entry.getKey(); 43 | Object el = entry.getValue(); 44 | hash.put(key, jsonToJava(el)); 45 | } 46 | return hash; 47 | } 48 | 49 | /** 50 | * Convert a String - Object HashMap to a JSON Object. This function will recurse deeply. 51 | */ 52 | public static JsonObject hashToJson(HashMap hash) { 53 | return new JsonObject(hash); // That was easier than expected 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/cmd/CommandList.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command.cmd; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.command.AbstractCommand; 5 | import jaci.openrio.toast.core.command.CommandBus; 6 | import jaci.openrio.toast.core.command.FuzzyCommand; 7 | import jaci.openrio.toast.core.command.IHelpable; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * Provides a list of all Abstract Commands in the CommandBus. 14 | * 15 | * @author Jaci 16 | */ 17 | public class CommandList extends AbstractCommand implements IHelpable { 18 | 19 | /** 20 | * Get the command name 21 | * e.g. 'cmd' for a command such as 'cmd 22 | */ 23 | @Override 24 | public String getCommandName() { 25 | return "list"; 26 | } 27 | 28 | /** 29 | * Returns a help message to display with the 'help' command 30 | */ 31 | @Override 32 | public String getHelp() { 33 | return "Will list all the commands registered on the Command Bus"; 34 | } 35 | 36 | /** 37 | * Invoke the command if the name matches the one to be triggered 38 | * @param argLength The amount of arguments in the 'args' param 39 | * @param args The arguments the command was invoked with. This can be empty if 40 | * none were provided. Keep in mind this does NOT include the Command Name. 41 | * Args are separated by spaces 42 | * @param command The full command message 43 | */ 44 | @Override 45 | public void invokeCommand(int argLength, String[] args, String command) { 46 | List strList = new ArrayList<>(); 47 | for (AbstractCommand cmd : CommandBus.commands) { 48 | strList.add(cmd.getCommandName()); 49 | } 50 | for (FuzzyCommand cmd : CommandBus.parsers) { 51 | if (cmd instanceof IHelpable) 52 | strList.add(((IHelpable) cmd).getCommandName()); 53 | } 54 | String join = String.join(", ", strList); 55 | Toast.log().info("Commands List: " + join); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/log/LogLevel.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.log; 2 | 3 | import jaci.openrio.toast.lib.util.Pretty; 4 | 5 | import java.io.PrintStream; 6 | 7 | /** 8 | * A level used by the {@link jaci.openrio.toast.lib.log.Logger} object. This is used to 9 | * differentiate severities of logged data 10 | * 11 | * @author Jaci 12 | */ 13 | public class LogLevel { 14 | 15 | String name; 16 | PrintStream stream; 17 | Pretty.Colors color; 18 | 19 | public LogLevel(String name) { 20 | SysLogProxy.init(); 21 | this.name = name; 22 | stream = System.out; 23 | color = Pretty.Colors.NORMAL; 24 | } 25 | 26 | /** 27 | * Set the name of the Log Level. This is seen in the Log message in upper case to define 28 | * the urgency of the message. 29 | */ 30 | public LogLevel setName(String n) { 31 | this.name = n; 32 | return this; 33 | } 34 | 35 | /** 36 | * Set the color of the Logger. This is red for warnings 37 | */ 38 | public LogLevel setColor(Pretty.Colors color) { 39 | this.color = color; 40 | return this; 41 | } 42 | 43 | /** 44 | * Get the color for the LogLevel. This is usually red for warnings or very very bad stuff. 45 | */ 46 | public Pretty.Colors getColor() { 47 | return color; 48 | } 49 | 50 | /** 51 | * Get the name of the Log Level. This is used in the Log message to define the urgency of 52 | * the message. 53 | */ 54 | public String getName() { 55 | return name; 56 | } 57 | 58 | /** 59 | * Set the PrintStream of the Logger. This should really only be System.out or System.err if 60 | * you want the message to show up in the console or log files. 61 | */ 62 | public LogLevel setPrintStream(PrintStream stream) { 63 | this.stream = stream; 64 | return this; 65 | } 66 | 67 | /** 68 | * Get the PrintStream object that was set for this Log Level. This is System.out by default. 69 | */ 70 | public PrintStream getPrintSteam() { 71 | return stream; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /release/ToastGradle4Dummies.txt: -------------------------------------------------------------------------------- 1 | HOW TO TOASTGRADLE: 2 | Note: Make sure your terminal/command prompt is in the 3 | same directory as the gradlew/gradlew.bat files... 4 | 5 | 1) To run gradle, type: 6 | gradlew (Windows) 7 | ./gradlew (Mac/Linux/UNIX) 8 | 9 | Not working? Try gradlew.bat for Windows. 10 | 11 | 2) To setup WPILib, run: 12 | gradlew wpi (Windows) 13 | ./gradlew wpi (Mac/Linux/UNIX) 14 | 15 | 3) To setup your workspace, do the following: 16 | -for IntelliJ IDEA: 17 | gradlew idea (Windows) 18 | ./gradlew idea (Mac/Linux/UNIX) 19 | 20 | Open the .ipr file in IntelliJ, or double click to open it 21 | -for Eclipse: 22 | gradlew eclipse (Windows) 23 | ./gradlew eclipse (Mac/Linux/UNIX) 24 | 25 | Point your eclipse workspace to this directory 26 | 27 | Dependencies aren't loaded? 28 | Dependencies are located in ${USERHOME}/wpilib/extracted/library/ 29 | Try adding them manually. 30 | 31 | 4) To deploy code to the RoboRIO, do the following: 32 | -Check all settings in build.gradle are accurate 33 | -Make sure you are connected to the same network as the RIO 34 | -Run the following command 35 | gradlew deploy (Windows) 36 | ./gradlew deploy (Mac/Linux/UNIX) 37 | 38 | 5) To restart robot code: 39 | Restarting Robot Code is to restart the user program on the RoboRIO without 40 | turning off the RoboRIO itself. This is handy for deploys. 41 | To do so, run: 42 | gradlew restart (Windows) 43 | ./gradlew restart (Mac/Linux/UNIX) 44 | 45 | 6) To reboot the RoboRIO: 46 | Rebooting means to completely restart the RoboRIO, not just the code on 47 | it. To do so, run: 48 | gradlew reboot (Windows) 49 | ./gradlew reboot (Mac/Linux/UNIX) 50 | 51 | 7) To clean the code on the RoboRIO: 52 | To clean the code on the RIO means to remove the java file already present 53 | on the RIO. This is useful for debugging. To do so, run: 54 | gradlew cleanRIO (Windows) 55 | ./gradlew cleanRIO (Mac/Linux/UNIX) 56 | -------------------------------------------------------------------------------- /src/main/resources/assets/toast/script/js/Filesystem.js: -------------------------------------------------------------------------------- 1 | jimport("jaci.openrio.toast.core.script.js.proxy.FileProxy", "__JFile"); 2 | 3 | $.withWriter = function(os, cb) { 4 | var jio = $("java.io"); 5 | var bw = new jio["BufferedWriter"](new jio["OutputStreamWriter"](os)); 6 | cb(bw); 7 | bw.close(); 8 | }; 9 | 10 | $.withOut = function(os, cb) { 11 | var jio = $("java.io"); 12 | var out = new jio["DataOutputStream"](os); 13 | cb(out); 14 | out.close(); 15 | }; 16 | 17 | $.withReader = function(is, cb) { 18 | var jio = $("java.io"); 19 | var br = new jio["BufferedReader"](new jio["InputStreamReader"](is)); 20 | cb(br); 21 | br.close(); 22 | }; 23 | 24 | $.readFully = function(is) { 25 | var str = ""; 26 | $.withReader(is, function(br) { 27 | var line = ""; 28 | while ((line = br.readLine()) != null) 29 | str += line + "\n"; 30 | }); 31 | return str; 32 | }; 33 | 34 | var __withWriter = function(fl, cb) { 35 | var jio = $("java.io"); 36 | var bw = new jio["BufferedWriter"](new jio["FileWriter"](fl)); 37 | cb(bw); 38 | bw.close(); 39 | }; 40 | 41 | var __withReader = function(fl, cb) { 42 | var jio = $("java.io"); 43 | var br = new jio["BufferedReader"](new jio["FileReader"](fl)); 44 | cb(br); 45 | br.close(); 46 | }; 47 | 48 | var __FileExtension = Java.extend(__JFile); 49 | 50 | function File(path) { 51 | var fl = new __FileExtension(path, { 52 | withWriter: function(cb) { 53 | __withWriter(fl, cb); 54 | }, 55 | withReader: function(cb) { 56 | __withReader(fl, cb); 57 | }, 58 | readFully: function() { 59 | var str = ""; 60 | __withReader(fl, function(br) { 61 | var line = ""; 62 | while ((line = br.readLine()) != null) 63 | str += line + "\n"; 64 | }); 65 | return str; 66 | } 67 | }); 68 | return fl; 69 | } 70 | 71 | $.file = function(root, target) { 72 | return new File(new java.io.File(new java.io.File(root.replace(/file:(\\|\/)?/, "")).getParentFile(), target)); 73 | }; -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/PneumaticsGUI.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.awt.event.WindowAdapter; 6 | import java.awt.event.WindowEvent; 7 | 8 | public class PneumaticsGUI extends JPanel { 9 | public static PneumaticsGUI INSTANCE; 10 | 11 | public static JPanel create() { 12 | JFrame frame = new JFrame("Toast Pneumatics GUI"); 13 | JPanel panel = new PneumaticsGUI(); 14 | frame.add(panel); 15 | frame.pack(); 16 | frame.setLocationRelativeTo(null); 17 | frame.setVisible(true); 18 | frame.setResizable(false); 19 | frame.addWindowListener(new WindowAdapter() { 20 | @Override 21 | public void windowOpened(WindowEvent e) { 22 | super.windowOpened(e); 23 | } 24 | 25 | @Override 26 | public void windowClosing(WindowEvent e) { 27 | super.windowClosing(e); 28 | INSTANCE = null; 29 | } 30 | }); 31 | return panel; 32 | } 33 | 34 | public PneumaticsGUI() { 35 | INSTANCE = this; 36 | 37 | this.setBackground(new Color(11, 11, 11)); 38 | this.setPreferredSize(new Dimension(400, 375)); 39 | this.setVisible(true); 40 | this.setLayout(null); 41 | 42 | CommonGUI.setup_keys(this, this::reinitElements); 43 | 44 | initElements(); 45 | } 46 | 47 | /** 48 | * Completely reinflate the GUI. This replaces all JComponents in the GUI. 49 | */ 50 | public void reinitElements() { 51 | this.removeAll(); 52 | initElements(); 53 | } 54 | 55 | GuiPCM[] pcms = new GuiPCM[3]; 56 | 57 | /** 58 | * Inflate the GUI. This does everything from adding all the elements, to adding the background image and setting up 59 | * the GUI. This is where most of the work is done, and is only called once: upon creation of the GUI. 60 | */ 61 | public void initElements() { 62 | for (int i = 0; i < pcms.length; i++) { 63 | pcms[i] = new GuiPCM(10, 30 + 105 * i, i, this); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/thread/NonVitalLoadTask.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.thread; 2 | 3 | /** 4 | * A Non-Vital Load Task is a task that starts initialization with Toast's Bootstrapper, but isn't necessarily 5 | * a requirement later on in the load process. These Load Tasks are started at Toast Bootstrap, and load in their 6 | * own Thread. From there on, the task will load and not cause any blocking on the main thread, reducing startup 7 | * time. If a module requires the use of the task, the Task will block the thread (join) and wait until loading 8 | * is complete before advancing. This method enables lengthy tasks (such as JavaScript engine preparation) to be 9 | * threaded and only be waited on if they are required for a task. If the loading is already complete, the thread 10 | * will not block and will be allowed to continue immediately. 11 | * 12 | * @author Jaci 13 | */ 14 | public class NonVitalLoadTask { 15 | 16 | private Thread __loading_thread; 17 | private Runnable __loading_runnable; 18 | private boolean __loaded = false; 19 | 20 | public NonVitalLoadTask(Runnable run) { 21 | this.__loading_runnable = run; 22 | } 23 | 24 | /** 25 | * Require the task to be completely loaded before continuing. This ensures that the task is prepared 26 | * and ready to go before use. This is a blocking method, but may return immediately if loading is already complete. 27 | */ 28 | public void requireLoaded() { 29 | if (__loaded) return; 30 | if (__loading_thread == null) 31 | throw new IllegalStateException("Loading has not started yet!"); 32 | try { 33 | __loading_thread.join(); 34 | __loaded = true; 35 | } catch (InterruptedException e) { } 36 | } 37 | 38 | /** 39 | * Start the loading of the task. This will launch a new thread dedicated to the loading of this task, 40 | * so any tasks being used should be classified as Thread-Safe. 41 | */ 42 | public void startLoading() { 43 | __loading_thread = new Thread(__loading_runnable); 44 | __loading_thread.start(); 45 | __loading_thread.setPriority(Thread.NORM_PRIORITY); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/cmd/CommandThreadPool.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command.cmd; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.command.AbstractCommand; 5 | import jaci.openrio.toast.core.command.IHelpable; 6 | import jaci.openrio.toast.core.thread.Async; 7 | import jaci.openrio.toast.lib.log.Logger; 8 | 9 | /** 10 | * This command will simply echo data about the {@link Async} to the console. 11 | * This is for debugging purposes 12 | * 13 | * command_name: 'threads' 14 | * args: nil 15 | * 16 | * @author Jaci 17 | */ 18 | public class CommandThreadPool extends AbstractCommand implements IHelpable { 19 | 20 | /** 21 | * Get the command name 22 | * e.g. 'cmd' for a command such as 'cmd 23 | */ 24 | @Override 25 | public String getCommandName() { 26 | return "threads"; 27 | } 28 | 29 | /** 30 | * Invoke the command if the name matches the one to be triggered 31 | * @param argLength The amount of arguments in the 'args' param 32 | * @param args The arguments the command was invoked with. This can be empty if 33 | * none were provided. Keep in mind this does NOT include the Command Name. 34 | * Args are separated by spaces 35 | * @param command The full command message 36 | */ 37 | @Override 38 | public void invokeCommand(int argLength, String[] args, String command) { 39 | Async e = Async.INSTANCE; 40 | Logger l = Toast.log(); 41 | l.info("*Toast Thread Pool Instance Data: "); 42 | l.info(String.format("\t Active Threads: %d, Core Threads: %d", e.getPoolSize(), e.getCorePoolSize())); 43 | l.info(String.format("\t Active Jobs: %d, Completed Jobs: %d, Total Jobs: %d", e.getActiveCount(), e.getCompletedTaskCount(), e.getTaskCount())); 44 | l.info(String.format("\t Shutdown? %s, Terminated? %s, Terminating? %s", e.isShutdown(), e.isTerminated(), e.isTerminating())); 45 | l.info("*End Toast Thread Pool Data"); 46 | } 47 | 48 | /** 49 | * Returns a help message to display with the 'help' command 50 | */ 51 | @Override 52 | public String getHelp() { 53 | return "Prints monitoring data regarding the ToastThreadPool. "; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /patches/src/main/java/edu/wpi/first/wpilibj/hal/InterruptJNI.java: -------------------------------------------------------------------------------- 1 | package edu.wpi.first.wpilibj.hal; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.jni.InterruptContainer; 4 | 5 | public class InterruptJNI extends JNIWrapper { 6 | 7 | public interface InterruptJNIHandlerFunction { 8 | void apply(int interruptAssertedMask, Object param); 9 | } 10 | 11 | private static InterruptContainer get(int point) { 12 | return InterruptContainer.getByIndex(point); 13 | } 14 | 15 | public static int initializeInterrupts(int interruptIndex, byte watcher) { 16 | InterruptContainer container = new InterruptContainer(); 17 | return getPort((byte) InterruptContainer.interrupts.indexOf(container)); 18 | } 19 | 20 | public static void cleanInterrupts(int interrupt_pointer) { 21 | InterruptContainer.interrupts.remove(get(interrupt_pointer)); 22 | } 23 | 24 | public static int waitForInterrupt(int interrupt_pointer, double timeout, boolean ignorePrevious) { 25 | get(interrupt_pointer).waitForInterrupt(timeout); 26 | return 0; 27 | } 28 | 29 | public static void enableInterrupts(int interrupt_pointer) { 30 | get(interrupt_pointer).setEnabled(true); 31 | } 32 | 33 | public static void disableInterrupts(int interrupt_pointer) { 34 | get(interrupt_pointer).setEnabled(false); 35 | } 36 | 37 | public static double readRisingTimestamp(int interrupt_pointer) { 38 | return get(interrupt_pointer).getTime(true); 39 | } 40 | 41 | public static double readFallingTimestamp(int interrupt_pointer) { 42 | return get(interrupt_pointer).getTime(false); 43 | } 44 | 45 | public static void requestInterrupts(int interrupt_pointer, byte routing_module, int routing_pin, byte routing_analog_trigger) { 46 | get(interrupt_pointer).setPin(routing_pin); 47 | } 48 | 49 | public static void attachInterruptHandler(int interrupt_pointer, InterruptJNIHandlerFunction handler, Object param) { 50 | get(interrupt_pointer).setFunc(handler, param); 51 | } 52 | 53 | public static void setInterruptUpSourceEdge(int interrupt_pointer, byte risingEdge, byte fallingEdge) { 54 | get(interrupt_pointer).setup(risingEdge != 0, fallingEdge != 0); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/security/SecurityPolicy.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.security; 2 | 3 | import jaci.openrio.toast.core.ToastConfiguration; 4 | import jaci.openrio.toast.lib.log.Logger; 5 | 6 | import java.security.Permission; 7 | 8 | /** 9 | * The SecurityPolicy enumeration containing all the possible values for controlling the verbosity and action of the 10 | * {@link ToastSecurityManager}. This dictates how strictly the security manager is controlled, and is defined in the 11 | * Toast configuration file. More information is defined in the {@link ToastSecurityManager} 12 | * 13 | * @author Jaci 14 | */ 15 | public enum SecurityPolicy { 16 | NONE, LOOSE, STRICT; 17 | 18 | static Logger log; 19 | static SecurityPolicy policy; 20 | 21 | /** 22 | * Get the SecurityPolicy logger, or create it if it doesn't already exist. 23 | */ 24 | public static Logger log() { 25 | if (log == null) log = new Logger("Security", Logger.ATTR_DEFAULT); 26 | return log; 27 | } 28 | 29 | /** 30 | * Match the String provided to the Enumerated values. This is used to parse the data 31 | * provided in the ToastConfiguration 32 | */ 33 | public static SecurityPolicy match(String s) { 34 | for (SecurityPolicy policy : values()) { 35 | if (policy.name().equalsIgnoreCase(s)) return policy; 36 | } 37 | return STRICT; 38 | } 39 | 40 | /** 41 | * Get the currently active security policy, or read it from the Configuration if it 42 | * isn't set. 43 | */ 44 | public static SecurityPolicy get() { 45 | if (policy != null) return policy; 46 | String s = ToastConfiguration.Property.SECURITY_POLICY.asString(); 47 | policy = match(s); 48 | return policy; 49 | } 50 | 51 | /** 52 | * Trigger the policy if there is a violation in the {@link SecurityManager} 53 | */ 54 | public void trigger(Permission perm, String message) { 55 | if (this.equals(NONE)) return; 56 | if (this.equals(LOOSE)) { 57 | log().warn(message); 58 | log().exception(new Throwable()); 59 | } else { 60 | log().warn(message); 61 | log().exception(new Throwable()); 62 | throw new SecurityException(message); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/network/SocketManager.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.network; 2 | 3 | import jaci.openrio.delegate.BoundDelegate; 4 | import jaci.openrio.delegate.DelegateServer; 5 | 6 | /** 7 | * The class responsible for managing Socket communication between Toast Modules and other programs running 8 | * on the Driver Station. This class implements the NetworkDelegate API in order to make sure modules do 9 | * not conflict on sockets, as well as making sure sockets are within the limits FMS provides, having only 10 | * 10 sockets available, specifically, 5800-5810. This SocketManager listens on ports 5806-5807, having the 11 | * master socket on port 5805. It is recommended to look though the NetworkDelegate API Documentation for 12 | * more information regarding the master-slave socket lifecycle. Ports 5800-5804 are left open for communication 13 | * that requires a specific protocol, such as the WebUI that needs a HTTP communication. Unless you absolutely 14 | * require a specific socket, it is highly recommended you use this class. 15 | * 16 | * @author Jaci 17 | */ 18 | public class SocketManager { 19 | 20 | static DelegateServer delegateServer = DelegateServer.createRange(5805, 5806, 5807); 21 | 22 | static boolean launch = false; 23 | 24 | /** 25 | * Register the default BoundDelegates used by Toast 26 | */ 27 | public static void registerNatives() { 28 | LoggerDelegate.init(); 29 | CommandDelegate.init(); 30 | } 31 | 32 | /** 33 | * Register your own Delegate. The String 'id' parameter should be your module name, prepended 34 | * by your package name. This is to make sure there are no conflicts. e.g. 'com.yourname.YourModule' 35 | */ 36 | public static BoundDelegate register(String id) { 37 | launch = true; 38 | return delegateServer.requestDelegate(id); 39 | } 40 | 41 | /** 42 | * Launch the DelegateServer. This should be left to Toast to handle. 43 | */ 44 | public static void launch() { 45 | SocketManager.registerNatives(); 46 | if (launch) { 47 | new Thread() { 48 | public void run() { 49 | try { 50 | delegateServer.launchDelegate(); 51 | } catch (Exception e) { } 52 | } 53 | }.start(); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/profiler/ProfilerEntity.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.profiler; 2 | 3 | /** 4 | * The ProfilerEntity is a class designed to measure the time taken between the .start() and .stop() methods are called, 5 | * and is designed to be used with the {@link Profiler} and {@link ProfilerSection} classes. 6 | * 7 | * @author Jaci 8 | */ 9 | public class ProfilerEntity { 10 | 11 | long start_time; 12 | long end_time; 13 | long total_time; 14 | String name; 15 | 16 | /** 17 | * A default, empty constructor for those who wish to call {@link #setName(String)} later 18 | */ 19 | public ProfilerEntity() { } 20 | 21 | /** 22 | * Set the name of the ProfilerSection. This is used to identify what exactly you are trying to measure. 23 | */ 24 | public void setName(String n) { 25 | this.name = n; 26 | } 27 | 28 | /** 29 | * Create a new ProfilerEntity with the given name 30 | */ 31 | public ProfilerEntity(String name) { 32 | this.name = name; 33 | } 34 | 35 | /** 36 | * Get the name of the Entity as set in the constructor or setName() method. May be null. 37 | */ 38 | public String name() { 39 | return name; 40 | } 41 | 42 | /** 43 | * Start the entity. Call this when you are ready to start measuring. Returns itself for easy chaining. 44 | */ 45 | public ProfilerEntity start() { 46 | start_time = System.nanoTime(); 47 | return this; 48 | } 49 | 50 | /** 51 | * Stop the entity. Call this when the thing you are measuring is complete. This will be measured in nanoseconds. 52 | */ 53 | public void stop() { 54 | end_time = System.nanoTime(); 55 | total_time = end_time - start_time; 56 | } 57 | 58 | /** 59 | * Get the duration of the profiler entity. This is measured in nanoseconds. 60 | */ 61 | public long getDuration() { 62 | return total_time; 63 | } 64 | 65 | /** 66 | * Get the duration of the profiler entity. This is measured in milliseconds. 67 | */ 68 | public long getDurationMS() { 69 | return getDuration() / 1000000; 70 | } 71 | 72 | /** 73 | * Get the duration of the profiler entity. This is measured in seconds. 74 | */ 75 | public long getDurationS() { 76 | return getDurationMS() / 1000; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/cmd/CommandJScript.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command.cmd; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.command.AbstractCommand; 5 | import jaci.openrio.toast.core.command.CommandBus; 6 | import jaci.openrio.toast.core.script.js.JavaScript; 7 | 8 | /** 9 | * The JavaScript command will open an interactive JavaScript prompt for live-scripting, similar to the 'jjs' command 10 | * on systems with Oracle Nashorn installed. 11 | * 12 | * @author Jaci 13 | */ 14 | public class CommandJScript extends AbstractCommand { 15 | 16 | /** 17 | * Get the command name 18 | * e.g. 'cmd' for a command such as 'cmd 19 | */ 20 | @Override 21 | public String getCommandName() { 22 | return "js"; 23 | } 24 | 25 | /** 26 | * Invoke the command if the name matches the one to be triggered 27 | * @param argLength The amount of arguments in the 'args' param 28 | * @param args The arguments the command was invoked with. This can be empty if 29 | * none were provided. Keep in mind this does NOT include the Command Name. 30 | * Args are separated by spaces 31 | * @param command The full command message 32 | */ 33 | @Override 34 | public void invokeCommand(int argLength, String[] args, String command) { 35 | boolean run = true; 36 | Toast.log().info("Interactive Toast JavaScript console."); 37 | while (run) { 38 | try { 39 | String message = CommandBus.requestNextMessage(); 40 | if (message == null) { 41 | run = false; 42 | continue; 43 | } 44 | if (message.equals("exit") || message.equals("stop")) { 45 | run = false; 46 | continue; 47 | } 48 | Object ret = JavaScript.eval(message); 49 | if (ret != null) 50 | Toast.log().raw("#=> " + ret.toString()); 51 | else 52 | Toast.log().raw("#=> null"); 53 | } catch (InterruptedException e) { 54 | run = false; 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | Toast.log().info("Interactive JavaScript console stopped."); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/shared/ModuleEventBus.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.shared; 2 | 3 | import jaci.openrio.toast.core.thread.Async; 4 | 5 | import java.util.Vector; 6 | 7 | /** 8 | * The Module Event Bus is a bus that allows for Modules to raise events 9 | * globally. This Event Bus allows for Modules to be optional dependencies, but 10 | * still have methods invoked/listened for 11 | * 12 | * This can also be used for communication inside of your own Module. Kinda like how you 13 | * can use a bag or suitcase as a foot-stool. It's not a bug, it's a feature. 14 | * 15 | * @author Jaci 16 | */ 17 | public class ModuleEventBus { 18 | 19 | static volatile Vector listeners = new Vector<>(); 20 | 21 | /** 22 | * Register a {@link jaci.openrio.toast.core.shared.ModuleEventListener} to the 23 | * bus. This is required for a class to be able to listen for events 24 | */ 25 | public static void registerListener(ModuleEventListener listener) { 26 | listeners.add(listener); 27 | } 28 | 29 | /** 30 | * Raise an event to all listeners on the bus 31 | * @param sender The sender of the event. This is usually your Module's name unless otherwise 32 | * defined 33 | * @param event_type The type of event to raise. This should be a unique identifier 34 | * @param data The data passed to the event, or null if none are provided 35 | */ 36 | public static void raiseEvent(String sender, String event_type, Object... data) { 37 | for (ModuleEventListener listener : listeners) 38 | listener.onModuleEvent(sender, event_type, data); 39 | } 40 | 41 | /** 42 | * Raise an event to all listeners on the bus, in a new Thread 43 | * @param sender The sender of the event. This is usually your Module's name unless otherwise 44 | * defined 45 | * @param event_type The type of event to raise. This should be a unique identifier 46 | * @param data The data passed to the event, or null if none are provided 47 | */ 48 | public static void raiseConcurrentEvent(String sender, String event_type, Object... data) { 49 | Async.INSTANCE.submit(new Runnable() { 50 | public void run() { 51 | for (ModuleEventListener listener : listeners) 52 | listener.onModuleEvent(sender, event_type, data); 53 | } 54 | }); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/module/ToastModule.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.module; 2 | 3 | import jaci.openrio.toast.core.loader.annotation.NoLoad; 4 | import jaci.openrio.toast.core.loader.module.ModuleContainer; 5 | 6 | import java.util.HashMap; 7 | 8 | /** 9 | * The Base class for all Toast Modules. This should be extending instead of {@link edu.wpi.first.wpilibj.RobotBase} if you wish 10 | * for your module to work with Toast. 11 | * 12 | * @author Jaci 13 | */ 14 | @NoLoad 15 | public abstract class ToastModule { 16 | 17 | /** 18 | * The {@link jaci.openrio.toast.core.loader.module.ModuleContainer} object for this Module. This is set before 19 | * {@link #onConstruct} by the {@link jaci.openrio.toast.core.loader.RobotLoader} 20 | */ 21 | public ModuleContainer _moduleContainer; 22 | 23 | /** 24 | * Get a Friendly name for the Module. This is what the Module is referenced by. This should be unique 25 | * per module 26 | * @return A unique, friendly name for the module 27 | */ 28 | public abstract String getModuleName(); 29 | 30 | /** 31 | * Get a Version for the Module. This should change as the Module is updated. If you Module is only being used by 32 | * your team, this isn't really necessary. This is here for distributed APIs and modules. 33 | * @return The version of the module 34 | */ 35 | public abstract String getModuleVersion(); 36 | 37 | /** 38 | * Called on 'Pre-Initialization' of the robot. This is called before the Robot is indicated as 'ready to go'. Inputs 39 | * and Outputs should be configured here. This method should not have much over-head 40 | */ 41 | public abstract void prestart(); 42 | 43 | /** 44 | * Called on 'Initialization' of the robot. This is called after the Robot is indicated as 'ready to go'. Things like 45 | * Network Communications and Camera Tracking should be initialized here. 46 | */ 47 | public abstract void start(); 48 | 49 | /** 50 | * Called when this Module has been discovered and constructed. This method isn't usually used for much, but 51 | * can be useful for triggering things before the robot is in Pre-Initialization. 52 | */ 53 | public void onConstruct() { } 54 | 55 | /** 56 | * Returns a HashMap of Custom data to add to the Crash Log if appropriate. 57 | */ 58 | public HashMap getCustomData() { return null; } 59 | } 60 | -------------------------------------------------------------------------------- /tools/imports.rb: -------------------------------------------------------------------------------- 1 | # Checks code Imports to ensure that they will work with the RoboRIO JDK 2 | require 'open-uri' 3 | require 'openssl' 4 | CLASSLIST = "https://gist.githubusercontent.com/JacisNonsense/910b501ffce221c0a41b/raw" 5 | class_list_content = open(CLASSLIST, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read.split("\n") 6 | 7 | exported_libs = Dir["build/libs/Toast-*.jar"] 8 | toast_jar = "" 9 | for filename in exported_libs.select {|i| i[/.*Toast-(\d+\.\d+\.\d+(-\d+[a-z]+)?).jar/]} 10 | toast_jar = filename 11 | end 12 | puts "Using Jar: #{toast_jar}" 13 | 14 | # Toast Jar Classes -- Raw names of each Source file 15 | toast_jar_classes = Dir["src/main/java/**/*.java"] 16 | # Toast Jar Classes -- Remove src/main/java prefix 17 | toast_jar_classes = toast_jar_classes.map {|str| str.gsub(/src.main.java./, "")} 18 | # Toast Jar Classes (Stub) -- Remove extension and format as package name 19 | toast_jar_classes_stub = toast_jar_classes.map {|str| str.gsub(/\//, ".").gsub(/\.(class|java)$/, "")} 20 | 21 | # List all the entries in the Compiled Toast Jar to make sure libraries are counted 22 | class_list_content += ` jar tf #{toast_jar} `.split("\n").grep /.*.class/ 23 | # Format everything in the ClassList in package form 24 | classlist = class_list_content.map {|str| str.gsub(/\//, ".").gsub(/\.(class|java)$/, "")} 25 | 26 | # AWT and Swing packages aren't required, as GUI operation is only done in Sim 27 | # Also ignore Nashorn extensions because of ButterKnife 28 | EXCLUSIONS = ["java.awt.*", "javax.swing.*", "javax.image.*", 29 | "jdk.nashorn.*", "jdk.internal.*"] 30 | 31 | puts "Classes To Check: #{toast_jar_classes.length}" 32 | puts "Valid Robot Classes: #{classlist.length}" 33 | 34 | @errored = false 35 | 36 | for current_class in toast_jar_classes_stub 37 | puts "Checking: #{current_class}" 38 | checklist = `javap -verbose -classpath #{toast_jar} -p #{current_class} `.split("\n") 39 | .grep(/#[0-9]* = Class.* \/\/ ([^\"].*)/).map { |x| x.gsub(/.*\/\/ (.*)/, "\\1").gsub(/\//, ".") } 40 | 41 | for importcheck in checklist 42 | importcheck = importcheck.gsub /(\$\S*)*/, "" # For things like jaci.openrio.toast.core.Environment$OS (nested classes) 43 | errored = !(classlist.include?(importcheck) || (EXCLUSIONS.select {|x| importcheck =~ /#{x}/}.length != 0)) 44 | @errored = true if errored 45 | puts "Error: import #{importcheck} on file #{current_class}" if errored 46 | end 47 | end 48 | 49 | if @errored; puts "Error Found: Aborting..."; exit 1; end 50 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/state/ConcurrentVector.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.state; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | 6 | /** 7 | * Why the extra Join and Remove Queues you ask? Well, if a module that is currently in a ticking or transition state wants 8 | * to add or remove a listener from the list, we run into some errors. Without 'synchronized', we run into a Concurrent 9 | * Modification, which causes big issues. With 'synchronized', the Thread will be forever blocked because it's trying to access 10 | * a synchronized lock from INSIDE the synchronized method. I hate iteration iteration iteration iteration iteration iteration 11 | * iteration iteration iteration iteration iteration iteration iteration.... 12 | * 13 | * @author Jaci 14 | */ 15 | public class ConcurrentVector extends ArrayList { 16 | 17 | ArrayList joinQueue = new ArrayList(); 18 | ArrayList removeQueue = new ArrayList(); 19 | 20 | boolean changed = false; 21 | 22 | /** 23 | * Push an element into the Concurrent Vector. This element will be added to the 24 | * main vector/list when using the {@link #tick()} method 25 | */ 26 | public void addConcurrent(E element) { 27 | joinQueue.add(element); 28 | changed = true; 29 | } 30 | 31 | /** 32 | * Pull and release an element from the Concurrent Vector. This element will be removed 33 | * from the main vector/list when using the {@link #tick()} method 34 | */ 35 | public void removeConcurrent(E element) { 36 | removeQueue.add(element); 37 | changed = true; 38 | } 39 | 40 | /** 41 | * Tick the vector. When called, this method will take all the recently added/removed objects and 42 | * pass them into/out of the main list. This allows the Vector to be accessed by multiple objects when 43 | * the list is being iterated over. Call this before calling .get() or other, similar methods. 44 | */ 45 | public void tick() { 46 | if (!changed) return; 47 | 48 | Iterator joinIt = joinQueue.iterator(); 49 | while (joinIt.hasNext()) { 50 | this.add(joinIt.next()); 51 | joinIt.remove(); 52 | } 53 | 54 | Iterator removeIt = removeQueue.iterator(); 55 | while (removeIt.hasNext()) { 56 | this.remove(removeIt.next()); 57 | removeIt.remove(); 58 | } 59 | changed = false; 60 | removeIt = null; 61 | joinIt = null; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/io/usb/MassStorageDevice.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.io.usb; 2 | 3 | import jaci.openrio.toast.lib.module.ModuleConfig; 4 | 5 | import java.io.File; 6 | 7 | /** 8 | * A container object for a Mass Storage Device (External HDD, Flash Drive, Pen Drive). This holds 9 | * the absolute, non sym-link directory as well as configuration settings for the autorun file. These should 10 | * ONLY contain valid Mass Storage Devices. 11 | * 12 | * @author Jaci 13 | */ 14 | public class MassStorageDevice { 15 | 16 | /** 17 | * The absolute directory of the Mass Storage Device 18 | */ 19 | public File drivePath; 20 | 21 | /** 22 | * The ModuleConfig file for the Drive. This is the toast_autorun.conf file required in the drive 23 | */ 24 | public ModuleConfig config; 25 | 26 | /** 27 | * The drive name. This is human-friendly and also the ID for the drive 28 | */ 29 | public String drive_name; 30 | 31 | /** 32 | * The directory that Toast files should be stored in on the drive 33 | */ 34 | public File toast_directory; 35 | 36 | /** 37 | * The directory that USB Dumps are kept in 38 | */ 39 | public File dump_directory; 40 | public boolean override_modules; 41 | public boolean concurrent_modules; 42 | public int config_priority; 43 | public int filesystem_priority; 44 | public boolean accept_logs; 45 | 46 | public MassStorageDevice(File path, ModuleConfig autorun, String name) { 47 | this.drivePath = path; 48 | this.config = autorun; 49 | this.drive_name = name; 50 | this.toast_directory = new File(path, autorun.getString("toast.directory", "toast")); 51 | this.dump_directory = new File(path, autorun.getString("toast.dumps", "toast_usb_dumps")); 52 | this.toast_directory.mkdirs(); 53 | this.override_modules = autorun.getBoolean("toast.override_modules", false); 54 | this.concurrent_modules = autorun.getBoolean("toast.concurrent_modules", true); 55 | this.config_priority = autorun.getInt("toast.priority.config", 0); 56 | this.filesystem_priority = autorun.getInt("toast.priority.filesystem", 0); 57 | this.accept_logs = autorun.getBoolean("toast.accept_logs", true); 58 | } 59 | 60 | /** 61 | * Convert the Mass Storage Device to a String, containing name and any other relevant details. 62 | */ 63 | public String toString() { 64 | return "MassStorageDevice[name: " + drive_name + ", path: " + drivePath + "]"; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/srx/SRX_Reg.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation.srx; 2 | 3 | import com.ctre.CANTalon; 4 | 5 | import java.util.HashMap; 6 | 7 | /** 8 | * SWIG Registry for Simulated Talon SRXs over the CAN bus. 9 | * 10 | * @author Jaci 11 | */ 12 | public class SRX_Reg { 13 | 14 | public static HashMap wrappers = new HashMap<>(); 15 | 16 | public static class SRX_Wrapper { 17 | 18 | public int dev_id, control, mode, slotid = 0; 19 | public double pvbus, voltage; 20 | public int follower, speed, position; 21 | 22 | public double[][] gains = new double[2][4]; 23 | 24 | public HashMap params = new HashMap<>(); 25 | 26 | public int cache_value = -1; 27 | 28 | Runnable updater; 29 | 30 | public SRX_Wrapper(int device_id, int control_period) { 31 | this.dev_id = device_id; 32 | this.control = control_period; 33 | } 34 | 35 | public void update() { 36 | if (updater != null) updater.run(); 37 | } 38 | 39 | public void onUpdate(Runnable run) { 40 | updater = run; 41 | } 42 | 43 | public void setMode(int mode) { 44 | this.mode = mode; 45 | if (cache_value != -1) 46 | setDemand(cache_value); 47 | update(); 48 | } 49 | 50 | public void setSlotID(int slot) { 51 | this.slotid = slot; 52 | update(); 53 | } 54 | 55 | public void setVBus(double val) { 56 | this.pvbus = val; 57 | update(); 58 | } 59 | 60 | public void setGains(int slot, int index, double value) { 61 | gains[slot][index] = value; 62 | update(); 63 | } 64 | 65 | public void setDemand(int value) { 66 | cache_value = -1; 67 | if (mode == CANTalon.TalonControlMode.Voltage.value) 68 | voltage = (double)value / 256; 69 | else if (mode == CANTalon.TalonControlMode.Follower.value) 70 | follower = value; 71 | else if (mode == CANTalon.TalonControlMode.Position.value) 72 | position = value; 73 | else if (mode == CANTalon.TalonControlMode.Speed.value) 74 | speed = value; 75 | else if (mode == CANTalon.TalonControlMode.Disabled.value) 76 | cache_value = value; 77 | 78 | update(); 79 | } 80 | 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/command/cmd/CommandHelp.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.command.cmd; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.command.*; 5 | 6 | import java.util.regex.Pattern; 7 | 8 | /** 9 | * Provides a command for testing the 'help' of other commands. This is used to display help messages of commands 10 | * to the console so the user knows how to use the commands required. 11 | * 12 | * @author Jaci 13 | */ 14 | public class CommandHelp extends AbstractCommand { 15 | 16 | /** 17 | * Get the command name 18 | * e.g. 'cmd' for a command such as 'cmd 19 | */ 20 | @Override 21 | public String getCommandName() { 22 | return "help"; 23 | } 24 | 25 | /** 26 | * Invoke the command if the name matches the one to be triggered 27 | * @param argLength The amount of arguments in the 'args' param 28 | * @param args The arguments the command was invoked with. This can be empty if 29 | * none were provided. Keep in mind this does NOT include the Command Name. 30 | * Args are separated by spaces 31 | * @param command The full command message 32 | */ 33 | @Override 34 | public void invokeCommand(int argLength, String[] args, String command) { 35 | Pattern regex = null; 36 | if (args.length == 1) { 37 | regex = Pattern.compile(args[0]); 38 | } else if (args.length != 0) { 39 | throw new UsageException("help [command]"); 40 | } 41 | 42 | for (AbstractCommand cmd : CommandBus.commands) 43 | tryRegex(regex, cmd); 44 | for (FuzzyCommand cmd : CommandBus.parsers) 45 | tryRegex(regex, cmd); 46 | } 47 | 48 | /** 49 | * Tests if the pattern provided with the Help Command matches the given Command object's name. 50 | * The Command Object must implement 'IHelpable' to be a valid command. 51 | */ 52 | public void tryRegex(Pattern pattern, Object obj) { 53 | if (obj instanceof IHelpable) { 54 | if (pattern == null) { 55 | help((IHelpable) obj); 56 | } else { 57 | if (pattern.matcher(((IHelpable) obj).getCommandName()).matches()) 58 | help((IHelpable) obj); 59 | } 60 | } 61 | } 62 | 63 | /** 64 | * Returns a help message to display with the 'help' command 65 | */ 66 | public void help(IHelpable helpable) { 67 | Toast.log().info(helpable.getCommandName() + " -- " + helpable.getHelp()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/EnvJars.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader; 2 | 3 | import jaci.openrio.toast.core.Environment; 4 | 5 | import java.io.File; 6 | import java.util.ArrayList; 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | /** 11 | * Helps Toast differentiate between what is a dependency and what isn't 12 | * 13 | * @author Jaci 14 | */ 15 | public class EnvJars { 16 | 17 | public static ArrayList knownFiles; 18 | 19 | static { 20 | knownFiles = new ArrayList<>(); 21 | 22 | add("NetworkTables"); 23 | add("WPILib"); 24 | add("idea_rt"); 25 | add("gragent"); 26 | add("groovy-.*"); 27 | add("nanojson-.*"); 28 | add("NetworkDelegate-.*"); 29 | add("NetworkTables-.*"); 30 | add("wpilib.*"); 31 | add(".*javafx.*"); 32 | } 33 | 34 | /** 35 | * Register a new Known file or path on the registry. Files or paths matching the Regex 36 | * pattern provided will not be loaded into the Toast Classpath or tested for Module 37 | * candidacy. 38 | */ 39 | public static void add(String pat) { 40 | knownFiles.add(Pattern.compile(pat)); 41 | } 42 | 43 | /** 44 | * Returns whether or not the file should be loaded or tested for candidacy. 45 | * @see #isKnown(File) 46 | * @see #isJDKJar(File) 47 | */ 48 | public static boolean isLoadable(File f) { 49 | boolean jdk = isJDKJar(f); 50 | boolean known = isKnown(f); 51 | return !jdk && !known; 52 | } 53 | 54 | /** 55 | * Will return true if the given file is known, and therefore shouldn't be checked for module candidacy. This 56 | * is used for things like Toast's external libraries and system jars 57 | */ 58 | public static boolean isKnown(File f) { 59 | String name = f.getName().replace(".jar", ""); 60 | for (Pattern p : knownFiles) { 61 | Matcher matcher = p.matcher(name); 62 | if (matcher.matches()) 63 | return true; 64 | } 65 | return false; 66 | } 67 | 68 | /** 69 | * Returns true if the given file is a JDK jar. This is gauged by whether or not the file's absolute path intersects 70 | * with the System's JDK home Environmental Variable. 71 | */ 72 | public static boolean isJDKJar(File f) { 73 | String file = f.getAbsolutePath(); 74 | String jdk = new File(Environment.getJava_home()).getParentFile().getAbsolutePath(); // Parent for libs 75 | return file.startsWith(jdk); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /release/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/crash/CrashInfoModules.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.crash; 2 | 3 | import jaci.openrio.toast.core.loader.module.ModuleContainer; 4 | import jaci.openrio.toast.core.loader.module.ModuleManager; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * CrashInfoProvider for Modules. This prints out important information about the modules, including the 13 | * packages they own and other details. 14 | * 15 | * @author Jaci 16 | */ 17 | public class CrashInfoModules implements CrashInfoProvider { 18 | 19 | @Override 20 | public String getName() { 21 | return "Modules"; 22 | } 23 | 24 | /** 25 | * The same as {@link #getCrashInfo}, but is done before the crash is logged. 26 | * Keep in mind this data is not appended with {@link #getName} 27 | * 28 | * @param t The exception encountered 29 | */ 30 | @Override 31 | public String getCrashInfoPre(Throwable t) { 32 | return null; 33 | } 34 | 35 | /** 36 | * The information to append to the crash log 37 | * 38 | * @param t The exception encountered 39 | */ 40 | @Override 41 | public List getCrashInfo(Throwable t) { 42 | ArrayList text = new ArrayList<>(); 43 | 44 | for (ModuleContainer module : ModuleManager.getContainers()) { 45 | try { 46 | text.add(module.getName()); 47 | text.add("\tName: " + module.getName()); 48 | text.add("\tVersion: " + module.getVersion()); 49 | text.add("\tFile: " + module.getCandidate().getModuleFile()); 50 | text.add("\tBypass Class: " + module.getCandidate().getBypassClass()); 51 | text.add("\tCore Module Class: " + module.getCandidate().getCorePluginClass()); 52 | text.add("\tOwned Packages: "); 53 | for (String pack : module.getCandidate().getClassEntries()) 54 | text.add("\t\t" + pack); 55 | 56 | HashMap customData = module.getModule().getCustomData(); 57 | if (customData != null) { 58 | text.add("\tCustom Data: "); 59 | for (Map.Entry entry : customData.entrySet()) 60 | text.add("\t\t" + entry.getKey() + ": " + entry.getValue()); 61 | } 62 | } catch (Throwable e) { 63 | text.add(module.getClass().getCanonicalName() + " could not be logged. (" + e.getLocalizedMessage() + ")"); 64 | } 65 | } 66 | 67 | return text; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /patches_full/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /patches/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/log/SysLogProxy.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.log; 2 | 3 | import jaci.openrio.toast.core.ToastBootstrap; 4 | 5 | import java.io.File; 6 | import java.io.FileOutputStream; 7 | import java.io.PrintStream; 8 | 9 | /** 10 | * A utility class to attach system.out and system.err into {@link jaci.openrio.toast.lib.log.SplitStream} to 11 | * a file and to the standard streams 12 | * 13 | * @author Jaci 14 | */ 15 | public class SysLogProxy { 16 | 17 | static PrintStream sysOut; 18 | static PrintStream sysErr; 19 | 20 | public static FileOutputStream fileOut; 21 | public static FileOutputStream fileErr; 22 | public static PrintStream outStream; 23 | public static PrintStream errStream; 24 | public static File logDir; 25 | public static File recentOut; 26 | public static File oldOut; 27 | public static File recentErr; 28 | public static SplitStream master; 29 | public static SplitStream masterError; 30 | 31 | static boolean init = false; 32 | 33 | /** 34 | * Initialize the proxy if it has not already been started. This splits the System.out and System.err streams 35 | * to Files in the filesystem. 36 | */ 37 | public static void init() { 38 | try { 39 | if (!init) { 40 | init = true; 41 | logDir = new File(ToastBootstrap.toastHome, "log"); 42 | logDir.mkdirs(); 43 | 44 | recentOut = new File(logDir, "recent.txt"); 45 | recentErr = new File(logDir, "recentErr.txt"); 46 | 47 | if (recentOut.exists()) { 48 | oldOut = new File(logDir, "last_session.txt"); 49 | if (oldOut.exists()) oldOut.delete(); 50 | recentOut.renameTo(oldOut); 51 | recentOut = new File(logDir, "recent.txt"); 52 | recentOut.delete(); 53 | } 54 | 55 | if (recentErr.exists()) 56 | recentErr.delete(); 57 | 58 | fileOut = new FileOutputStream(recentOut); 59 | fileErr = new FileOutputStream(recentErr); 60 | 61 | sysOut = System.out; 62 | sysErr = System.err; 63 | 64 | master = new SplitStream(sysOut, fileOut); 65 | outStream = new ColorPrint(master); 66 | masterError = new SplitStream(sysErr, fileOut, fileErr); 67 | errStream = new ColorPrint(masterError); 68 | 69 | System.setOut(outStream); 70 | System.setErr(errStream); 71 | } 72 | } catch (Exception e) { 73 | System.err.println("System Log Proxy failed..."); 74 | e.printStackTrace(); 75 | } 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/network/ToastSessionJoiner.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.network; 2 | 3 | import jaci.openrio.delegate.DelegateClient; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.DataOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.util.Scanner; 10 | 11 | /** 12 | * The SessionJoiner acts as an interface between Toast and.. well... Toast. Calling toast with the --join arguments 13 | * will attempt to join the Toast console on the local host, useful for when you SSH into the RoboRIO. 14 | * 15 | * @author Jaci 16 | */ 17 | public class ToastSessionJoiner { 18 | 19 | static DelegateClient LOGGER_DELEGATE; 20 | static DelegateClient COMMAND_DELEGATE; 21 | 22 | static DataOutputStream commands_out; 23 | static BufferedReader logger_in; 24 | 25 | /** 26 | * Start the joiner. This simply connects to the designated Toast instance on localhost and 27 | * creates a logger and command bus bridge. 28 | */ 29 | public static void init() { 30 | LOGGER_DELEGATE = new DelegateClient("localhost", 5805, "TOAST_logger"); 31 | COMMAND_DELEGATE = new DelegateClient("localhost", 5805, "TOAST_command"); 32 | 33 | try { 34 | LOGGER_DELEGATE.connect(); 35 | COMMAND_DELEGATE.connect(); 36 | 37 | commands_out = new DataOutputStream(COMMAND_DELEGATE.getSocket().getOutputStream()); 38 | logger_in = new BufferedReader(new InputStreamReader(LOGGER_DELEGATE.getSocket().getInputStream())); 39 | 40 | new Thread(new Runnable() { 41 | @Override 42 | public void run() { 43 | String line; 44 | try { 45 | while ((line = logger_in.readLine()) != null) { 46 | System.out.println(line); 47 | } 48 | } catch (IOException e) { 49 | System.err.println("Unexpected error while reading from Logger Delegate"); 50 | e.printStackTrace(); 51 | System.exit(-1); 52 | } 53 | } 54 | }).start(); 55 | 56 | Scanner scanner = new Scanner(System.in); 57 | while (true) { 58 | String line = scanner.nextLine(); 59 | if (line.trim().equalsIgnoreCase("--exit")) 60 | System.exit(0); 61 | commands_out.writeBytes(line + "\n"); 62 | } 63 | } catch (Exception e) { 64 | System.err.println("Something went wrong while establishing a connection to the Toast instance..."); 65 | e.printStackTrace(); 66 | System.exit(-1); 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/util/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.util; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.Vector; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * Miscellaneous utilities used by Toast and modules. These Utilities provide common shorthand and utilities 10 | * for a range of purposes. 11 | * 12 | * @author Jaci 13 | */ 14 | public class ToastUtil { 15 | 16 | /** 17 | * Checks if a given object is included in an Array of objects. 18 | * 19 | * @return True if 'target' is an element of 'arr' 20 | */ 21 | public static boolean contains(Object[] arr, Object target) { 22 | for (Object a : arr) 23 | if (a.equals(target)) return true; 24 | return false; 25 | } 26 | 27 | /** 28 | * Will find the greatest-common package(s) of an array of packages or class names. 29 | * This checks from the root package and works upwards, i.e. 'jaci.openrio.test' and 'jaci.openrio.anothertest' 30 | * would yield 'jaci.openrio'. 31 | * 32 | * When the root package differs in the array, multiple common packages are declared, for example, the package set: 33 | * jaci.openrio.test 34 | * jaci.openrio.anothertest 35 | * something.your.test 36 | * something.your.anothertest 37 | * 38 | * Will yield the return: 39 | * jaci.openrio 40 | * something.your 41 | * 42 | * This is used in module candidation to check what packages a module owns without keeping a list of all 43 | * it's classes which can become memory-inefficient for large included libraries such as Apache Commons, Guava or 44 | * JRuby. 45 | * 46 | * @param packages the list of packages to reduce 47 | * @return The reduced list of common package(s) 48 | */ 49 | public static List findCommonPkgs(List packages) { 50 | List common = new Vector(); 51 | 52 | for (String pack : packages) { 53 | String[] spl = pack.split("\\."); 54 | boolean fnd = false; 55 | for (int i = 0; i < common.size(); i++) { 56 | String[] com = common.get(i); 57 | if (com[0].equals(spl[0])) { // Root package is equal -> continue 58 | common.set(i, Arrays.stream(spl) 59 | .filter(b -> contains(com, b)) 60 | .toArray(String[]::new)); // Reduce the current common package to the greatest common package 61 | fnd = true; 62 | } 63 | } 64 | if (!fnd) common.add(spl); // No root package found, treat as new common package 65 | } 66 | 67 | return common.stream() 68 | .map(b -> String.join(".", b)) 69 | .collect(Collectors.toList()); // Convert the String[] values into a single, period delimited package id 70 | } 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/lib/log/SplitStream.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.lib.log; 2 | 3 | import jaci.openrio.toast.lib.util.Pretty; 4 | 5 | import java.io.IOException; 6 | import java.io.OutputStream; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | 10 | /** 11 | * Acts as a splitter for {@link java.io.OutputStream} objects, splitting the output 12 | * between all the given instances in the constructor 13 | * 14 | * @author Jaci 15 | */ 16 | public class SplitStream extends OutputStream { 17 | 18 | ArrayList outs; 19 | 20 | public SplitStream(OutputStream... streams) { 21 | this.outs = new ArrayList<>(Arrays.asList(streams)); 22 | } 23 | 24 | /** 25 | * Add an output stream to the splitstream. Use this to delegate logger and 26 | * system.out output to your own handler or file. 27 | */ 28 | public void add(OutputStream stream) { 29 | outs.add(stream); 30 | } 31 | 32 | /** 33 | * Write a single byte to all the output streams created for this SplitStream 34 | */ 35 | @Override 36 | public void write(int b) throws IOException { 37 | for (OutputStream stream : outs) 38 | stream.write(b); 39 | } 40 | 41 | /** 42 | * Write a byte array to all the output streams created for this SplitStream 43 | */ 44 | @Override 45 | public void write(byte b[]) throws IOException { 46 | for (OutputStream stream : outs) 47 | stream.write(b); 48 | } 49 | 50 | /** 51 | * Write a byte array with the offset and length given in this method to all 52 | * output streams created for this SplitStream 53 | */ 54 | @Override 55 | public void write(byte b[], int off, int len) throws IOException { 56 | for (OutputStream stream : outs) { 57 | stream.write(b, off, len); 58 | } 59 | } 60 | 61 | /** 62 | * Flush the output streams registered for this SplitStream 63 | */ 64 | @Override 65 | public void flush() throws IOException { 66 | for (OutputStream stream : outs) 67 | stream.flush(); 68 | } 69 | 70 | /** 71 | * Close this stream and all it's children output streams. 72 | */ 73 | @Override 74 | public void close() throws IOException { 75 | for (OutputStream stream : outs) 76 | stream.close(); 77 | } 78 | 79 | /** 80 | * Print a color stream. This outputs color to the first output, but an escaped version to everything else 81 | * so your files don't get weird escape chars in them. 82 | */ 83 | public void color(String s) throws IOException { 84 | outs.get(0).write(s.getBytes()); 85 | String noc = Pretty.strip(s); 86 | for (int i = 1; i < outs.size(); i++) { 87 | OutputStream stream = outs.get(i); 88 | if (stream instanceof ColorPrint.ColorStream) 89 | stream.write(s.getBytes()); 90 | else 91 | stream.write(noc.getBytes()); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/shared/OptionParser.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.shared; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.function.Consumer; 6 | 7 | public class OptionParser { 8 | 9 | public static class Handler { 10 | public String flagS, flagL, desc; 11 | public Consumer> callback; 12 | public int expected; 13 | } 14 | 15 | public List handlers; 16 | 17 | public OptionParser(boolean exitOnHelp) { 18 | handlers = new ArrayList<>(); 19 | on("-h", "--help", "Display Help Message", 0, (list) -> { 20 | System.out.println(helpMessage()); 21 | if (exitOnHelp) System.exit(0); 22 | }); 23 | } 24 | 25 | public List parse(String[] args) { 26 | List passable = new ArrayList<>(); 27 | final int[] index = new int[1]; // Needs to be a final array to be modified inside loop 28 | for (index[0] = 0; index[0] < args.length; index[0]++) { 29 | int startI = index[0]; 30 | String argument = args[index[0]]; 31 | handlers.stream().forEach(handler -> { 32 | if (argument.equals(handler.flagL) || argument.equals(handler.flagS)) { 33 | int exp = handler.expected; 34 | List cbPass = new ArrayList(); 35 | for (int expIdx = startI + 1; expIdx < (startI + 1 + exp) && expIdx < args.length; expIdx++) { 36 | cbPass.add(args[expIdx]); 37 | } 38 | handler.callback.accept(cbPass); 39 | index[0] += exp; 40 | } 41 | }); 42 | if (startI == index[0]) passable.add(argument); 43 | } 44 | return passable; 45 | } 46 | 47 | public List parse(String args, String delim) { 48 | return parse(args.split(delim)); 49 | } 50 | 51 | public List parse(String args) { 52 | return parse(args, " "); 53 | } 54 | 55 | public void on(String flagShort, String flagLong, String flagDescription, int expected, Consumer> callback) { 56 | Handler h = new Handler(); 57 | h.flagS = flagShort; 58 | h.flagL = flagLong; 59 | h.desc = flagDescription; 60 | h.callback = callback; 61 | h.expected = expected; 62 | handlers.add(h); 63 | } 64 | 65 | public void on(String flag, String description, int expected, Consumer> callback) { 66 | on(null, flag, description, expected, callback); 67 | } 68 | 69 | public String helpMessage() { 70 | List list = new ArrayList<>(); 71 | 72 | for (Handler handler : handlers) { 73 | if (handler.flagS != null) { 74 | list.add(String.format("\t %-7s %15s \t-- %10s", handler.flagS, handler.flagL, handler.desc)); 75 | } else { 76 | list.add(String.format("\t %-7s %15s \t-- %10s", "", handler.flagL, handler.desc)); 77 | } 78 | } 79 | 80 | return String.join("\n", list); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/srx/GuiSRX.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation.srx; 2 | 3 | import com.ctre.CANTalon; 4 | import jaci.openrio.toast.core.loader.simulation.GuiNumberSpinner; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | 9 | public class GuiSRX extends JComponent { 10 | 11 | int x, y; 12 | SRX_Reg.SRX_Wrapper wrapper; 13 | static Color enabled = new Color(20, 200, 20); 14 | static Color disabled = new Color(200, 20, 20); 15 | static Color graytext = new Color(140, 140, 140); 16 | 17 | JLabel control_mode, slotid, follower, speed, position; 18 | GuiNumberSpinner pvbus, voltage; 19 | 20 | public GuiSRX(int x, int y, SRX_Reg.SRX_Wrapper wrapper, JPanel parent) { 21 | this.x = x; this.y = y; this.wrapper = wrapper; 22 | this.setBounds(x, y, 500, 150); 23 | parent.add(this); 24 | 25 | createLabel("SRX: " + wrapper.dev_id, 0, 10, 100, 20, new Color(200, 200, 200)); 26 | control_mode = createLabel("", 10, 30, 200, 14, graytext); 27 | slotid = createLabel("", 10, 50, 200, 14, graytext); 28 | follower = createLabel("", 10, 70, 200, 14, graytext); 29 | speed = createLabel("", 230, 70, 200, 14, graytext); 30 | position = createLabel("", 230, 90, 200, 14, graytext); 31 | 32 | createLabel("Throttle: ", 230, 30, 70, 14, graytext); 33 | pvbus = new GuiNumberSpinner(300, 35, 0, 0, -1, 1, false, this).enableProgress().setFontSize(14); 34 | 35 | createLabel("Voltage: ", 230, 50, 70, 14, graytext); 36 | voltage = new GuiNumberSpinner(300, 55, 0, 0, -12, 12, false, this).enableProgress().setFontSize(14); 37 | 38 | wrapper.onUpdate(this::update); 39 | update(); 40 | } 41 | 42 | /** 43 | * On Talon Update 44 | */ 45 | public void update() { 46 | if (wrapper != null) { 47 | control_mode.setText("Control Mode: " + CANTalon.TalonControlMode.valueOf(wrapper.mode).toString()); 48 | slotid.setText("Slot ID: " + wrapper.slotid); 49 | follower.setText("Following: " + wrapper.follower); 50 | 51 | pvbus.setValue(wrapper.pvbus); 52 | voltage.setValue(wrapper.voltage); 53 | speed.setText("Speed Delta: " + wrapper.speed); 54 | position.setText("Position Delta: " + wrapper.position); 55 | } 56 | repaint(); 57 | } 58 | 59 | /** 60 | * Paint the component on the GUI 61 | */ 62 | public void paintComponent(Graphics g) { 63 | super.paintComponent(g); 64 | paint((Graphics2D) g); 65 | } 66 | 67 | /** 68 | * Paints the component with the Graphics2D instance. This is used to paint our graphics manually. 69 | * This is called once per refresh 70 | */ 71 | public void paint(Graphics2D g) { 72 | 73 | } 74 | 75 | /** 76 | * Create a JLabel to place next to various components. 77 | */ 78 | public JLabel createLabel(String text, int x, int y, int width, int fontSize, Color color) { 79 | JLabel label = new JLabel(text); 80 | label.setForeground(color); 81 | label.setBounds(x, y, width, 20); 82 | label.setFont(new Font("Arial", 0, fontSize)); 83 | this.add(label); 84 | return label; 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/network/CommandDelegate.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.network; 2 | 3 | import jaci.openrio.delegate.BoundDelegate; 4 | import jaci.openrio.delegate.Security; 5 | import jaci.openrio.toast.core.ToastConfiguration; 6 | import jaci.openrio.toast.core.command.CommandBus; 7 | 8 | import java.io.BufferedReader; 9 | import java.io.InputStreamReader; 10 | import java.net.Socket; 11 | 12 | /** 13 | * A one-way delegate for the Command Line. This Delegate will only receive messages and will interpret them as commands. 14 | * No data will be sent to the client from this delegate. To read the output log, it's recommended to use the {@link jaci.openrio.toast.core.network.LoggerDelegate} 15 | * 16 | * DelegateID: "TOAST_command" 17 | * 18 | * @author Jaci 19 | */ 20 | public class CommandDelegate implements BoundDelegate.ConnectionCallback { 21 | 22 | static BoundDelegate server; 23 | 24 | /** 25 | * Initialize the Delegate. This registers the delegate on the SocketManager, as well as configures it if a 26 | * password or hash-type is provided in the Toast Configuration files. This is already called by Toast, so it is 27 | * not necessary to call this method yourself. 28 | */ 29 | public static void init() { 30 | server = SocketManager.register("TOAST_command"); 31 | String pass = ToastConfiguration.Property.COMMANDS_DELEGATE_PASSWORD.asString(); 32 | String algorithm = ToastConfiguration.Property.COMMANDS_DELEGATE_ALGORITHM.asString(); 33 | if (pass != null && !pass.equals("")) { 34 | if (algorithm != null && Security.HashType.match(algorithm) != null) 35 | server.setPassword(pass, Security.HashType.match(algorithm)); 36 | else 37 | server.setPassword(pass); 38 | } 39 | CommandDelegate instance = new CommandDelegate(); 40 | server.callback(instance); 41 | } 42 | 43 | /** 44 | * Called when a Client is Connected to the Socket. This is used to listen for incoming data. 45 | * @param clientSocket The socket of the Client 46 | * @param delegate The Delegate this callback is triggered on. 47 | */ 48 | @Override 49 | public void onClientConnect(Socket clientSocket, BoundDelegate delegate) { 50 | new Thread() { 51 | public void run() { 52 | this.setName("CommandDelegate"); 53 | try { 54 | BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 55 | while (true) { 56 | String line = reader.readLine(); 57 | if (line != null) 58 | CommandBus.parseMessage(line); 59 | else { 60 | try { 61 | clientSocket.close(); // Close the socket in case it hasn't been already 62 | return; 63 | } catch (Exception ignored) {} 64 | } 65 | } 66 | 67 | } catch (Throwable e) { 68 | try { 69 | clientSocket.close(); // Close the socket in case it hasn't been already 70 | } catch (Exception ignored) {} 71 | } 72 | } 73 | }.start(); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/verification/VerificationWorker.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.verification; 2 | 3 | import jaci.openrio.toast.core.Toast; 4 | import jaci.openrio.toast.core.loader.module.ModuleContainer; 5 | import jaci.openrio.toast.core.loader.module.ModuleManager; 6 | import jaci.openrio.toast.core.loader.simulation.SimulationData; 7 | import jaci.openrio.toast.lib.log.Logger; 8 | import jaci.openrio.toast.lib.state.RobotState; 9 | 10 | /** 11 | * The Verification Worker. This class is called when the Toast Jar file is launched with the arguments -vf or -verify. 12 | * This thread runs through the Disabled -> Autonomous -> Teleoperated -> End lifecycle of the robot, and if any errors 13 | * or uncaught exceptions are encountered along the way, the program will exit with error code -1. If this is launched from 14 | * gradle using 'gradlew verify', the build will fail. This class is mostly used in Travis CI builds and exists to give 15 | * a proper 'yes, this code works' requirement to a successful build instead of the typical 'there's no compile errors' 16 | * requirement, giving repos an accurate look at how the build is passing. 17 | * 18 | * @author Jaci 19 | */ 20 | public class VerificationWorker extends Thread { 21 | 22 | static VerificationWorker worker; 23 | static Logger logger; 24 | 25 | public VerificationWorker() { 26 | this.setName("Verification Worker"); 27 | } 28 | 29 | /** 30 | * Begin the Verification Routine. This is called automatically by Toast when launched with the --verify arguments 31 | */ 32 | public static void begin() { 33 | logger = new Logger("Verification", Logger.ATTR_TIME); 34 | worker = new VerificationWorker(); 35 | worker.start(); 36 | } 37 | 38 | /** 39 | * Run a single loop of the Verification Routine. 40 | */ 41 | @Override 42 | public void run() { 43 | try { 44 | logger.info("Beginning Code Verification. Echoing environmental data..."); 45 | echoEnvironment(); 46 | logger.info("Starting Code Verification in 5 seconds..."); 47 | Thread.sleep(5 * 1000); 48 | logger.info("Transferring into Autonomous... (Switching to Teleop in 15 seconds)"); 49 | SimulationData.currentState = RobotState.AUTONOMOUS; 50 | Thread.sleep(15 * 1000); 51 | logger.info("Transferring into Teleoperated... (Switching to Disabled in 1 minute)"); 52 | SimulationData.currentState = RobotState.TELEOP; 53 | Thread.sleep(60 * 1000); 54 | logger.info("Disabling Robot... (Shutting Down in 10 seconds)"); 55 | SimulationData.currentState = RobotState.DISABLED; 56 | Thread.sleep(10 * 1000); 57 | logger.info("Code Verification Successful! Shutting Down..."); 58 | Toast.getToast().shutdownSafely(); 59 | } catch (Exception e) { 60 | logger.error("Exception encountered during verification: " + e); 61 | logger.exception(e); 62 | Toast.getToast().shutdownCrash(); 63 | } 64 | } 65 | 66 | /** 67 | * Print relevant environmental data to the console. 68 | */ 69 | void echoEnvironment() { 70 | logger.info("\tLoaded Modules:"); 71 | for (ModuleContainer module : ModuleManager.getContainers()) 72 | logger.info("\t\t" + module.getDetails()); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/ToastConfiguration.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core; 2 | 3 | import jaci.openrio.toast.lib.module.ModuleConfig; 4 | 5 | /** 6 | * The configuration manager for Toast's config file. This is handled by Toast and does not concern external modules. 7 | * 8 | * @author Jaci 9 | */ 10 | public class ToastConfiguration { 11 | 12 | public static ModuleConfig config; 13 | 14 | /** 15 | * Initialize the Configuration. This creates the Preferences file 16 | * and all the properties required. 17 | */ 18 | public static void init() { 19 | config = new ModuleConfig("Toast"); 20 | for (Property prop : Property.values()) 21 | prop.read(config); 22 | } 23 | 24 | public static enum Property { 25 | THREAD_POOL_SIZE("threading.pool_size", 1), 26 | 27 | COMMANDS_DELEGATE_PASSWORD("delegate.command.password", ""), 28 | COMMANDS_DELEGATE_ALGORITHM("delegate.command.algorithm", "SHA256"), 29 | LOGGER_DELEGATE_PASSWORD("delegate.logger.password", ""), 30 | LOGGER_DELEGATE_ALGORITHM("delegate.logger.algorithm", "SHA256"), 31 | 32 | OPTIMIZATION_GC("optimization.gc.enabled", false), 33 | OPTIMIZATION_GC_TIME("optimization.gc.time", 30), 34 | 35 | SECURITY_POLICY("security.policy", "STRICT"), 36 | 37 | ROBOT_NAME("robot.name", "{ NAME NOT SET }"), 38 | ROBOT_TEAM("robot.team", -1), 39 | ROBOT_DESC("robot.desc", "{ DESCRIPTION NOT SET }"), 40 | 41 | SIM_BROADCAST_MDNS("sim.mdns.enabled", false), 42 | SIM_BROADCAST_TEAM("sim.mdns.team", "9990"), 43 | SIM_DS_ENABLED("sim.ds.enabled", true) 44 | ; 45 | 46 | String key; 47 | Object defaultValue; 48 | 49 | Object value; 50 | 51 | Property(String key, Object defaultValue) { 52 | this.key = key; 53 | this.defaultValue = defaultValue; 54 | } 55 | 56 | /** 57 | * Read the property from the ModuleConfig file, with the default value and comments 58 | * if it doesn't exist. 59 | */ 60 | public void read(ModuleConfig config) { 61 | value = config.get(key, defaultValue); 62 | } 63 | 64 | /** 65 | * Get the property as a Number object 66 | */ 67 | public Number asNumber() { 68 | return (Number) value; 69 | } 70 | 71 | /** 72 | * Get the property, casted to an Integer 73 | */ 74 | public int asInt() { 75 | return asNumber().intValue(); 76 | } 77 | 78 | /** 79 | * Get the property casted to a Double 80 | */ 81 | public double asDouble() { 82 | return asNumber().doubleValue(); 83 | } 84 | 85 | /** 86 | * Get the property, casted to a Float 87 | */ 88 | public float asFloat() { 89 | return asNumber().floatValue(); 90 | } 91 | 92 | /** 93 | * Get the property, casted to a Byte 94 | */ 95 | public byte asByte() { 96 | return asNumber().byteValue(); 97 | } 98 | 99 | /** 100 | * Get the property in String form 101 | */ 102 | public String asString() { 103 | return (String) value; 104 | } 105 | 106 | /** 107 | * Get the property as a boolean. 108 | */ 109 | public boolean asBoolean() { 110 | return (boolean) value; 111 | } 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/srx/TalonSRX_GUI.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation.srx; 2 | 3 | import jaci.openrio.toast.core.loader.simulation.CommonGUI; 4 | import jaci.openrio.toast.core.loader.simulation.GuiScrollbar; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.awt.event.WindowAdapter; 9 | import java.awt.event.WindowEvent; 10 | 11 | public class TalonSRX_GUI extends JPanel { 12 | 13 | public static TalonSRX_GUI INSTANCE; 14 | 15 | public static JPanel create() { 16 | JFrame frame = new JFrame("Toast CAN Talon SRX GUI"); 17 | JPanel panel = new TalonSRX_GUI(); 18 | frame.add(panel); 19 | frame.pack(); 20 | frame.setLocationRelativeTo(null); 21 | frame.setVisible(true); 22 | frame.setResizable(true); 23 | frame.setMinimumSize(new Dimension(600, 400)); 24 | frame.addWindowListener(new WindowAdapter() { 25 | @Override 26 | public void windowOpened(WindowEvent e) { 27 | super.windowOpened(e); 28 | } 29 | 30 | @Override 31 | public void windowClosing(WindowEvent e) { 32 | super.windowClosing(e); 33 | INSTANCE = null; 34 | } 35 | }); 36 | 37 | return panel; 38 | } 39 | 40 | public TalonSRX_GUI() { 41 | INSTANCE = this; 42 | 43 | this.setBackground(new Color(11, 11, 11)); 44 | this.setPreferredSize(new Dimension(600, 500)); 45 | this.setLayout(new BorderLayout()); 46 | this.setVisible(true); 47 | 48 | CommonGUI.setup_keys(this, this::reinitElements); 49 | 50 | initElements(); 51 | } 52 | 53 | /** 54 | * Completely reinflate the GUI. This replaces all JComponents in the GUI. 55 | */ 56 | public void reinitElements() { 57 | this.removeAll(); 58 | initElements(); 59 | } 60 | 61 | 62 | /** 63 | * Inflate the GUI. This does everything from adding all the elements, to adding the background image and setting up 64 | * the GUI. This is where most of the work is done, and is only called once: upon creation of the GUI. 65 | */ 66 | public void initElements() { 67 | JPanel viewcontroller = new JPanel(); 68 | int pref_height = 10; 69 | viewcontroller.setVisible(true); 70 | viewcontroller.setLayout(null); 71 | viewcontroller.setBackground(new Color(11, 11, 11)); 72 | 73 | JScrollPane pane = new JScrollPane(viewcontroller); 74 | pane.setBorder(null); 75 | pane.getVerticalScrollBar().setUI(new GuiScrollbar()); 76 | pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 77 | 78 | int i = 0; 79 | for (SRX_Reg.SRX_Wrapper wrapper : SRX_Reg.wrappers.values()) { 80 | viewcontroller.add(new GuiSRX(50, 10 + 120 * i, wrapper, viewcontroller)); 81 | pref_height += 120; 82 | i++; 83 | } 84 | viewcontroller.setPreferredSize(new Dimension(600, pref_height)); 85 | 86 | this.add(pane); 87 | } 88 | 89 | /** 90 | * Paint the component on the GUI 91 | */ 92 | public void paintComponent(Graphics g) { 93 | super.paintComponent(g); 94 | paint((Graphics2D) g); 95 | } 96 | 97 | /** 98 | * Paints the component with the Graphics2D instance. This is used to paint our graphics manually. 99 | * This is called once per refresh 100 | */ 101 | public void paint(Graphics2D g) { 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/GuiPCM.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | 6 | public class GuiPCM extends JComponent { 7 | 8 | int x, y, pcmid; 9 | 10 | Color enabled = new Color(20, 200, 20); 11 | Color disabled = new Color(200, 20, 20); 12 | Color graytext = new Color(140, 140, 140); 13 | JLabel compressor_mode; 14 | 15 | public GuiPCM(int x, int y, int pcmid, JPanel parent) { 16 | this.x = x; 17 | this.y = y; 18 | this.pcmid = pcmid; 19 | this.setBounds(x, y, 400, 100); 20 | parent.add(this); 21 | 22 | createLabel("Pneumatics Control Module " + pcmid, 10, 0, 200, 14, new Color(180, 180, 180)); 23 | createLabel("Compressor: ", 15, 15, 100, 12, graytext); 24 | boolean run = SimulationData.compressorRunning((byte) pcmid); 25 | compressor_mode = createLabel(run ? "Running" : "Off", 100, 30, 75, 12, run ? enabled : graytext); 26 | 27 | createLabel("Current: ", 15, 45, 100, 12, graytext); 28 | new GuiNumberSpinner(100, 50, 5, 0.5, 0, 11, true, this).setCallback(value -> { 29 | SimulationData.compressor_current[pcmid] = (float) value; 30 | }); 31 | 32 | createLabel("Control Loop: ", 15, 60, 100, 12, graytext); 33 | 34 | new GuiButton(15, 80, 100, 20, SimulationData.compressor_pressure[pcmid], "Pressure Switch", true, this).setCallback(new GuiButton.ButtonCallback() { 35 | @Override 36 | public void onClick() { } 37 | 38 | @Override 39 | public void onToggle(boolean state) { 40 | SimulationData.setCompressorPressureSwitch((byte) pcmid, state); 41 | } 42 | }); 43 | 44 | createLabel("Solenoids: ", 200, 15, 100, 12, new Color(150, 150, 150)); 45 | 46 | } 47 | 48 | /** 49 | * Paint the component on the GUI 50 | */ 51 | public void paintComponent(Graphics g) { 52 | super.paintComponent(g); 53 | paint((Graphics2D) g); 54 | } 55 | 56 | /** 57 | * Paints the component with the Graphics2D instance. This is used to paint our graphics manually. 58 | * This is called once per refresh 59 | */ 60 | public void paint(Graphics2D g) { 61 | if (SimulationData.enabled_compressors[pcmid]) g.setColor(enabled); 62 | else g.setColor(disabled); 63 | g.fillRect(100, 21, 15, 10); 64 | 65 | if (SimulationData.loop_compressors[pcmid]) g.setColor(enabled); 66 | else g.setColor(disabled); 67 | 68 | g.fillRect(100, 66, 15, 10); 69 | 70 | boolean run = SimulationData.compressorRunning((byte) pcmid); 71 | compressor_mode.setText(run ? "Running" : "Off"); 72 | compressor_mode.setForeground(run ? enabled : graytext); 73 | 74 | int sc = 0; 75 | for (int j = 0; j < 2; j++) 76 | for (int i = 0; i < 4; i++) { 77 | g.setColor(graytext); 78 | g.drawString("" + sc, 240 + (j * 40), 45 + (17 * i)); 79 | boolean en = SimulationData.solenoids[pcmid][sc]; 80 | g.setColor(en ? enabled : disabled); 81 | g.fillRect(220 + (j * 40), 35 + (17 * i), 15, 10); 82 | sc++; 83 | } 84 | } 85 | 86 | /** 87 | * Create a JLabel to place next to various components. 88 | */ 89 | public JLabel createLabel(String text, int x, int y, int width, int fontSize, Color color) { 90 | JLabel label = new JLabel(text); 91 | label.setForeground(color); 92 | label.setBounds(x, y, width, 20); 93 | label.setFont(new Font("Arial", 0, fontSize)); 94 | this.add(label); 95 | return label; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/jni/InterruptContainer.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation.jni; 2 | 3 | import edu.wpi.first.wpilibj.hal.InterruptJNI; 4 | import jaci.openrio.toast.core.ToastBootstrap; 5 | 6 | import java.util.Vector; 7 | 8 | /** 9 | * A container object for what would be a DIO Interrupt. Because this is a simulation, we have to simulate the interrupt 10 | * 11 | * @author Jaci 12 | */ 13 | public class InterruptContainer { 14 | 15 | public static Vector interrupts = new Vector<>(); 16 | 17 | private int index; 18 | private InterruptJNI.InterruptJNIHandlerFunction func; 19 | private Object funcParam; 20 | private boolean triggerRising = true, triggerFalling = false; 21 | private boolean enabled = true; 22 | 23 | private long risingTime, fallingTime; 24 | 25 | private int pin; 26 | 27 | public InterruptContainer() { 28 | interrupts.add(this); 29 | } 30 | 31 | /** 32 | * Set the DIO pin of the interrupt 33 | */ 34 | public void setPin(int p) { 35 | this.pin = p; 36 | } 37 | 38 | /** 39 | * @return The DIO pin of the interrupt 40 | */ 41 | public int getPin() { 42 | return pin; 43 | } 44 | 45 | /** 46 | * Get an InterruptContainer for the given DIO Port. Return null if not 47 | * registered 48 | */ 49 | public static InterruptContainer getByPin(int p) { 50 | for (InterruptContainer cont : interrupts) { 51 | if (cont.pin == p) return cont; 52 | } 53 | return null; 54 | } 55 | 56 | /** 57 | * Blocks the current thread until an interrupt is detected. Try not to do this in the main thread, as it will 58 | * cause the Thread to be blocked until the timeout period is over 59 | */ 60 | public synchronized void waitForInterrupt(double timeout) { 61 | try { 62 | wait((long) (timeout * 1000)); 63 | } catch (Exception e) { 64 | } 65 | } 66 | 67 | /** 68 | * Enable the Interrupt 69 | */ 70 | public void setEnabled(boolean s) { 71 | this.enabled = s; 72 | } 73 | 74 | /** 75 | * Get the container for the given Pointer ID 76 | */ 77 | public static InterruptContainer getByIndex(int index) { 78 | return interrupts.get(index); 79 | } 80 | 81 | /** 82 | * Setup which phase the interrupt triggers on 83 | */ 84 | public void setup(boolean triggerRising, boolean triggerFalling) { 85 | this.triggerRising = triggerRising; 86 | this.triggerFalling = triggerFalling; 87 | } 88 | 89 | /** 90 | * Set the Interrupt callback 91 | */ 92 | public void setFunc(InterruptJNI.InterruptJNIHandlerFunction func, Object param) { 93 | this.func = func; 94 | this.funcParam = param; 95 | } 96 | 97 | /** 98 | * Trigger the interrupt 99 | */ 100 | public synchronized void trigger(boolean isRising) { 101 | if (!enabled) 102 | return; 103 | 104 | if (isRising) 105 | risingTime = System.currentTimeMillis(); 106 | else 107 | fallingTime = System.currentTimeMillis(); 108 | 109 | if (isRising && triggerRising || !isRising && triggerFalling) { 110 | if (func != null) 111 | func.apply(interrupts.indexOf(this), funcParam); 112 | 113 | notifyAll(); 114 | } 115 | } 116 | 117 | /** 118 | * Get the Timestamp of the trigger 119 | */ 120 | public long getTime(boolean isRising) { 121 | long t = isRising ? risingTime : fallingTime; 122 | t -= ToastBootstrap.startTimeMS; 123 | return t / 1000; 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/GuiRobotState.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation; 2 | 3 | import jaci.openrio.toast.lib.state.RobotState; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | import java.awt.event.MouseEvent; 8 | import java.awt.event.MouseListener; 9 | import java.awt.geom.Rectangle2D; 10 | 11 | /** 12 | * A GUI Element for switching the Robot State during Simulation 13 | * 14 | * @author Jaci 15 | */ 16 | public class GuiRobotState extends JComponent implements MouseListener { 17 | 18 | RobotState state; 19 | int x, y; 20 | int width = 100; 21 | int height = 30; 22 | 23 | static final Color bgPassive = new Color(20, 20, 20); 24 | static final Color bgClicked = new Color(11, 11, 11); 25 | static final Color fgPassive = new Color(100, 100, 100); 26 | 27 | public GuiRobotState(int x, int y, RobotState state, JPanel parent) { 28 | this.x = x; 29 | this.y = y; 30 | this.state = state; 31 | this.setBounds(x, y, width, height); 32 | parent.add(this); 33 | parent.addMouseListener(this); 34 | 35 | this.setBackground(bgPassive); 36 | this.setForeground(fgPassive); 37 | } 38 | 39 | /** 40 | * Paints the component. This calls the super as well as calling the second 'paint()' method that will 41 | * draw the button based on the state given in {@link SimulationData} 42 | */ 43 | public void paintComponent(Graphics g) { 44 | super.paintComponent(g); 45 | paint((Graphics2D) g); 46 | } 47 | 48 | /** 49 | * Paints the object with the new Graphics2D object. This takes data from the {@link SimulationData} class in order 50 | * to paint the correct button. 51 | */ 52 | public void paint(Graphics2D g) { 53 | g.setColor(this.getBackground()); 54 | g.fillRect(0, 0, width, height); 55 | g.setColor(SimulationData.currentState == state ? new Color(100, 170, 100) : this.getForeground()); 56 | FontMetrics metrics = g.getFontMetrics(); 57 | Rectangle2D textBounds = metrics.getStringBounds(state.state, g); 58 | g.drawString(state.state, (float) ((width - textBounds.getWidth()) / 2), (float) ((height - textBounds.getHeight()) / 2 + metrics.getAscent())); 59 | } 60 | 61 | /** 62 | * Does a check for whether or not the Mouse exists within the bounds of the button. 63 | */ 64 | public boolean inBounds(MouseEvent e) { 65 | return e.getX() > x && e.getX() < x + width && e.getY() > y && e.getY() < y + height; 66 | } 67 | 68 | /** 69 | * Apply this button 70 | */ 71 | public void apply() { 72 | SimulationData.currentState = this.state; 73 | repaint(); 74 | } 75 | 76 | /** 77 | * Stub Method - Not Used 78 | */ 79 | @Override 80 | public void mouseClicked(MouseEvent e) { 81 | } 82 | 83 | /** 84 | * Serves to change the colour of the button to indicate it being depressed. 85 | */ 86 | @Override 87 | public void mousePressed(MouseEvent e) { 88 | if (inBounds(e)) { 89 | this.setBackground(bgClicked); 90 | } 91 | this.repaint(); 92 | } 93 | 94 | /** 95 | * Invokes the new state change 96 | */ 97 | @Override 98 | public void mouseReleased(MouseEvent e) { 99 | if (inBounds(e)) 100 | apply(); 101 | 102 | this.setBackground(bgPassive); 103 | this.repaint(); 104 | } 105 | 106 | /** 107 | * Stub Method - Not Used 108 | */ 109 | @Override 110 | public void mouseEntered(MouseEvent e) { 111 | } 112 | 113 | /** 114 | * Stub Method - Not Used 115 | */ 116 | @Override 117 | public void mouseExited(MouseEvent e) { 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/loader/simulation/jni/SimulatedJoystick.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.loader.simulation.jni; 2 | 3 | /** 4 | * An instance of a Simulated Joystick Controller. This is used to simulate joystick control in a simulation environment, 5 | * as the default FRC driver station does not work in Simulated Environments. 6 | * 7 | * @author Jaci 8 | */ 9 | public class SimulatedJoystick { 10 | 11 | int buttonCount; 12 | boolean[] buttons; 13 | double[] axisV; 14 | int[] povs; 15 | 16 | public SimulatedJoystick(int buttonCount, int axisCount, int povCount) { 17 | this.buttonCount = buttonCount; 18 | this.buttons = new boolean[buttonCount]; 19 | axisV = new double[axisCount]; 20 | povs = new int[povCount]; 21 | for (int i = 0; i < povCount; i++) 22 | povs[i] = -1; 23 | } 24 | 25 | /** 26 | * Set the given button id (0-indexed) to true or false 27 | */ 28 | public void setButton(int button, boolean state) { 29 | buttons[button] = state; 30 | } 31 | 32 | /** 33 | * Get the Simulated Button states set with the {@link #setButton(int, boolean)} method 34 | */ 35 | public boolean[] getButtons() { 36 | return buttons; 37 | } 38 | 39 | /** 40 | * Set the POV value on the given ID. This usually consists of 8 settings (0..7) indexed from "Up" 41 | */ 42 | public void setPOV(int id, int value) { 43 | povs[id] = value; 44 | } 45 | 46 | /** 47 | * Get the Simulated POV values set with the {@link #setPOV(int, int)} method 48 | */ 49 | public int[] getPOVs() { 50 | return povs; 51 | } 52 | 53 | /** 54 | * Get the specified POV value set with {@link #setPOV(int, int)} 55 | */ 56 | public int getPOV(int id) { 57 | return povs[id]; 58 | } 59 | 60 | /** 61 | * Set the given Axis ID with the specified value (usually from -1..1). This changes per Joystick type 62 | */ 63 | public void setAxis(int axis, double value) { 64 | axisV[axis] = value; 65 | } 66 | 67 | /** 68 | * Get the collective values of every axis. This is from the values set with {@link #setAxis(int, double)} 69 | */ 70 | public double[] getAxis() { 71 | return axisV; 72 | } 73 | 74 | /** 75 | * Get a specified axis defined in {@link #setAxis(int, double)} 76 | */ 77 | public double getAxis(int axis) { 78 | return axisV[axis]; 79 | } 80 | 81 | /** 82 | * Encode all the Axis to a short system that can be read by WPILib. This is to a resolution of 128 in either 83 | * direction. 84 | */ 85 | public short[] encodeAxis() { //encodes to Short values to be read by WPILib 86 | short[] vals = new short[axisV.length]; 87 | for (int i = 0; i < vals.length; i++) { 88 | vals[i] = (short) (axisV[i] * 127); 89 | } 90 | return vals; 91 | } 92 | 93 | /** 94 | * Encode the POV to a short system that WPILib can read and parse into it's Joystick class. 95 | */ 96 | public short[] encodePOV() { 97 | short[] vals = new short[povs.length]; 98 | for (int i = 0; i < vals.length; i++) 99 | vals[i] = (short) povs[i]; 100 | return vals; 101 | } 102 | 103 | /** 104 | * Encode the buttons into a single integer, where each bit of the 32 bit sequence defines a button state. 105 | */ 106 | public int encodeButtons() { //encodes to 0b000000000000 Where each digit can be an on/off state 107 | int base = 0x0; 108 | for (int i = buttonCount - 1; i >= 0; i--) { 109 | base = base << 1; 110 | base = base | (buttons[i] ? 0b1 : 0b0); 111 | } 112 | return base; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/jaci/openrio/toast/core/thread/Async.java: -------------------------------------------------------------------------------- 1 | package jaci.openrio.toast.core.thread; 2 | 3 | import jaci.openrio.toast.core.ToastConfiguration; 4 | 5 | import java.util.concurrent.*; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | /** 9 | * The Toast Asynchronous Thread Pool. This class acts as a task-scheduling system, in which tasks can be submitted for 10 | * work and will be completed when available. By default, the Thread Pool will launch 4 tasks at a time, and when each is 11 | * complete it will schedule the next. This can be changed in the Toast.conf file. 12 | * 13 | * Async Tasks have no guarantee for when they complete, and so this should be used for time-insensitive tasks. If you 14 | * rely on getting a return value or something similar of a Task, a Future is provided so you can 'wait' for the task to 15 | * be scheduled and finished. 16 | * 17 | * @author Jaci 18 | */ 19 | public class Async extends ThreadPoolExecutor { 20 | 21 | public static Async INSTANCE; 22 | 23 | /** 24 | * Start the main Async INSTANCE. This is done for you in Toast initialization. 25 | */ 26 | public static void init() { 27 | int size = ToastConfiguration.Property.THREAD_POOL_SIZE.asInt(); 28 | INSTANCE = new Async(size, size, "Toast|Async"); 29 | } 30 | 31 | /** 32 | * Create a new Async pool for you own usage 33 | * @param corePoolSize The starting size of the pool 34 | * @param maximumPoolSize The maximum size of the pool 35 | * @param name The name of the pool 36 | */ 37 | public Async(int corePoolSize, int maximumPoolSize, String name) { 38 | super(corePoolSize, maximumPoolSize, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), new Factory(name)); 39 | } 40 | 41 | /** 42 | * Submit a task to this Async pool. Calls the {@link AsyncTask#onAddedToQueue(Async, Future)} method 43 | */ 44 | public Future submit(AsyncTask task) { 45 | Future f = submit((Runnable)task); 46 | task.onAddedToQueue(this, f); 47 | return f; 48 | } 49 | 50 | /** 51 | * Submit a task to the default Async pool. Calls the {@link AsyncTask#onAddedToQueue(Async, Future)} method 52 | */ 53 | public static Future schedule(AsyncTask task) { 54 | return INSTANCE.submit(task); 55 | } 56 | 57 | /** 58 | * Shutdown the thread pool and wait for any pending workers to finish. DO NOT CALL THIS ON THE MAIN THREAD POOL. 59 | */ 60 | public void finish() { 61 | shutdown(); 62 | } 63 | 64 | /** 65 | * Wait until the threadpool is done with all work, forever. DO NOT CALL THIS ON THE MAIN THREAD POOL. 66 | */ 67 | public void waitForCompletion() { 68 | try { 69 | awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 70 | } catch (Exception e) {} 71 | } 72 | 73 | // Factory 74 | private static class Factory implements ThreadFactory { 75 | 76 | private AtomicInteger integer = new AtomicInteger(1); 77 | 78 | String name; 79 | 80 | public Factory(String name) { 81 | this.name = name; 82 | } 83 | 84 | /** 85 | * Creates a new Thread Object for the ThreadFactory. This is given the proper name for the Thread Pool and is not 86 | * set as a daemon to assure that it can be easily debugged in profilers and other utilities. 87 | */ 88 | @Override 89 | public Thread newThread(Runnable r) { 90 | Thread t = new Thread(r, name + "-" + integer.getAndIncrement()); 91 | if (t.isDaemon()) 92 | t.setDaemon(false); 93 | if (t.getPriority() != Thread.NORM_PRIORITY) 94 | t.setPriority(Thread.NORM_PRIORITY); 95 | return t; 96 | } 97 | 98 | } 99 | 100 | } 101 | --------------------------------------------------------------------------------