mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpilib] Add persistent alerts API (#6735)
This commit is contained in:
68
wpilibc/src/main/native/cpp/Alert.cpp
Normal file
68
wpilibc/src/main/native/cpp/Alert.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "frc/Alert.h"
|
||||
|
||||
#include <frc/Timer.h>
|
||||
#include <frc/smartdashboard/SmartDashboard.h>
|
||||
|
||||
#include <networktables/NTSendableBuilder.h>
|
||||
|
||||
using namespace frc;
|
||||
|
||||
Alert::Alert(std::string_view text, AlertType type)
|
||||
: Alert("Alerts", text, type) {}
|
||||
|
||||
wpi::StringMap<Alert::SendableAlerts> Alert::groups;
|
||||
|
||||
Alert::Alert(std::string_view group, std::string_view text, AlertType type)
|
||||
: m_type(type), m_text(text) {
|
||||
if (!groups.contains(group)) {
|
||||
groups[group] = SendableAlerts();
|
||||
frc::SmartDashboard::PutData(group, &groups[group]);
|
||||
}
|
||||
groups[group].m_alerts.push_back(std::shared_ptr<Alert>(this));
|
||||
}
|
||||
|
||||
void Alert::Set(bool active) {
|
||||
if (active && !m_active) {
|
||||
m_activeStartTime = frc::Timer::GetFPGATimestamp();
|
||||
}
|
||||
m_active = active;
|
||||
}
|
||||
|
||||
void Alert::SetText(std::string_view text) {
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
void Alert::SendableAlerts::InitSendable(nt::NTSendableBuilder& builder) {
|
||||
builder.SetSmartDashboardType("Alerts");
|
||||
builder.AddStringArrayProperty(
|
||||
"errors", [this]() { return GetStrings(AlertType::kError); }, nullptr);
|
||||
builder.AddStringArrayProperty(
|
||||
"warnings", [this]() { return GetStrings(AlertType::kWarning); },
|
||||
nullptr);
|
||||
builder.AddStringArrayProperty(
|
||||
"infos", [this]() { return GetStrings(AlertType::kInfo); }, nullptr);
|
||||
}
|
||||
|
||||
std::vector<std::string> Alert::SendableAlerts::GetStrings(
|
||||
AlertType type) const {
|
||||
wpi::SmallVector<std::shared_ptr<Alert>> alerts;
|
||||
alerts.reserve(m_alerts.size());
|
||||
for (auto alert : m_alerts) {
|
||||
if (alert->m_active && alert->m_type == type) {
|
||||
alerts.push_back(alert);
|
||||
}
|
||||
}
|
||||
std::sort(alerts.begin(), alerts.end(), [](const auto a, const auto b) {
|
||||
return a->m_activeStartTime > b->m_activeStartTime;
|
||||
});
|
||||
std::vector<std::string> output{alerts.size()};
|
||||
for (unsigned int i = 0; i < alerts.size(); ++i) {
|
||||
std::string text{alerts[i]->m_text};
|
||||
output[i] = text;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
127
wpilibc/src/main/native/include/frc/Alert.h
Normal file
127
wpilibc/src/main/native/include/frc/Alert.h
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <networktables/NTSendable.h>
|
||||
#include <units/time.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
#include <wpi/StringMap.h>
|
||||
#include <wpi/sendable/SendableHelper.h>
|
||||
|
||||
namespace frc {
|
||||
|
||||
/**
|
||||
* Persistent alert to be sent via NetworkTables. Alerts are tagged with a type
|
||||
* of kError, kWarning, or kInfo to denote urgency. See Alert::AlertType for
|
||||
* suggested usage of each type. Alerts can be displayed on supported
|
||||
* dashboards, and are shown in a priority order based on type and recency of
|
||||
* activation.
|
||||
*
|
||||
* Alerts should be created once and stored persistently, then updated to
|
||||
* "active" or "inactive" as necessary. Set(bool) can be safely called
|
||||
* periodically.
|
||||
*
|
||||
* This API is new for 2025, but is likely to change in future seasons to
|
||||
* facilitate deeper integration with the robot control system.
|
||||
*
|
||||
* <pre>
|
||||
* class Robot {
|
||||
* frc::Alert alert{"Something went wrong", frc::Alert::AlertType::kWarning};
|
||||
* }
|
||||
*
|
||||
* Robot::periodic() {
|
||||
* alert.Set(...);
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
class Alert {
|
||||
public:
|
||||
/**
|
||||
* Represents an alert's level of urgency.
|
||||
*/
|
||||
enum class 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.
|
||||
*/
|
||||
kError,
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
kWarning,
|
||||
|
||||
/**
|
||||
* 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 the
|
||||
* other categories.
|
||||
*/
|
||||
kInfo
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 urgency level.
|
||||
*/
|
||||
Alert(std::string_view text, AlertType 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, used as the entry name in NetworkTables.
|
||||
* @param text Text to be displayed when the alert is active.
|
||||
* @param type Alert urgency level.
|
||||
*/
|
||||
Alert(std::string_view group, std::string_view text, AlertType type);
|
||||
|
||||
/**
|
||||
* Sets whether the alert should currently be displayed. When activated, the
|
||||
* alert text will also be sent to the console. This method can be safely
|
||||
* called periodically.
|
||||
*
|
||||
* @param active Whether to display the alert.
|
||||
*/
|
||||
void Set(bool active);
|
||||
|
||||
/**
|
||||
* Updates current alert text. Use this method to dynamically change the
|
||||
* displayed alert, such as including more details about the detected problem.
|
||||
*
|
||||
* @param text Text to be displayed when the alert is active.
|
||||
*/
|
||||
void SetText(std::string_view text);
|
||||
|
||||
private:
|
||||
AlertType m_type;
|
||||
bool m_active = false;
|
||||
units::second_t m_activeStartTime;
|
||||
std::string_view m_text;
|
||||
|
||||
class SendableAlerts : public nt::NTSendable,
|
||||
public wpi::SendableHelper<SendableAlerts> {
|
||||
public:
|
||||
wpi::SmallVector<std::shared_ptr<Alert>> m_alerts;
|
||||
void InitSendable(nt::NTSendableBuilder& builder) override;
|
||||
|
||||
private:
|
||||
std::vector<std::string> GetStrings(AlertType type) const;
|
||||
};
|
||||
|
||||
static wpi::StringMap<SendableAlerts> groups;
|
||||
};
|
||||
|
||||
} // namespace frc
|
||||
150
wpilibj/src/main/java/edu/wpi/first/wpilibj/Alert.java
Normal file
150
wpilibj/src/main/java/edu/wpi/first/wpilibj/Alert.java
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Persistent alert to be sent via NetworkTables. Alerts are tagged with a type of {@code kError},
|
||||
* {@code kWarning}, or {@code kInfo} to denote urgency. See {@link
|
||||
* edu.wpi.first.wpilibj.Alert.AlertType AlertType} for suggested usage of each type. Alerts can be
|
||||
* displayed on supported dashboards, and are shown in a priority order based on type and recency of
|
||||
* activation.
|
||||
*
|
||||
* <p>Alerts should be created once and stored persistently, then updated to "active" or "inactive"
|
||||
* as necessary. {@link #set(boolean)} can be safely called periodically.
|
||||
*
|
||||
* <p><b>This API is new for 2025, but is likely to change in future seasons to facilitate deeper
|
||||
* integration with the robot control system.</b>
|
||||
*
|
||||
* <pre>
|
||||
* class Robot {
|
||||
* Alert alert = new Alert("Something went wrong", AlertType.kWarning);
|
||||
*
|
||||
* periodic() {
|
||||
* alert.set(...);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Alternatively, alerts which are only used once at startup can be created and activated inline.
|
||||
*
|
||||
* <pre>
|
||||
* public Robot() {
|
||||
* new Alert("Failed to load auto paths", AlertType.kError).set(true);
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class Alert {
|
||||
private static Map<String, SendableAlerts> groups = new HashMap<String, SendableAlerts>();
|
||||
|
||||
private final AlertType m_type;
|
||||
private boolean m_active;
|
||||
private double m_activeStartTime;
|
||||
private String m_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 urgency level.
|
||||
*/
|
||||
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, used as the entry name in NetworkTables.
|
||||
* @param text Text to be displayed when the alert is active.
|
||||
* @param type Alert urgency level.
|
||||
*/
|
||||
public Alert(String group, String text, AlertType type) {
|
||||
if (!groups.containsKey(group)) {
|
||||
groups.put(group, new SendableAlerts());
|
||||
SmartDashboard.putData(group, groups.get(group));
|
||||
}
|
||||
|
||||
m_text = text;
|
||||
m_type = type;
|
||||
groups.get(group).m_alerts.add(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the alert should currently be displayed. When activated, the alert text will also
|
||||
* be sent to the console. This method can be safely called periodically.
|
||||
*
|
||||
* @param active Whether to display the alert.
|
||||
*/
|
||||
public void set(boolean active) {
|
||||
if (active && !m_active) {
|
||||
m_activeStartTime = Timer.getFPGATimestamp();
|
||||
}
|
||||
m_active = active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates current alert text. Use this method to dynamically change the displayed alert, such as
|
||||
* including more details about the detected problem.
|
||||
*
|
||||
* @param text Text to be displayed when the alert is active.
|
||||
*/
|
||||
public void setText(String text) {
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
private static final class SendableAlerts implements Sendable {
|
||||
private final Collection<Alert> m_alerts = new HashSet<>();
|
||||
|
||||
private String[] getStrings(AlertType type) {
|
||||
return m_alerts.stream()
|
||||
.filter((Alert a) -> a.m_active && a.m_type == type)
|
||||
.sorted((Alert a, Alert b) -> Double.compare(b.m_activeStartTime, a.m_activeStartTime))
|
||||
.map((Alert a) -> a.m_text)
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSendable(SendableBuilder builder) {
|
||||
builder.setSmartDashboardType("Alerts");
|
||||
builder.addStringArrayProperty("errors", () -> getStrings(AlertType.kError), null);
|
||||
builder.addStringArrayProperty("warnings", () -> getStrings(AlertType.kWarning), null);
|
||||
builder.addStringArrayProperty("infos", () -> getStrings(AlertType.kInfo), null);
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents an alert's level of urgency. */
|
||||
public 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.
|
||||
*/
|
||||
kError,
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
kWarning,
|
||||
|
||||
/**
|
||||
* 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 the other categories.
|
||||
*/
|
||||
kInfo
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user