mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-05 03:21:42 +00:00
Update Java SmartDashboard and LiveWindow to match C++
This commit is contained in:
@@ -12,7 +12,6 @@ import edu.wpi.first.networktables.NetworkTableEntry;
|
|||||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||||
import edu.wpi.first.wpilibj.Sendable;
|
import edu.wpi.first.wpilibj.Sendable;
|
||||||
import edu.wpi.first.wpilibj.command.Scheduler;
|
import edu.wpi.first.wpilibj.command.Scheduler;
|
||||||
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilderImpl;
|
|
||||||
import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
|
import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
|
||||||
|
|
||||||
|
|
||||||
@@ -22,7 +21,6 @@ import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
|
|||||||
*/
|
*/
|
||||||
public class LiveWindow {
|
public class LiveWindow {
|
||||||
private static class Component {
|
private static class Component {
|
||||||
final SendableBuilderImpl m_builder = new SendableBuilderImpl();
|
|
||||||
boolean m_firstTime = true;
|
boolean m_firstTime = true;
|
||||||
boolean m_telemetryEnabled = true;
|
boolean m_telemetryEnabled = true;
|
||||||
}
|
}
|
||||||
@@ -73,13 +71,9 @@ public class LiveWindow {
|
|||||||
scheduler.removeAll();
|
scheduler.removeAll();
|
||||||
} else {
|
} else {
|
||||||
System.out.println("stopping live window mode.");
|
System.out.println("stopping live window mode.");
|
||||||
SendableRegistry.foreachLiveWindow(dataHandle,
|
SendableRegistry.foreachLiveWindow(dataHandle, cbdata -> {
|
||||||
(sendable, name, subsystem, parent, data) -> {
|
cbdata.builder.stopLiveWindowMode();
|
||||||
if (data != null) {
|
});
|
||||||
((Component) data).m_builder.stopLiveWindowMode();
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
scheduler.enable();
|
scheduler.enable();
|
||||||
}
|
}
|
||||||
enabledEntry.setBoolean(enabled);
|
enabledEntry.setBoolean(enabled);
|
||||||
@@ -111,12 +105,11 @@ public class LiveWindow {
|
|||||||
*/
|
*/
|
||||||
public static synchronized void disableAllTelemetry() {
|
public static synchronized void disableAllTelemetry() {
|
||||||
telemetryEnabled = false;
|
telemetryEnabled = false;
|
||||||
SendableRegistry.foreachLiveWindow(dataHandle, (sendable, name, subsystem, parent, data) -> {
|
SendableRegistry.foreachLiveWindow(dataHandle, cbdata -> {
|
||||||
if (data == null) {
|
if (cbdata.data == null) {
|
||||||
data = new Component();
|
cbdata.data = new Component();
|
||||||
}
|
}
|
||||||
((Component) data).m_telemetryEnabled = false;
|
((Component) cbdata.data).m_telemetryEnabled = false;
|
||||||
return data;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,19 +126,19 @@ public class LiveWindow {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendableRegistry.foreachLiveWindow(dataHandle, (sendable, name, subsystem, parent, data) -> {
|
SendableRegistry.foreachLiveWindow(dataHandle, cbdata -> {
|
||||||
if (sendable == null || parent != null) {
|
if (cbdata.sendable == null || cbdata.parent != null) {
|
||||||
return data;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data == null) {
|
if (cbdata.data == null) {
|
||||||
data = new Component();
|
cbdata.data = new Component();
|
||||||
}
|
}
|
||||||
|
|
||||||
Component component = (Component) data;
|
Component component = (Component) cbdata.data;
|
||||||
|
|
||||||
if (!liveWindowEnabled && !component.m_telemetryEnabled) {
|
if (!liveWindowEnabled && !component.m_telemetryEnabled) {
|
||||||
return data;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component.m_firstTime) {
|
if (component.m_firstTime) {
|
||||||
@@ -153,30 +146,29 @@ public class LiveWindow {
|
|||||||
// components to be redefined. This allows default sensor and actuator
|
// components to be redefined. This allows default sensor and actuator
|
||||||
// values to be created that are replaced with the custom names from
|
// values to be created that are replaced with the custom names from
|
||||||
// users calling setName.
|
// users calling setName.
|
||||||
if (name.isEmpty()) {
|
if (cbdata.name.isEmpty()) {
|
||||||
return data;
|
return;
|
||||||
}
|
}
|
||||||
NetworkTable ssTable = liveWindowTable.getSubTable(subsystem);
|
NetworkTable ssTable = liveWindowTable.getSubTable(cbdata.subsystem);
|
||||||
NetworkTable table;
|
NetworkTable table;
|
||||||
// Treat name==subsystem as top level of subsystem
|
// Treat name==subsystem as top level of subsystem
|
||||||
if (name.equals(subsystem)) {
|
if (cbdata.name.equals(cbdata.subsystem)) {
|
||||||
table = ssTable;
|
table = ssTable;
|
||||||
} else {
|
} else {
|
||||||
table = ssTable.getSubTable(name);
|
table = ssTable.getSubTable(cbdata.name);
|
||||||
}
|
}
|
||||||
table.getEntry(".name").setString(name);
|
table.getEntry(".name").setString(cbdata.name);
|
||||||
component.m_builder.setTable(table);
|
cbdata.builder.setTable(table);
|
||||||
sendable.initSendable(component.m_builder);
|
cbdata.sendable.initSendable(cbdata.builder);
|
||||||
ssTable.getEntry(".type").setString("LW Subsystem");
|
ssTable.getEntry(".type").setString("LW Subsystem");
|
||||||
|
|
||||||
component.m_firstTime = false;
|
component.m_firstTime = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startLiveWindow) {
|
if (startLiveWindow) {
|
||||||
component.m_builder.startLiveWindowMode();
|
cbdata.builder.startLiveWindowMode();
|
||||||
}
|
}
|
||||||
component.m_builder.updateTable();
|
cbdata.builder.updateTable();
|
||||||
return data;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
startLiveWindow = false;
|
startLiveWindow = false;
|
||||||
|
|||||||
@@ -79,6 +79,14 @@ public class SendableBuilderImpl implements SendableBuilder {
|
|||||||
return m_table;
|
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.
|
* 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
|
* Set the string representation of the named data type that will be used by the smart dashboard
|
||||||
* for this sendable.
|
* for this sendable.
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ import java.lang.ref.WeakReference;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.WeakHashMap;
|
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.DriverStation;
|
||||||
import edu.wpi.first.wpilibj.Sendable;
|
import edu.wpi.first.wpilibj.Sendable;
|
||||||
|
|
||||||
@@ -30,6 +32,7 @@ public class SendableRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
WeakReference<Sendable> m_sendable;
|
WeakReference<Sendable> m_sendable;
|
||||||
|
SendableBuilderImpl m_builder = new SendableBuilderImpl();
|
||||||
String m_name;
|
String m_name;
|
||||||
String m_subsystem = "Ungrouped";
|
String m_subsystem = "Ungrouped";
|
||||||
WeakReference<Sendable> m_parent;
|
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 static synchronized void publish(Sendable sendable, NetworkTable table) {
|
||||||
public interface LiveWindowForeachCallback {
|
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.
|
* Sendable object.
|
||||||
*
|
|
||||||
* @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
|
|
||||||
*/
|
*/
|
||||||
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
|
* It is *not* safe to call other SendableRegistry functions from the
|
||||||
* callback.
|
* 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
|
* @param callback function to call for each object
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.AvoidInstantiatingObjectsInLoops",
|
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.AvoidInstantiatingObjectsInLoops",
|
||||||
"PMD.AvoidCatchingThrowable"})
|
"PMD.AvoidCatchingThrowable"})
|
||||||
public static synchronized void foreachLiveWindow(int dataHandle,
|
public static synchronized void foreachLiveWindow(int dataHandle,
|
||||||
LiveWindowForeachCallback callback) {
|
Consumer<CallbackData> callback) {
|
||||||
|
CallbackData cbdata = new CallbackData();
|
||||||
for (Component comp : components.values()) {
|
for (Component comp : components.values()) {
|
||||||
Sendable sendable = comp.m_sendable.get();
|
cbdata.sendable = comp.m_sendable.get();
|
||||||
if (sendable != null && comp.m_liveWindow) {
|
if (cbdata.sendable != null && comp.m_liveWindow) {
|
||||||
Sendable parent = null;
|
cbdata.name = comp.m_name;
|
||||||
|
cbdata.subsystem = comp.m_subsystem;
|
||||||
if (comp.m_parent != null) {
|
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) {
|
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 {
|
try {
|
||||||
data = callback.call(sendable, comp.m_name, comp.m_subsystem, parent, data);
|
callback.accept(cbdata);
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
Throwable cause = throwable.getCause();
|
Throwable cause = throwable.getCause();
|
||||||
if (cause != null) {
|
if (cause != null) {
|
||||||
@@ -436,13 +495,13 @@ public class SendableRegistry {
|
|||||||
+ throwable.toString(), false);
|
+ throwable.toString(), false);
|
||||||
comp.m_liveWindow = false;
|
comp.m_liveWindow = false;
|
||||||
}
|
}
|
||||||
if (data != null) {
|
if (cbdata.data != null) {
|
||||||
if (comp.m_data == null) {
|
if (comp.m_data == null) {
|
||||||
comp.m_data = new Object[dataHandle + 1];
|
comp.m_data = new Object[dataHandle + 1];
|
||||||
} else if (dataHandle >= comp.m_data.length) {
|
} else if (dataHandle >= comp.m_data.length) {
|
||||||
comp.m_data = Arrays.copyOf(comp.m_data, dataHandle + 1);
|
comp.m_data = Arrays.copyOf(comp.m_data, dataHandle + 1);
|
||||||
}
|
}
|
||||||
comp.m_data[dataHandle] = data;
|
comp.m_data[dataHandle] = cbdata.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,28 +27,19 @@ import edu.wpi.first.wpilibj.Sendable;
|
|||||||
* laptop. Users can put values into and get values from the SmartDashboard.
|
* laptop. Users can put values into and get values from the SmartDashboard.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"PMD.GodClass", "PMD.TooManyMethods"})
|
@SuppressWarnings({"PMD.GodClass", "PMD.TooManyMethods"})
|
||||||
public class SmartDashboard {
|
public final class SmartDashboard {
|
||||||
/**
|
/**
|
||||||
* The {@link NetworkTable} used by {@link SmartDashboard}.
|
* The {@link NetworkTable} used by {@link SmartDashboard}.
|
||||||
*/
|
*/
|
||||||
private static final NetworkTable table =
|
private static final NetworkTable table =
|
||||||
NetworkTableInstance.getDefault().getTable("SmartDashboard");
|
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
|
* A table linking tables in the SmartDashboard to the {@link Sendable} objects they
|
||||||
* came from.
|
* came from.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("PMD.UseConcurrentHashMap")
|
@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.
|
* The executor for listener tasks; calls listener tasks synchronously from main thread.
|
||||||
@@ -71,19 +62,13 @@ public class SmartDashboard {
|
|||||||
* @param data the value
|
* @param data the value
|
||||||
* @throws IllegalArgumentException If key is null
|
* @throws IllegalArgumentException If key is null
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
||||||
public static synchronized void putData(String key, Sendable data) {
|
public static synchronized void putData(String key, Sendable data) {
|
||||||
Data sddata = tablesToData.get(key);
|
Sendable sddata = tablesToData.get(key);
|
||||||
if (sddata == null || sddata.m_sendable != data) {
|
if (sddata == null || sddata != data) {
|
||||||
if (sddata != null) {
|
tablesToData.put(key, data);
|
||||||
sddata.m_builder.stopListeners();
|
|
||||||
}
|
|
||||||
sddata = new Data(data);
|
|
||||||
tablesToData.put(key, sddata);
|
|
||||||
NetworkTable dataTable = table.getSubTable(key);
|
NetworkTable dataTable = table.getSubTable(key);
|
||||||
sddata.m_builder.setTable(dataTable);
|
SendableRegistry.publish(data, dataTable);
|
||||||
data.initSendable(sddata.m_builder);
|
|
||||||
sddata.m_builder.updateTable();
|
|
||||||
sddata.m_builder.startListeners();
|
|
||||||
dataTable.getEntry(".name").setString(key);
|
dataTable.getEntry(".name").setString(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,11 +96,11 @@ public class SmartDashboard {
|
|||||||
* @throws IllegalArgumentException if the key is null
|
* @throws IllegalArgumentException if the key is null
|
||||||
*/
|
*/
|
||||||
public static synchronized Sendable getData(String key) {
|
public static synchronized Sendable getData(String key) {
|
||||||
Data data = tablesToData.get(key);
|
Sendable data = tablesToData.get(key);
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
throw new IllegalArgumentException("SmartDashboard data does not exist: " + key);
|
throw new IllegalArgumentException("SmartDashboard data does not exist: " + key);
|
||||||
} else {
|
} else {
|
||||||
return data.m_sendable;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,8 +528,8 @@ public class SmartDashboard {
|
|||||||
* Puts all sendable data to the dashboard.
|
* Puts all sendable data to the dashboard.
|
||||||
*/
|
*/
|
||||||
public static synchronized void updateValues() {
|
public static synchronized void updateValues() {
|
||||||
for (Data data : tablesToData.values()) {
|
for (Sendable data : tablesToData.values()) {
|
||||||
data.m_builder.updateTable();
|
SendableRegistry.update(data);
|
||||||
}
|
}
|
||||||
// Execute posted listener tasks
|
// Execute posted listener tasks
|
||||||
listenerExecutor.runListenerTasks();
|
listenerExecutor.runListenerTasks();
|
||||||
|
|||||||
Reference in New Issue
Block a user