Skip to content

Commit a9659d0

Browse files
authored
Merge pull request #646 from AustinShalit/ntSource
Add NetworkTableSource
2 parents a700892 + fc680f8 commit a9659d0

26 files changed

+651
-36
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,7 @@ bower_components
8888
**/generated
8989
*/generated_tests
9090
/bin/
91+
92+
### NetworkTables
93+
networktables.ini
94+
networktables.ini.bak

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

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import edu.wpi.grip.core.sources.HttpSource;
1212
import edu.wpi.grip.core.sources.ImageFileSource;
1313
import edu.wpi.grip.core.sources.MultiImageFileSource;
14+
import edu.wpi.grip.core.sources.NetworkTableEntrySource;
1415
import edu.wpi.grip.core.util.ExceptionWitness;
1516
import edu.wpi.grip.core.util.GripMode;
1617

@@ -144,6 +145,9 @@ public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
144145
install(new FactoryModuleBuilder()
145146
.implement(HttpSource.class, HttpSource.class)
146147
.build(HttpSource.Factory.class));
148+
install(new FactoryModuleBuilder()
149+
.implement(NetworkTableEntrySource.class, NetworkTableEntrySource.class)
150+
.build(NetworkTableEntrySource.Factory.class));
147151

148152
install(new FactoryModuleBuilder().build(ExceptionWitness.Factory.class));
149153
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import edu.wpi.grip.core.sources.HttpSource;
66
import edu.wpi.grip.core.sources.ImageFileSource;
77
import edu.wpi.grip.core.sources.MultiImageFileSource;
8+
import edu.wpi.grip.core.sources.NetworkTableEntrySource;
89
import edu.wpi.grip.core.util.ExceptionWitness;
910

1011
import com.google.common.collect.ImmutableList;
@@ -111,6 +112,8 @@ public static class SourceFactoryImpl implements SourceFactory {
111112
MultiImageFileSource.Factory multiImageFactory;
112113
@Inject
113114
HttpSource.Factory httpFactory;
115+
@Inject
116+
NetworkTableEntrySource.Factory networkTableEntryFactory;
114117

115118
@Override
116119
public Source create(Class<?> type, Properties properties) throws IOException {
@@ -122,6 +125,8 @@ public Source create(Class<?> type, Properties properties) throws IOException {
122125
return multiImageFactory.create(properties);
123126
} else if (type.isAssignableFrom(HttpSource.class)) {
124127
return httpFactory.create(properties);
128+
} else if (type.isAssignableFrom(NetworkTableEntrySource.class)) {
129+
return networkTableEntryFactory.create(properties);
125130
} else {
126131
throw new IllegalArgumentException(type + " was not a valid type");
127132
}

core/src/main/java/edu/wpi/grip/core/operations/network/GripNetworkModule.java

+5
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,10 @@ protected void configure() {
3434
bind(ROSNetworkPublisherFactory.class)
3535
.annotatedWith(Names.named("rosManager"))
3636
.to(ROSManager.class);
37+
38+
// Network receiver bindings
39+
bind(MapNetworkReceiverFactory.class)
40+
.annotatedWith(Names.named("ntManager"))
41+
.to(NTManager.class);
3742
}
3843
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package edu.wpi.grip.core.operations.network;
2+
3+
4+
/**
5+
* A factory to create {@link NetworkReceiver NetworkRecievers}.
6+
*/
7+
@FunctionalInterface
8+
public interface MapNetworkReceiverFactory {
9+
NetworkReceiver create(String path);
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package edu.wpi.grip.core.operations.network;
2+
3+
import java.util.function.Consumer;
4+
5+
import static com.google.common.base.Preconditions.checkArgument;
6+
import static com.google.common.base.Preconditions.checkNotNull;
7+
8+
/**
9+
* Manages the interface between the {@link PublishAnnotatedOperation} and the actual network
10+
* protocol implemented by a specific {@link Manager}.
11+
*/
12+
public abstract class NetworkReceiver implements AutoCloseable {
13+
14+
protected final String path;
15+
16+
/**
17+
* Create a new NetworkReceiver with the specified path.
18+
*
19+
* @param path The path of the object to get
20+
*/
21+
public NetworkReceiver(String path) {
22+
checkNotNull(path, "Path cannot be null");
23+
checkArgument(!path.isEmpty(), "Path cannot be an empty string");
24+
this.path = path;
25+
}
26+
27+
/**
28+
* Get the value of the object.
29+
*
30+
* @return The value of this NetworkReceiver
31+
*/
32+
public abstract Object getValue();
33+
34+
/**
35+
* Add a listener to the NetworkReceiver item.
36+
*
37+
* @param consumer The consumer to call when this item has a update
38+
*/
39+
public abstract void addListener(Consumer<Object> consumer);
40+
41+
/**
42+
* Close the network reciever. This should not throw an exception.
43+
*/
44+
public abstract void close();
45+
}

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

+70-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import edu.wpi.grip.core.operations.network.Manager;
66
import edu.wpi.grip.core.operations.network.MapNetworkPublisher;
77
import edu.wpi.grip.core.operations.network.MapNetworkPublisherFactory;
8+
import edu.wpi.grip.core.operations.network.MapNetworkReceiverFactory;
9+
import edu.wpi.grip.core.operations.network.NetworkReceiver;
810
import edu.wpi.grip.core.settings.ProjectSettings;
911
import edu.wpi.grip.core.util.GripMode;
1012

@@ -19,13 +21,15 @@
1921
import edu.wpi.first.wpilibj.tables.ITable;
2022

2123
import java.io.File;
24+
import java.util.LinkedList;
25+
import java.util.List;
2226
import java.util.Map;
2327
import java.util.Optional;
2428
import java.util.Set;
2529
import java.util.concurrent.atomic.AtomicInteger;
30+
import java.util.function.Consumer;
2631
import java.util.logging.Level;
2732
import java.util.logging.Logger;
28-
2933
import javax.inject.Inject;
3034

3135
import static com.google.common.base.Preconditions.checkNotNull;
@@ -34,18 +38,18 @@
3438
* This class encapsulates the way we map various settings to the global NetworkTables state.
3539
*/
3640
@Singleton
37-
public class NTManager implements Manager, MapNetworkPublisherFactory {
41+
public class NTManager implements Manager, MapNetworkPublisherFactory, MapNetworkReceiverFactory {
3842
/*
3943
* Nasty hack that is unavoidable because of how NetworkTables works.
4044
*/
41-
private static final AtomicInteger publisherCount = new AtomicInteger(0);
45+
private static final AtomicInteger count = new AtomicInteger(0);
4246

4347
/**
4448
* Information from: https://github.com/PeterJohnson/ntcore/blob/master/src/Log.h and
4549
* https://github.com/PeterJohnson/ntcore/blob/e6054f543a6ab10aa27af6cace855da66d67ee44
4650
* /include/ntcore_c.h#L39
4751
*/
48-
private static final Map<Integer, Level> ntLogLevels = ImmutableMap.<Integer, Level>builder()
52+
protected static final Map<Integer, Level> ntLogLevels = ImmutableMap.<Integer, Level>builder()
4953
.put(40, Level.SEVERE)
5054
.put(30, Level.WARNING)
5155
.put(20, Level.INFO)
@@ -120,11 +124,69 @@ public void updateSettings(ProjectSettingsChangedEvent event) {
120124

121125
@Override
122126
public <P> MapNetworkPublisher<P> create(Set<String> keys) {
123-
// Keep track of ever publisher created.
124-
publisherCount.getAndAdd(1);
127+
// Keep track of every publisher created.
128+
count.getAndAdd(1);
125129
return new NTPublisher<>(keys);
126130
}
127131

132+
@Override
133+
public NetworkReceiver create(String path) {
134+
count.getAndAdd(1);
135+
return new NTReceiver(path);
136+
}
137+
138+
private static final class NTReceiver extends NetworkReceiver {
139+
140+
private int entryListenerFunctionUid;
141+
private Object object = false;
142+
private final List<Consumer<Object>> listeners = new LinkedList<>();
143+
144+
protected NTReceiver(String path) {
145+
super(path);
146+
addListener();
147+
148+
synchronized (NetworkTable.class) {
149+
NetworkTable.initialize();
150+
}
151+
}
152+
153+
private void addListener() {
154+
entryListenerFunctionUid = NetworkTablesJNI.addEntryListener(path,
155+
(uid, key, value, flags) -> {
156+
object = value;
157+
listeners.forEach(c -> c.accept(object));
158+
},
159+
ITable.NOTIFY_IMMEDIATE
160+
| ITable.NOTIFY_NEW
161+
| ITable.NOTIFY_UPDATE
162+
| ITable.NOTIFY_DELETE
163+
| ITable.NOTIFY_LOCAL);
164+
}
165+
166+
@Override
167+
public void addListener(Consumer<Object> consumer) {
168+
listeners.add(consumer);
169+
}
170+
171+
@Override
172+
public Object getValue() {
173+
return object;
174+
}
175+
176+
@Override
177+
public void close() {
178+
NetworkTablesJNI.removeEntryListener(entryListenerFunctionUid);
179+
180+
synchronized (NetworkTable.class) {
181+
// This receiver is no longer used.
182+
if (NTManager.count.addAndGet(-1) == 0) {
183+
// We are the last resource using NetworkTables so shut it down
184+
NetworkTable.shutdown();
185+
}
186+
}
187+
}
188+
}
189+
128190
private static final class NTPublisher<P> extends MapNetworkPublisher<P> {
129191
private final ImmutableSet<String> keys;
130192
private Optional<String> name = Optional.empty();
@@ -184,8 +246,8 @@ public void close() {
184246
}
185247
synchronized (NetworkTable.class) {
186248
// This publisher is no longer used.
187-
if (NTManager.publisherCount.addAndGet(-1) == 0) {
188-
// We are the last publisher so shut it down
249+
if (NTManager.count.addAndGet(-1) == 0) {
250+
// We are the last resource using NetworkTables so shut it down
189251
NetworkTable.shutdown();
190252
}
191253
}

core/src/main/java/edu/wpi/grip/core/sockets/SocketHints.java

+8
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,13 @@ public static SocketHint<Number> createNumberSocketHint(final String identifier,
193193
defaultValue) {
194194
return createNumberSocketHintBuilder(identifier, defaultValue).build();
195195
}
196+
197+
public static SocketHint<String> createStringSocketHint(final String identifier,
198+
String defaultValue) {
199+
return new SocketHint.Builder<String>(String.class)
200+
.identifier(identifier)
201+
.initialValue(defaultValue)
202+
.build();
203+
}
196204
}
197205
}

0 commit comments

Comments
 (0)