Skip to content

Commit

Permalink
feat(logging): create new telemetry subsystem, add NetworkAlerts inte…
Browse files Browse the repository at this point in the history
…rface
  • Loading branch information
TheGamer1002 committed Jan 27, 2024
1 parent 4390163 commit 36ace22
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ src/main/java/frc/robot/BuildConstants.java
.gradle/8.5/fileHashes/fileHashes.lock
.gradle/buildOutputCleanup/buildOutputCleanup.lock
.gradle/
.gradle/8.5/checksums/checksums.lock
.gradle/8.5/checksums/md5-checksums.bin
.gradle/8.5/checksums/sha1-checksums.bin
.gradle/8.5/fileHashes/fileHashes.lock
.gradle/buildOutputCleanup/buildOutputCleanup.lock
41 changes: 41 additions & 0 deletions src/main/java/frc/robot/subsystems/TelemetrySubsystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package frc.robot.subsystems;


import edu.wpi.first.wpilibj2.command.SubsystemBase;

public class TelemetrySubsystem extends SubsystemBase {

// With eager singleton initialization, any static variables/fields used in the
// constructor must appear before the "INSTANCE" variable so that they are initialized
// before the constructor is called when the "INSTANCE" variable initializes.

/**
* The Singleton instance of this TelemetrySubsystem. Code should use
* the {@link #getInstance()} method to get the single instance (rather
* than trying to construct an instance of this class.)
*/
private final static TelemetrySubsystem INSTANCE = new TelemetrySubsystem();

/**
* Returns the Singleton instance of this TelemetrySubsystem. This static method
* should be used, rather than the constructor, to get the single instance
* of this class. For example: {@code TelemetrySubsystem.getInstance();}
*/
@SuppressWarnings("WeakerAccess")
public static TelemetrySubsystem getInstance() {
return INSTANCE;
}

/**
* Creates a new instance of this TelemetrySubsystem. This constructor
* is private since this class is a Singleton. Code should use
* the {@link #getInstance()} method to get the singleton instance.
*/
private TelemetrySubsystem() {
// TODO: Set the default command, if any, for this subsystem by calling setDefaultCommand(command)
// in the constructor or in the robot coordination class, such as RobotContainer.
// Also, you can call addChild(name, sendableChild) to associate sendables with the subsystem
// such as SpeedControllers, Encoders, DigitalInputs, etc.
}
}

195 changes: 195 additions & 0 deletions src/main/java/frc/robot/util/Alert.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// Copyright (c) 2023 FRC 6328
// http://github.com/Mechanical-Advantage
//
// Use of this source code is governed by an MIT-style
// license that can be found below.

// MIT License
//
// Copyright (c) 2023 FRC 6328
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package frc.robot.util;

import edu.wpi.first.util.sendable.Sendable;
import edu.wpi.first.util.sendable.SendableBuilder;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

/** Class for managing persistent alerts to be sent over NetworkTables. */
public class Alert {
private static Map<String, SendableAlerts> groups = new HashMap<String, SendableAlerts>();

private final AlertType type;
private boolean active = false;
private double activeStartTime = 0.0;
private String text;

/**
* Creates a new Alert in the default group - "Alerts". If this is the first to be instantiated,
* the appropriate entries will be added to NetworkTables.
*
* @param text Text to be displayed when the alert is active.
* @param type Alert level specifying urgency.
*/
public Alert(String text, AlertType type) {
this("Alerts", text, type);
}

/**
* Creates a new Alert. If this is the first to be instantiated in its group, the appropriate
* entries will be added to NetworkTables.
*
* @param group Group identifier, also used as NetworkTables title
* @param text Text to be displayed when the alert is active.
* @param type Alert level specifying urgency.
*/
public Alert(String group, String text, AlertType type) {
if (!groups.containsKey(group)) {
groups.put(group, new SendableAlerts());
SmartDashboard.putData(group, groups.get(group));
}

this.text = text;
this.type = type;
groups.get(group).alerts.add(this);
}

/**
* Sets whether the alert should currently be displayed. When activated, the alert text will also
* be sent to the console.
*/
public void set(boolean active) {
if (active && !this.active) {
activeStartTime = Timer.getFPGATimestamp();
switch (type) {
case ERROR:
DriverStation.reportError(text, false);
break;
case ERROR_TRACE:
DriverStation.reportError(text, true);
break;
case WARNING:
DriverStation.reportWarning(text, false);
break;
case WARNING_TRACE:
DriverStation.reportWarning(text, true);
break;
case INFO:
System.out.println(text);
break;
}
}
this.active = active;
}

/** Updates current alert text. */
public void setText(String text) {
if (active && !text.equals(this.text)) {
switch (type) {
case ERROR:
DriverStation.reportError(text, false);
break;
case ERROR_TRACE:
DriverStation.reportError(text, true);
break;
case WARNING:
DriverStation.reportWarning(text, false);
break;
case WARNING_TRACE:
DriverStation.reportWarning(text, true);
break;
case INFO:
System.out.println(text);
break;
}
}
this.text = text;
}

private static class SendableAlerts implements Sendable {
public final List<Alert> alerts = new ArrayList<>();

public String[] getStrings(AlertType type) {
Predicate<Alert> activeFilter = (Alert x) -> x.type == type && x.active;
Comparator<Alert> timeSorter =
(Alert a1, Alert a2) -> (int) (a2.activeStartTime - a1.activeStartTime);
return alerts.stream()
.filter(activeFilter)
.sorted(timeSorter)
.map((Alert a) -> a.text)
.toArray(String[]::new);
}

@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Alerts");
builder.addStringArrayProperty("errors", () -> getStrings(AlertType.ERROR), null);
builder.addStringArrayProperty("errors", () -> getStrings(AlertType.ERROR_TRACE), null);
builder.addStringArrayProperty("warnings", () -> getStrings(AlertType.WARNING), null);
builder.addStringArrayProperty("warnings", () -> getStrings(AlertType.WARNING_TRACE), null);
builder.addStringArrayProperty("infos", () -> getStrings(AlertType.INFO), null);
}
}

/** Represents an alert's level of urgency. */
public static enum AlertType {
/**
* High priority alert - displayed first on the dashboard with a red "X" symbol. Use this type
* for problems which will seriously affect the robot's functionality and thus require immediate
* attention.
*/
ERROR,
/**
* High priority alert - displayed first on the dashboard with a red "X" symbol. Use this type
* for problems which will seriously affect the robot's functionality and thus require immediate
* attention.
* Trace printed to driver station console.
*/
ERROR_TRACE,

/**
* Medium priority alert - displayed second on the dashboard with a yellow "!" symbol. Use this
* type for problems which could affect the robot's functionality but do not necessarily require
* immediate attention.
*/
WARNING,
/**
* Medium priority alert - displayed second on the dashboard with a yellow "!" symbol. Use this
* type for problems which could affect the robot's functionality but do not necessarily require
* immediate attention.
* Trace printed to driver station console.
*/
WARNING_TRACE,
/**
* Low priority alert - displayed last on the dashboard with a green "i" symbol. Use this type
* for problems which are unlikely to affect the robot's functionality, or any other alerts
* which do not fall under "ERROR" or "WARNING".
*/
INFO
}
}

0 comments on commit 36ace22

Please sign in to comment.