Reorganize commands meant for Shuffleboard

Implement NetworkTables purging for the shooter tuner
This commit is contained in:
nathanrsxtn
2022-04-06 13:22:15 -06:00
parent 95e1ec76b6
commit 7808b2c8d3
7 changed files with 63 additions and 46 deletions
@@ -42,13 +42,13 @@ import edu.wpi.first.wpilibj2.command.button.JoystickButton;
import frc4388.robot.Constants.OIConstants;
import frc4388.robot.Constants.StorageConstants;
import frc4388.robot.Constants.SwerveDriveConstants;
import frc4388.robot.commands.CommandSchedule;
import frc4388.robot.commands.PathRecorder;
import frc4388.robot.commands.RunCommandForTime;
import frc4388.robot.commands.ShooterTuner;
import frc4388.robot.commands.DriveCommands.DriveWithInputForTime;
import frc4388.robot.commands.ExtenderIntakeCommands.ExtenderIntakeGroup;
import frc4388.robot.commands.ShooterCommands.TrackTarget;
import frc4388.robot.commands.shuffleboard.ShooterTuner;
import frc4388.robot.commands.shuffleboard.CommandSchedule;
import frc4388.robot.subsystems.BoomBoom;
import frc4388.robot.subsystems.Camera;
import frc4388.robot.subsystems.Claws;
@@ -42,9 +42,9 @@ import edu.wpi.first.wpilibj2.command.InstantCommand;
import edu.wpi.first.wpilibj2.command.NotifierCommand;
import frc4388.robot.Constants.SwerveDriveConstants;
import frc4388.robot.subsystems.SwerveDrive;
import frc4388.utility.ListeningSendableChooser;
import frc4388.utility.PathPlannerUtil;
import frc4388.utility.PathPlannerUtil.Path.Waypoint;
import frc4388.utility.shuffleboard.ListeningSendableChooser;
public class PathRecorder extends CommandBase {
private static final Logger LOGGER = Logger.getLogger(PathRecorder.class.getSimpleName());
@@ -1,4 +1,4 @@
package frc4388.robot.commands;
package frc4388.robot.commands.shuffleboard;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -20,14 +20,11 @@ import java.util.logging.Logger;
import com.diffplug.common.base.Errors;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.shuffleboard.BuiltInLayouts;
import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard;
import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardComponent;
import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardContainer;
import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardLayout;
import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.CommandBase;
import edu.wpi.first.wpilibj2.command.CommandGroupBase;
@@ -36,6 +33,7 @@ import edu.wpi.first.wpilibj2.command.ParallelCommandGroup;
import edu.wpi.first.wpilibj2.command.ParallelDeadlineGroup;
import edu.wpi.first.wpilibj2.command.ParallelRaceGroup;
import edu.wpi.first.wpilibj2.command.SequentialCommandGroup;
import frc4388.utility.shuffleboard.ShuffleboardHelper;
public final class CommandSchedule extends CommandBase {
private static final Logger LOGGER = Logger.getLogger(CommandSchedule.class.getSimpleName());
@@ -51,6 +49,7 @@ public final class CommandSchedule extends CommandBase {
private final int maxHeight;
private final boolean showGroupStatus;
/** The maxWidth and maxHeight must be less than or equal to the number of full grid cells in the Shuffleboard tab. This amount will vary depending on window size. */
public CommandSchedule(int maxWidth, int maxHeight, boolean showGroupStatus) {
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
@@ -74,8 +73,8 @@ public final class CommandSchedule extends CommandBase {
parallelDeadlineGroupCommandsMethod = lookup.unreflectGetter(parallelDeadlineGroupCommandsField);
parallelRaceGroupCommandsMethod = lookup.unreflectGetter(parallelRaceGroupCommandsField);
scheduledCommands = ((LinkedHashMap<Command, Object>) lookup.unreflectGetter(scheduledCommandsField).invoke(CommandScheduler.getInstance()));
} catch (Throwable e) {
LOGGER.log(Level.SEVERE, "Failed to reflect necessary fields to run the command schedule.", e);
} catch (Throwable exception) {
LOGGER.log(Level.SEVERE, "Failed to reflect necessary fields to run the command schedule.", exception);
cancel();
return;
}
@@ -102,7 +101,7 @@ public final class CommandSchedule extends CommandBase {
root = null;
ungroupedLayout = null;
scheduledCommands = null;
purgeShuffleboardTab("Command Schedule");
ShuffleboardHelper.purgeShuffleboardTab("Command Schedule");
}
@Override
@@ -158,35 +157,4 @@ public final class CommandSchedule extends CommandBase {
target.addBoolean(name, running);
}
}
private static void purgeShuffleboardTab(String name) {
Shuffleboard.getTab(name).getComponents().clear();
NetworkTable rootTable = NetworkTableInstance.getDefault().getTable("Shuffleboard");
NetworkTable rootMetaTable = rootTable.getSubTable(".metadata");
recursiveClearTable(rootMetaTable.getSubTable(name));
recursiveClearTable(rootTable.getSubTable(name));
rootMetaTable.getEntry("Selected").setString("");
rootMetaTable.delete(name);
rootTable.delete(name);
try {
Field shuffleboardRootField = Shuffleboard.class.getDeclaredField("root");
shuffleboardRootField.trySetAccessible();
Object shuffleboardRoot = shuffleboardRootField.get(null);
Field shuffleboardTabsField = shuffleboardRoot.getClass().getDeclaredField("m_tabs");
Field shuffleboardTabsChangedField = shuffleboardRoot.getClass().getDeclaredField("m_tabsChanged");
shuffleboardTabsField.trySetAccessible();
shuffleboardTabsChangedField.trySetAccessible();
((LinkedHashMap<String, ShuffleboardTab>) shuffleboardTabsField.get(shuffleboardRoot)).remove(name);
shuffleboardTabsChangedField.set(shuffleboardRoot, true);
} catch (NoSuchFieldException | IllegalAccessException e) {
LOGGER.log(Level.SEVERE, "Failed to purge Shuffleboard tab " + name + ".", e);
}
Shuffleboard.update();
}
private static void recursiveClearTable(NetworkTable table) {
table.getSubTables().forEach(name -> recursiveClearTable(table.getSubTable(name)));
table.getSubTables().forEach(table::delete);
table.getKeys().forEach(table::delete);
}
}
@@ -1,4 +1,4 @@
package frc4388.robot.commands;
package frc4388.robot.commands.shuffleboard;
import java.io.File;
import java.io.IOException;
@@ -23,7 +23,8 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj2.command.CommandBase;
import frc4388.robot.subsystems.BoomBoom;
import frc4388.robot.subsystems.BoomBoom.ShooterTableEntry;
import frc4388.utility.SendableTable;
import frc4388.utility.shuffleboard.SendableTable;
import frc4388.utility.shuffleboard.ShuffleboardHelper;
public class ShooterTuner extends CommandBase {
private static final Logger LOGGER = Logger.getLogger(ShooterTuner.class.getSimpleName());
@@ -60,7 +61,7 @@ public class ShooterTuner extends CommandBase {
tableOverrideEntry.drumVelocity = 0.0;
m_boomBoom.m_shooterTable = new ShooterTableEntry[] { tableOverrideEntry };
Shuffleboard.selectTab("Shooter Tuner");
SmartDashboard.putData("TABLE", m_tableEditor);
SmartDashboard.putData("Shooter Table", m_tableEditor);
}
@Override
public void execute() {
@@ -71,6 +72,7 @@ public class ShooterTuner extends CommandBase {
public void end(boolean interrupted) {
m_boomBoom.loadShooterTable();
LOGGER.info(Errors.log().wrapWithDefault(() -> Files.readString(PATH), "Failed to read CSV"));
ShuffleboardHelper.purgeShuffleboardTab("Shooter Tuner");
}
@Override
public final boolean isFinished() {
@@ -3,7 +3,7 @@
// the WPILib BSD license file in the root directory of this project.
// package edu.wpi.first.wpilibj.smartdashboard;
package frc4388.utility;
package frc4388.utility.shuffleboard;
import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
@@ -1,4 +1,4 @@
package frc4388.utility;
package frc4388.utility.shuffleboard;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -0,0 +1,47 @@
package frc4388.utility.shuffleboard;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard;
import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab;
public final class ShuffleboardHelper {
private static final Logger LOGGER = Logger.getLogger(ShuffleboardHelper.class.getSimpleName());
@SuppressWarnings("unchecked")
public static void purgeShuffleboardTab(String name) {
Shuffleboard.getTab(name).getComponents().clear();
NetworkTable rootTable = NetworkTableInstance.getDefault().getTable("Shuffleboard");
NetworkTable rootMetaTable = rootTable.getSubTable(".metadata");
recursiveClearTable(rootMetaTable.getSubTable(name));
recursiveClearTable(rootTable.getSubTable(name));
rootMetaTable.getEntry("Selected").setString("");
rootMetaTable.delete(name);
rootTable.delete(name);
try {
Field shuffleboardRootField = Shuffleboard.class.getDeclaredField("root");
shuffleboardRootField.trySetAccessible();
Object shuffleboardRoot = shuffleboardRootField.get(null);
Field shuffleboardTabsField = shuffleboardRoot.getClass().getDeclaredField("m_tabs");
Field shuffleboardTabsChangedField = shuffleboardRoot.getClass().getDeclaredField("m_tabsChanged");
shuffleboardTabsField.trySetAccessible();
shuffleboardTabsChangedField.trySetAccessible();
((LinkedHashMap<String, ShuffleboardTab>) shuffleboardTabsField.get(shuffleboardRoot)).remove(name);
shuffleboardTabsChangedField.set(shuffleboardRoot, true);
} catch (NoSuchFieldException | IllegalAccessException | ClassCastException exception) {
LOGGER.log(Level.SEVERE, exception, () -> "Failed to purge Shuffleboard tab " + name + ".");
}
Shuffleboard.update();
}
public static void recursiveClearTable(NetworkTable table) {
table.getSubTables().forEach(name -> recursiveClearTable(table.getSubTable(name)));
table.getSubTables().forEach(table::delete);
table.getKeys().forEach(table::delete);
}
}