Add mechanism to control Shuffleboard recordings and add event markers (#1414)

This commit is contained in:
Sam Carlberg
2018-11-19 02:15:30 -05:00
committed by Peter Johnson
parent 69cb53b51b
commit 45f4472d42
8 changed files with 433 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.shuffleboard;
/**
* The importance of an event marker in Shuffleboard. The exact meaning of each importance level is
* up for interpretation on a team-to-team basis, but users should follow the general guidelines
* of the various importance levels. The examples given are for reference and may be ignored or
* considered to be more or less important from team to team.
*/
public enum EventImportance {
// Maintainer note: this enum is mirrored in WPILibC and in Shuffleboard
// Modifying the enum or enum strings requires a corresponding change to the C++ enum
// and the enum in Shuffleboard
/**
* A trivial event such as a change in command state.
*/
kTrivial("TRIVIAL"),
/**
* A low importance event such as acquisition of a game piece.
*/
kLow("LOW"),
/**
* A "normal" importance event, such as a transition from autonomous mode to teleoperated control.
*/
kNormal("NORMAL"),
/**
* A high-importance event such as scoring a game piece.
*/
kHigh("HIGH"),
/**
* A critically important event such as a brownout, component failure, or software deadlock.
*/
kCritical("CRITICAL");
private final String m_simpleName;
EventImportance(String simpleName) {
m_simpleName = simpleName;
}
public String getSimpleName() {
return m_simpleName;
}
}

View File

@@ -0,0 +1,69 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.shuffleboard;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.DriverStation;
/**
* Controls Shuffleboard recordings via NetworkTables.
*/
final class RecordingController {
private static final String kRecordingTableName = "/Shuffleboard/.recording/";
private static final String kRecordingControlKey = kRecordingTableName + "RecordData";
private static final String kRecordingFileNameFormatKey = kRecordingTableName + "FileNameFormat";
private static final String kEventMarkerTableName = kRecordingTableName + "events";
private final NetworkTableEntry m_recordingControlEntry;
private final NetworkTableEntry m_recordingFileNameFormatEntry;
private final NetworkTable m_eventsTable;
RecordingController(NetworkTableInstance ntInstance) {
m_recordingControlEntry = ntInstance.getEntry(kRecordingControlKey);
m_recordingFileNameFormatEntry = ntInstance.getEntry(kRecordingFileNameFormatKey);
m_eventsTable = ntInstance.getTable(kEventMarkerTableName);
}
public void startRecording() {
m_recordingControlEntry.setBoolean(true);
}
public void stopRecording() {
m_recordingControlEntry.setBoolean(false);
}
public void setRecordingFileNameFormat(String format) {
m_recordingFileNameFormatEntry.setString(format);
}
public void clearRecordingFileNameFormat() {
m_recordingFileNameFormatEntry.delete();
}
public void addEventMarker(String name, String description, EventImportance importance) {
if (name == null || name.isEmpty() || name.isBlank()) {
DriverStation.reportError(
"Shuffleboard event name was not specified", true);
return;
}
if (importance == null) {
DriverStation.reportError(
"Shuffleboard event importance was null", true);
return;
}
String eventDescription = description == null || description.isBlank() ? "" : description;
m_eventsTable.getSubTable(name)
.getEntry("Info")
.setStringArray(new String[]{eventDescription, importance.getSimpleName()});
}
}

View File

@@ -54,6 +54,8 @@ public final class Shuffleboard {
private static final ShuffleboardRoot root =
new ShuffleboardInstance(NetworkTableInstance.getDefault());
private static final RecordingController recordingController =
new RecordingController(NetworkTableInstance.getDefault());
// TODO usage reporting
@@ -101,4 +103,80 @@ public final class Shuffleboard {
root.disableActuatorWidgets();
}
/**
* Starts data recording on the dashboard. Has no effect if recording is already in progress.
*
* @see #stopRecording()
*/
public static void startRecording() {
recordingController.startRecording();
}
/**
* Stops data recording on the dashboard. Has no effect if no recording is in progress.
*
* @see #startRecording()
*/
public static void stopRecording() {
recordingController.stopRecording();
}
/**
* Sets the file name format for new recording files to use. If recording is in progress when this
* method is called, it will continue to use the same file. New recordings will use the format.
*
* <p>To avoid recording files overwriting each other, make sure to use unique recording file
* names. File name formats accept templates for inserting the date and time when the recording
* started with the {@code ${date}} and {@code ${time}} templates, respectively. For example,
* the default format is {@code "recording-${time}"} and recording files created with it will have
* names like {@code "recording-2018.01.15.sbr"}. Users are <strong>strongly</strong> recommended
* to use the {@code ${time}} template to ensure unique file names.
* </p>
*
* @param format the format for the
* @see #clearRecordingFileNameFormat()
*/
public static void setRecordingFileNameFormat(String format) {
recordingController.setRecordingFileNameFormat(format);
}
/**
* Clears the custom name format for recording files. New recordings will use the default format.
*
* @see #setRecordingFileNameFormat(String)
*/
public static void clearRecordingFileNameFormat() {
recordingController.clearRecordingFileNameFormat();
}
/**
* Notifies Shuffleboard of an event. Events can range from as trivial as a change in a command
* state to as critical as a total power loss or component failure. If Shuffleboard is recording,
* the event will also be recorded.
*
* <p>If {@code name} is {@code null} or empty, or {@code importance} is {@code null}, then
* no event will be sent and an error will be printed to the driver station.
*
* @param name the name of the event
* @param description a description of the event
* @param importance the importance of the event
*/
public static void addEventMarker(String name, String description, EventImportance importance) {
recordingController.addEventMarker(name, description, importance);
}
/**
* Notifies Shuffleboard of an event. Events can range from as trivial as a change in a command
* state to as critical as a total power loss or component failure. If Shuffleboard is recording,
* the event will also be recorded.
*
* <p>If {@code name} is {@code null} or empty, or {@code importance} is {@code null}, then
* no event will be sent and an error will be printed to the driver station.
*
* @param name the name of the event
* @param importance the importance of the event
*/
public static void addEventMarker(String name, EventImportance importance) {
addEventMarker(name, "", importance);
}
}