mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11: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.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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user