Skip to content

Commit f5abbe6

Browse files
committed
Merge pull request #505 from ThomasJClark/start-stop-nt
Start and stop headless GRIP using NetworkTables
2 parents c7cbbb7 + 11db640 commit f5abbe6

File tree

8 files changed

+66
-18
lines changed

8 files changed

+66
-18
lines changed

core/src/main/java/edu/wpi/grip/core/GRIPCoreModule.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
import com.google.inject.spi.TypeEncounter;
1111
import com.google.inject.spi.TypeListener;
1212
import edu.wpi.grip.core.events.UnexpectedThrowableEvent;
13+
import edu.wpi.grip.core.operations.networktables.NTManager;
1314
import edu.wpi.grip.core.serialization.Project;
1415
import edu.wpi.grip.core.sources.CameraSource;
1516
import edu.wpi.grip.core.sources.ImageFileSource;
1617
import edu.wpi.grip.core.sources.MultiImageFileSource;
1718
import edu.wpi.grip.core.util.ExceptionWitness;
19+
import edu.wpi.grip.core.util.GRIPMode;
1820

1921
import javax.annotation.Nullable;
2022
import java.io.IOException;
@@ -87,6 +89,8 @@ public GRIPCoreModule() {
8789

8890
@Override
8991
protected void configure() {
92+
bind(GRIPMode.class).toInstance(GRIPMode.HEADLESS);
93+
9094
// Register any injected object on the event bus
9195
bindListener(Matchers.any(), new TypeListener() {
9296
@Override
@@ -97,6 +101,8 @@ public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
97101

98102
bind(EventBus.class).toInstance(eventBus);
99103

104+
bind(NTManager.class).asEagerSingleton();
105+
100106
install(new FactoryModuleBuilder().build(new TypeLiteral<Connection.Factory<Object>>() {
101107
}));
102108

core/src/main/java/edu/wpi/grip/core/Pipeline.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import com.thoughtworks.xstream.annotations.XStreamAlias;
88
import com.thoughtworks.xstream.annotations.XStreamOmitField;
99
import edu.wpi.grip.core.events.*;
10-
import edu.wpi.grip.core.operations.networktables.NTManager;
1110
import edu.wpi.grip.core.settings.ProjectSettings;
1211

1312
import javax.inject.Inject;
@@ -37,10 +36,6 @@ public class Pipeline {
3736
@XStreamOmitField
3837
private EventBus eventBus;
3938

40-
@Inject
41-
@XStreamOmitField
42-
private NTManager ntManager;
43-
4439
/*
4540
* We have separate locks for sources and steps because we don't want to
4641
* block access to both resources when only one is in use.

core/src/main/java/edu/wpi/grip/core/operations/networktables/NTManager.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import edu.wpi.first.wpilibj.networktables.NetworkTable;
66
import edu.wpi.first.wpilibj.networktables.NetworkTablesJNI;
77
import edu.wpi.grip.core.Pipeline;
8+
import edu.wpi.grip.core.PipelineRunner;
89
import edu.wpi.grip.core.events.ProjectSettingsChangedEvent;
910
import edu.wpi.grip.core.events.StepRemovedEvent;
1011
import edu.wpi.grip.core.settings.ProjectSettings;
12+
import edu.wpi.grip.core.util.GRIPMode;
1113

1214
import javax.inject.Inject;
1315
import java.io.File;
@@ -41,13 +43,16 @@ public class NTManager {
4143
put(6, Level.FINEST);
4244
}};
4345

44-
@Inject Pipeline pipeline;
46+
@Inject private Pipeline pipeline;
47+
@Inject private PipelineRunner pipelineRunner;
48+
@Inject private GRIPMode gripMode;
4549

4650
@Inject
4751
public NTManager(Logger logger) {
4852
checkNotNull(logger, "Logger cannot be null");
4953
// We may have another instance of this method lying around
5054
NetworkTable.shutdown();
55+
5156
// Redirect NetworkTables log messages to our own log files. This gets rid of console spam, and it also lets
5257
// us grep through NetworkTables messages just like any other messages.
5358
NetworkTablesJNI.setLogger((level, file, line, msg) -> {
@@ -56,6 +61,30 @@ public NTManager(Logger logger) {
5661
}, 0);
5762

5863
NetworkTable.setClientMode();
64+
65+
// When in headless mode, start and stop the pipeline based on the "GRIP/run" key. This allows robot programs
66+
// to control GRIP without actually restarting the process.
67+
NetworkTable.getTable("GRIP").addTableListener("run", (source, key, value, isNew) -> {
68+
if (gripMode == GRIPMode.HEADLESS) {
69+
if (!(value instanceof Boolean)) {
70+
logger.warning("NetworkTables value GRIP/run should be a boolean!");
71+
return;
72+
}
73+
74+
if ((Boolean) value) {
75+
if (!pipelineRunner.isRunning()) {
76+
logger.info("Starting GRIP from NetworkTables");
77+
pipelineRunner.startAsync();
78+
}
79+
} else if (pipelineRunner.isRunning()) {
80+
logger.info("Stopping GRIP from NetworkTables");
81+
pipelineRunner.stopAsync();
82+
83+
}
84+
}
85+
}, true);
86+
87+
NetworkTable.shutdown();
5988
}
6089

6190
/**
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package edu.wpi.grip.core.util;
2+
3+
/**
4+
* An enum that indicates if GRIP is running in GUI mode with JavaFX or as a headless command line application.
5+
* <p>
6+
* To the get the mode, this can be injected into a class (ie: @Inject private GRIPMode mode;)
7+
*/
8+
public enum GRIPMode {
9+
GUI, HEADLESS
10+
}

ui/src/main/java/edu/wpi/grip/ui/GRIPUIModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.google.inject.spi.TypeEncounter;
99
import com.google.inject.spi.TypeListener;
1010
import edu.wpi.grip.core.Source;
11+
import edu.wpi.grip.core.util.GRIPMode;
1112
import edu.wpi.grip.ui.annotations.ParametrizedController;
1213
import edu.wpi.grip.ui.components.ExceptionWitnessResponderButton;
1314
import edu.wpi.grip.ui.components.StartStoppableButton;
@@ -28,6 +29,7 @@
2829
public class GRIPUIModule extends AbstractModule {
2930
@Override
3031
protected void configure() {
32+
bind(GRIPMode.class).toInstance(GRIPMode.GUI);
3133

3234
bindListener(Matchers.any(), new TypeListener() {
3335
@Override

ui/src/main/java/edu/wpi/grip/ui/Main.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.google.common.eventbus.Subscribe;
66
import com.google.inject.Guice;
77
import com.google.inject.Injector;
8+
import com.google.inject.util.Modules;
89
import com.sun.javafx.application.PlatformImpl;
910
import edu.wpi.grip.core.GRIPCoreModule;
1011
import edu.wpi.grip.core.PipelineRunner;
@@ -37,8 +38,12 @@ public class Main extends Application {
3738
@Inject private Project project;
3839
@Inject private Logger logger;
3940

41+
/**
42+
* JavaFX insists on creating the main application with its own reflection code, so we can't create with the
43+
* Guice and do automatic field injection. However, we can inject it after the fact.
44+
*/
4045
@VisibleForTesting
41-
protected final Injector injector = Guice.createInjector(new GRIPCoreModule(), new GRIPUIModule());
46+
protected Injector injector;
4247

4348
private final Object dialogLock = new Object();
4449
private Parent root;
@@ -47,23 +52,22 @@ public static void main(String[] args) {
4752
launch(args);
4853
}
4954

50-
/**
51-
* JavaFX insists on creating the main application with its own reflection code, so we can't create with the
52-
* Guice and do automatic field injection. However, we can inject it after the fact.
53-
*/
54-
public Main() {
55-
injector.injectMembers(this);
56-
}
57-
5855
@Override
5956
@SuppressWarnings("PMD.SignatureDeclareThrowsException")
6057
public void start(Stage stage) throws Exception {
61-
// If --headless was specified on the command line, run in headless mode
6258
List<String> parameters = new ArrayList<>(getParameters().getRaw());
6359

6460
if (parameters.contains("--headless")) {
61+
// If --headless was specified on the command line, run in headless mode (only use the core module)
62+
injector = Guice.createInjector(new GRIPCoreModule());
63+
injector.injectMembers(this);
64+
6565
parameters.remove("--headless");
6666
} else {
67+
// Otherwise, run with both the core and UI modules, and show the JavaFX stage
68+
injector = Guice.createInjector(Modules.override(new GRIPCoreModule()).with(new GRIPUIModule()));
69+
injector.injectMembers(this);
70+
6771
root = FXMLLoader.load(Main.class.getResource("MainWindow.fxml"), null, null, injector::getInstance);
6872
root.setStyle("-fx-font-size: " + DPIUtility.FONT_SIZE + "px");
6973

ui/src/test/java/edu/wpi/grip/ui/pipeline/PipelineUITest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.google.common.eventbus.EventBus;
55
import com.google.inject.Guice;
66
import com.google.inject.Injector;
7+
import com.google.inject.util.Modules;
78
import edu.wpi.grip.core.*;
89
import edu.wpi.grip.core.util.MockExceptionWitness;
910
import edu.wpi.grip.ui.GRIPUIModule;
@@ -44,7 +45,7 @@ public class PipelineUITest extends ApplicationTest {
4445
public void start(Stage stage) {
4546
testModule = new GRIPCoreTestModule();
4647
testModule.setUp();
47-
final Injector injector = Guice.createInjector(testModule, new GRIPUIModule());
48+
final Injector injector = Guice.createInjector(Modules.override(testModule).with(new GRIPUIModule()));
4849
eventBus = injector.getInstance(EventBus.class);
4950
pipeline = injector.getInstance(Pipeline.class);
5051
additionOperation = new AdditionOperation();

ui/src/test/java/edu/wpi/grip/ui/pipeline/input/InputSocketControllerFactoryTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.eventbus.EventBus;
44
import com.google.inject.Guice;
55
import com.google.inject.Injector;
6+
import com.google.inject.util.Modules;
67
import edu.wpi.grip.core.InputSocket;
78
import edu.wpi.grip.core.Operation;
89
import edu.wpi.grip.core.Palette;
@@ -77,7 +78,7 @@ public InputSocketControllerFactoryTest(Operation operation, String name) {
7778
public void start(Stage stage) {
7879
testModule = new GRIPCoreTestModule();
7980
testModule.setUp();
80-
Injector injector = Guice.createInjector(testModule, new GRIPUIModule());
81+
Injector injector = Guice.createInjector(Modules.override(testModule).with(new GRIPUIModule()));
8182
inputSocketControllerFactory = injector.getInstance(InputSocketControllerFactory.class);
8283
stepFactory = injector.getInstance(Step.Factory.class);
8384
gridPane = new GridPane();

0 commit comments

Comments
 (0)