Update Java SmartDashboard and LiveWindow to match C++

This commit is contained in:
Peter Johnson
2019-10-18 13:36:01 -07:00
parent 05c25deb7b
commit f3ad927f45
4 changed files with 133 additions and 81 deletions

View File

@@ -12,7 +12,6 @@ import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.command.Scheduler;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilderImpl;
import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
@@ -22,7 +21,6 @@ import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
*/
public class LiveWindow {
private static class Component {
final SendableBuilderImpl m_builder = new SendableBuilderImpl();
boolean m_firstTime = true;
boolean m_telemetryEnabled = true;
}
@@ -73,13 +71,9 @@ public class LiveWindow {
scheduler.removeAll();
} else {
System.out.println("stopping live window mode.");
SendableRegistry.foreachLiveWindow(dataHandle,
(sendable, name, subsystem, parent, data) -> {
if (data != null) {
((Component) data).m_builder.stopLiveWindowMode();
}
return data;
});
SendableRegistry.foreachLiveWindow(dataHandle, cbdata -> {
cbdata.builder.stopLiveWindowMode();
});
scheduler.enable();
}
enabledEntry.setBoolean(enabled);
@@ -111,12 +105,11 @@ public class LiveWindow {
*/
public static synchronized void disableAllTelemetry() {
telemetryEnabled = false;
SendableRegistry.foreachLiveWindow(dataHandle, (sendable, name, subsystem, parent, data) -> {
if (data == null) {
data = new Component();
SendableRegistry.foreachLiveWindow(dataHandle, cbdata -> {
if (cbdata.data == null) {
cbdata.data = new Component();
}
((Component) data).m_telemetryEnabled = false;
return data;
((Component) cbdata.data).m_telemetryEnabled = false;
});
}
@@ -133,19 +126,19 @@ public class LiveWindow {
return;
}
SendableRegistry.foreachLiveWindow(dataHandle, (sendable, name, subsystem, parent, data) -> {
if (sendable == null || parent != null) {
return data;
SendableRegistry.foreachLiveWindow(dataHandle, cbdata -> {
if (cbdata.sendable == null || cbdata.parent != null) {
return;
}
if (data == null) {
data = new Component();
if (cbdata.data == null) {
cbdata.data = new Component();
}
Component component = (Component) data;
Component component = (Component) cbdata.data;
if (!liveWindowEnabled && !component.m_telemetryEnabled) {
return data;
return;
}
if (component.m_firstTime) {
@@ -153,30 +146,29 @@ public class LiveWindow {
// components to be redefined. This allows default sensor and actuator
// values to be created that are replaced with the custom names from
// users calling setName.
if (name.isEmpty()) {
return data;
if (cbdata.name.isEmpty()) {
return;
}
NetworkTable ssTable = liveWindowTable.getSubTable(subsystem);
NetworkTable ssTable = liveWindowTable.getSubTable(cbdata.subsystem);
NetworkTable table;
// Treat name==subsystem as top level of subsystem
if (name.equals(subsystem)) {
if (cbdata.name.equals(cbdata.subsystem)) {
table = ssTable;
} else {
table = ssTable.getSubTable(name);
table = ssTable.getSubTable(cbdata.name);
}
table.getEntry(".name").setString(name);
component.m_builder.setTable(table);
sendable.initSendable(component.m_builder);
table.getEntry(".name").setString(cbdata.name);
cbdata.builder.setTable(table);
cbdata.sendable.initSendable(cbdata.builder);
ssTable.getEntry(".type").setString("LW Subsystem");
component.m_firstTime = false;
}
if (startLiveWindow) {
component.m_builder.startLiveWindowMode();
cbdata.builder.startLiveWindowMode();
}
component.m_builder.updateTable();
return data;
cbdata.builder.updateTable();
});
startLiveWindow = false;

View File

@@ -79,6 +79,14 @@ public class SendableBuilderImpl implements SendableBuilder {
return m_table;
}
/**
* Return whether this sendable has an associated table.
* @return True if it has a table, false if not.
*/
public boolean hasTable() {
return m_table != null;
}
/**
* Return whether this sendable should be treated as an actuator.
*
@@ -148,6 +156,14 @@ public class SendableBuilderImpl implements SendableBuilder {
}
}
/**
* Clear properties.
*/
public void clearProperties() {
stopListeners();
m_properties.clear();
}
/**
* Set the string representation of the named data type that will be used by the smart dashboard
* for this sendable.

View File

@@ -11,7 +11,9 @@ import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.function.Consumer;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.Sendable;
@@ -30,6 +32,7 @@ public class SendableRegistry {
}
WeakReference<Sendable> m_sendable;
SendableBuilderImpl m_builder = new SendableBuilderImpl();
String m_name;
String m_subsystem = "Ungrouped";
WeakReference<Sendable> m_parent;
@@ -384,21 +387,71 @@ public class SendableRegistry {
}
/**
* Functional interface for foreachLiveWindow().
* Publishes an object in the registry to a network table.
*
* @param sendable object
* @param table network table
*/
@FunctionalInterface
public interface LiveWindowForeachCallback {
public static synchronized void publish(Sendable sendable, NetworkTable table) {
Component comp = getOrAdd(sendable);
comp.m_builder.clearProperties();
comp.m_builder.setTable(table);
sendable.initSendable(comp.m_builder);
comp.m_builder.updateTable();
comp.m_builder.startListeners();
}
/**
* Updates network table information from an object.
*
* @param sendable object
*/
public static synchronized void update(Sendable sendable) {
Component comp = components.get(sendable);
if (comp != null) {
comp.m_builder.updateTable();
}
}
/**
* Data passed to foreachLiveWindow() callback function.
*/
public static class CallbackData {
/**
* Callback.
*
* @param sendable sendable object
* @param name name
* @param subsystem subsystem
* @param parent parent sendable object
* @param data data stored in object with setData()
* @return data to be stored back into object, or null if none/don't modify
* Sendable object.
*/
Object call(Sendable sendable, String name, String subsystem, Sendable parent, Object data);
@SuppressWarnings("MemberName")
public Sendable sendable;
/**
* Name.
*/
@SuppressWarnings("MemberName")
public String name;
/**
* Subsystem.
*/
@SuppressWarnings("MemberName")
public String subsystem;
/**
* Parent sendable object.
*/
@SuppressWarnings("MemberName")
public Sendable parent;
/**
* Data stored in object with setData(). Update this to change the data.
*/
@SuppressWarnings("MemberName")
public Object data;
/**
* Sendable builder for the sendable.
*/
@SuppressWarnings("MemberName")
public SendableBuilderImpl builder;
}
/**
@@ -406,26 +459,32 @@ public class SendableRegistry {
* It is *not* safe to call other SendableRegistry functions from the
* callback.
*
* @param dataHandle data handle to get data pointer passed to callback
* @param dataHandle data handle to get data object passed to callback
* @param callback function to call for each object
*/
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.AvoidInstantiatingObjectsInLoops",
"PMD.AvoidCatchingThrowable"})
public static synchronized void foreachLiveWindow(int dataHandle,
LiveWindowForeachCallback callback) {
Consumer<CallbackData> callback) {
CallbackData cbdata = new CallbackData();
for (Component comp : components.values()) {
Sendable sendable = comp.m_sendable.get();
if (sendable != null && comp.m_liveWindow) {
Sendable parent = null;
cbdata.sendable = comp.m_sendable.get();
if (cbdata.sendable != null && comp.m_liveWindow) {
cbdata.name = comp.m_name;
cbdata.subsystem = comp.m_subsystem;
if (comp.m_parent != null) {
parent = comp.m_parent.get();
cbdata.parent = comp.m_parent.get();
} else {
cbdata.parent = null;
}
Object data = null;
if (comp.m_data != null && dataHandle < comp.m_data.length) {
data = comp.m_data[dataHandle];
cbdata.data = comp.m_data[dataHandle];
} else {
cbdata.data = null;
}
cbdata.builder = comp.m_builder;
try {
data = callback.call(sendable, comp.m_name, comp.m_subsystem, parent, data);
callback.accept(cbdata);
} catch (Throwable throwable) {
Throwable cause = throwable.getCause();
if (cause != null) {
@@ -436,13 +495,13 @@ public class SendableRegistry {
+ throwable.toString(), false);
comp.m_liveWindow = false;
}
if (data != null) {
if (cbdata.data != null) {
if (comp.m_data == null) {
comp.m_data = new Object[dataHandle + 1];
} else if (dataHandle >= comp.m_data.length) {
comp.m_data = Arrays.copyOf(comp.m_data, dataHandle + 1);
}
comp.m_data[dataHandle] = data;
comp.m_data[dataHandle] = cbdata.data;
}
}
}

View File

@@ -27,28 +27,19 @@ import edu.wpi.first.wpilibj.Sendable;
* laptop. Users can put values into and get values from the SmartDashboard.
*/
@SuppressWarnings({"PMD.GodClass", "PMD.TooManyMethods"})
public class SmartDashboard {
public final class SmartDashboard {
/**
* The {@link NetworkTable} used by {@link SmartDashboard}.
*/
private static final NetworkTable table =
NetworkTableInstance.getDefault().getTable("SmartDashboard");
private static class Data {
Data(Sendable sendable) {
m_sendable = sendable;
}
final Sendable m_sendable;
final SendableBuilderImpl m_builder = new SendableBuilderImpl();
}
/**
* A table linking tables in the SmartDashboard to the {@link Sendable} objects they
* came from.
*/
@SuppressWarnings("PMD.UseConcurrentHashMap")
private static final Map<String, Data> tablesToData = new HashMap<>();
private static final Map<String, Sendable> tablesToData = new HashMap<>();
/**
* The executor for listener tasks; calls listener tasks synchronously from main thread.
@@ -71,19 +62,13 @@ public class SmartDashboard {
* @param data the value
* @throws IllegalArgumentException If key is null
*/
@SuppressWarnings("PMD.CompareObjectsWithEquals")
public static synchronized void putData(String key, Sendable data) {
Data sddata = tablesToData.get(key);
if (sddata == null || sddata.m_sendable != data) {
if (sddata != null) {
sddata.m_builder.stopListeners();
}
sddata = new Data(data);
tablesToData.put(key, sddata);
Sendable sddata = tablesToData.get(key);
if (sddata == null || sddata != data) {
tablesToData.put(key, data);
NetworkTable dataTable = table.getSubTable(key);
sddata.m_builder.setTable(dataTable);
data.initSendable(sddata.m_builder);
sddata.m_builder.updateTable();
sddata.m_builder.startListeners();
SendableRegistry.publish(data, dataTable);
dataTable.getEntry(".name").setString(key);
}
}
@@ -111,11 +96,11 @@ public class SmartDashboard {
* @throws IllegalArgumentException if the key is null
*/
public static synchronized Sendable getData(String key) {
Data data = tablesToData.get(key);
Sendable data = tablesToData.get(key);
if (data == null) {
throw new IllegalArgumentException("SmartDashboard data does not exist: " + key);
} else {
return data.m_sendable;
return data;
}
}
@@ -543,8 +528,8 @@ public class SmartDashboard {
* Puts all sendable data to the dashboard.
*/
public static synchronized void updateValues() {
for (Data data : tablesToData.values()) {
data.m_builder.updateTable();
for (Sendable data : tablesToData.values()) {
SendableRegistry.update(data);
}
// Execute posted listener tasks
listenerExecutor.runListenerTasks();