Skip to content

Commit 1562e66

Browse files
committed
Merge branch 'master' of https://github.com/Open-RIO/ToastAPI
2 parents 30137b7 + 21b75a6 commit 1562e66

9 files changed

Lines changed: 196 additions & 4 deletions

File tree

src/main/java/jaci/openrio/toast/core/StateTracker.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ public class StateTracker {
3535

3636
private static Toast impl;
3737

38-
private static List<StateListener.Ticker> tickers = new ArrayList<StateListener.Ticker>();
39-
private static List<StateListener.Transition> transitioners = new ArrayList<StateListener.Transition>();
38+
private static volatile List<StateListener.Ticker> tickers = new ArrayList<StateListener.Ticker>();
39+
private static volatile List<StateListener.Transition> transitioners = new ArrayList<StateListener.Transition>();
4040

4141
/**
4242
* Start the StateTracker loop

src/main/java/jaci/openrio/toast/core/Toast.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import edu.wpi.first.wpilibj.DriverStation;
66
import edu.wpi.first.wpilibj.RobotBase;
77
import groovy.lang.GroovyObject;
8+
import jaci.openrio.toast.core.command.CommandBus;
89
import jaci.openrio.toast.core.loader.RobotLoader;
910
import jaci.openrio.toast.core.loader.groovy.GroovyLoader;
1011
import jaci.openrio.toast.core.loader.groovy.GroovyPreferences;
@@ -18,8 +19,6 @@
1819

1920
/**
2021
* The Toast Base Class. This is the base for the Toast API.
21-
* In order to take advantage of this, change your Robot-Class
22-
* to this instead of your own in the Manifest.MF file.
2322
*
2423
* @author Jaci
2524
*/
@@ -75,6 +74,7 @@ protected void prestart() {
7574

7675
CrashHandler.init();
7776
RobotLoader.init();
77+
CommandBus.init();
7878
GroovyLoader.init();
7979
GroovyPreferences.init();
8080

src/main/java/jaci/openrio/toast/core/ToastBootstrap.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import jaci.openrio.toast.core.loader.RobotLoader;
66
import jaci.openrio.toast.core.loader.groovy.GroovyLoader;
77
import jaci.openrio.toast.core.loader.simulation.SimulationGUI;
8+
import jaci.openrio.toast.core.shared.GlobalBlackboard;
89
import jaci.openrio.toast.lib.log.Logger;
910
import jaci.openrio.toast.lib.log.SysLogProxy;
1011

@@ -74,6 +75,7 @@ public static void main(String[] args) {
7475
toastHome.mkdirs();
7576

7677
toastLogger = new Logger("Toast", Logger.ATTR_DEFAULT);
78+
new GlobalBlackboard();
7779
SysLogProxy.init();
7880

7981
toastLogger.info("Slicing Loaf...");
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
*
16+
* e.g. 'cmd' for a command such as 'cmd <your args>
17+
*/
18+
public abstract String getCommandName();
19+
20+
/**
21+
* Invoke the command if the name matches the one to be triggered
22+
* @param argLength The amount of arguments in the 'args' param
23+
* @param args The arguments the command was invoked with. This can be empty if
24+
* none were provided. Keep in mind this does NOT include the Command Name.
25+
* Args are separated by spaces
26+
* @param command The full command message
27+
*/
28+
public abstract void invokeCommand(int argLength, String[] args, String command);
29+
30+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package jaci.openrio.toast.core.command;
2+
3+
import jaci.openrio.toast.core.ToastBootstrap;
4+
import jaci.openrio.toast.core.command.cmd.CommandGroovyScript;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.Scanner;
9+
10+
/**
11+
* The main pipeline for commands. This bus handles registering and invocation of commands. This allows for
12+
* robot functions to be triggered remotely, or locally, based on a message.
13+
*
14+
* @see jaci.openrio.toast.core.command.AbstractCommand
15+
* @see jaci.openrio.toast.core.command.FuzzyCommand
16+
*
17+
* @author Jaci
18+
*/
19+
public class CommandBus {
20+
21+
private static List<AbstractCommand> commands;
22+
private static List<FuzzyCommand> parsers;
23+
24+
public static void init() {
25+
commands = new ArrayList<>();
26+
parsers = new ArrayList<>();
27+
28+
if (ToastBootstrap.isSimulation)
29+
setupSim();
30+
31+
registerNatives();
32+
}
33+
34+
private static void registerNatives() {
35+
registerCommand(new CommandGroovyScript());
36+
}
37+
38+
/**
39+
* Parse the given message and invoke any commands matching it
40+
*/
41+
public static void parseMessage(String message) {
42+
String[] split = message.split(" ");
43+
for (AbstractCommand command : commands) {
44+
if (split[0].equals(command.getCommandName())) {
45+
String[] newSplit = new String[split.length - 1];
46+
System.arraycopy(split, 1, newSplit, 0, split.length-1);
47+
command.invokeCommand(split.length, newSplit, message);
48+
}
49+
}
50+
51+
for (FuzzyCommand command : parsers) {
52+
if (command.shouldInvoke(message))
53+
command.invokeCommand(message);
54+
}
55+
}
56+
57+
/**
58+
* Register a {@link jaci.openrio.toast.core.command.FuzzyCommand} on the bus
59+
*/
60+
public static void registerCommand(FuzzyCommand command) {
61+
parsers.add(command);
62+
}
63+
64+
/**
65+
* Register a {@link jaci.openrio.toast.core.command.AbstractCommand} on the bus
66+
*/
67+
public static void registerCommand(AbstractCommand command) {
68+
commands.add(command);
69+
}
70+
71+
private static void setupSim() {
72+
Scanner scanner = new Scanner(System.in);
73+
Thread thread = new Thread() {
74+
public void run() {
75+
Thread.currentThread().setName("Toast|SimulationCommands");
76+
try {
77+
while (Thread.currentThread().isAlive()) {
78+
parseMessage(scanner.nextLine());
79+
}
80+
} catch (Exception e) {}
81+
};
82+
};
83+
thread.start();
84+
}
85+
86+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package jaci.openrio.toast.core.command.cmd
2+
3+
import jaci.openrio.toast.core.Toast
4+
import jaci.openrio.toast.core.command.FuzzyCommand
5+
import jaci.openrio.toast.core.shared.GlobalBlackboard
6+
7+
class CommandGroovyScript extends FuzzyCommand {
8+
9+
@Override
10+
boolean shouldInvoke(String message) {
11+
return message.startsWith("script")
12+
}
13+
14+
@Override
15+
void invokeCommand(String message) {
16+
String groovy = message.replaceFirst("script", "")
17+
Binding binding = new Binding();
18+
binding.setVariable("_global", GlobalBlackboard.INSTANCE)
19+
binding.setVariable("_toast", Toast.getToast())
20+
GroovyShell shell = new GroovyShell(binding)
21+
shell.evaluate(groovy)
22+
}
23+
}

src/main/java/jaci/openrio/toast/core/loader/groovy/GroovyLoader.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ public static void init() {
5252
loadScripts();
5353
}
5454

55+
public static GroovyClassLoader getGLoader() {
56+
return gLoader;
57+
}
58+
5559
static void loadScripts() {
5660
try {
5761
gLoader = new GroovyClassLoader(loader);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 more generally than the {@link jaci.openrio.toast.core.loader.module.ModuleStorage} object.
8+
*
9+
* This class is intended to be used by the {@link jaci.openrio.toast.core.command.cmd.CommandGroovyScript} class to
10+
* allow variables to be altered simply, and can be accessed from the Script command using '_global'
11+
*
12+
* @author Jaci
13+
*/
14+
public class GlobalBlackboard extends HashMap<String, Object> {
15+
16+
public static GlobalBlackboard INSTANCE;
17+
18+
public GlobalBlackboard() {
19+
super();
20+
INSTANCE = this;
21+
}
22+
23+
}

0 commit comments

Comments
 (0)