mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-04 03:11:43 +00:00
[hal,wpilib] Move Alert to HAL (#8646)
SystemCore implementation is not yet connected to MRCComm.
This commit is contained in:
52
wpilibc/src/main/native/cpp/driverstation/Alert.cpp
Normal file
52
wpilibc/src/main/native/cpp/driverstation/Alert.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// 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 "wpi/driverstation/Alert.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "wpi/util/string.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
static HAL_AlertHandle CreateAlert(std::string_view group,
|
||||
std::string_view text, Alert::Level level) {
|
||||
WPI_String wpiGroup = wpi::util::make_string(group);
|
||||
WPI_String wpiText = wpi::util::make_string(text);
|
||||
int32_t status = 0;
|
||||
return HAL_CreateAlert(&wpiGroup, &wpiText, static_cast<int32_t>(level),
|
||||
&status);
|
||||
}
|
||||
|
||||
Alert::Alert(std::string_view text, Level type) : Alert("Alerts", text, type) {}
|
||||
|
||||
Alert::Alert(std::string_view group, std::string_view text, Level type)
|
||||
: m_handle{CreateAlert(group, text, type)} {}
|
||||
|
||||
void Alert::Set(bool active) {
|
||||
int32_t status = 0;
|
||||
HAL_SetAlertActive(m_handle, active, &status);
|
||||
}
|
||||
|
||||
bool Alert::Get() const {
|
||||
int32_t status = 0;
|
||||
return HAL_IsAlertActive(m_handle, &status);
|
||||
}
|
||||
|
||||
void Alert::SetText(std::string_view text) {
|
||||
WPI_String wpiText = wpi::util::make_string(text);
|
||||
int32_t status = 0;
|
||||
HAL_SetAlertText(m_handle, &wpiText, &status);
|
||||
}
|
||||
|
||||
std::string Alert::GetText() const {
|
||||
WPI_String wpiText;
|
||||
int32_t status = 0;
|
||||
HAL_GetAlertText(m_handle, &wpiText, &status);
|
||||
std::string rv{wpiText.str, wpiText.len};
|
||||
WPI_FreeString(&wpiText);
|
||||
return rv;
|
||||
}
|
||||
40
wpilibc/src/main/native/cpp/simulation/AlertSim.cpp
Normal file
40
wpilibc/src/main/native/cpp/simulation/AlertSim.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
// 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 "wpi/simulation/AlertSim.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "wpi/hal/simulation/AlertData.h"
|
||||
#include "wpi/util/string.h"
|
||||
|
||||
using namespace wpi;
|
||||
using namespace wpi::sim;
|
||||
|
||||
int32_t AlertSim::GetCount() {
|
||||
return HALSIM_GetNumAlerts();
|
||||
}
|
||||
|
||||
std::vector<AlertSim::AlertInfo> AlertSim::GetAll() {
|
||||
int32_t allocLen = HALSIM_GetNumAlerts();
|
||||
HALSIM_AlertInfo* cInfos = new HALSIM_AlertInfo[allocLen];
|
||||
int32_t len = HALSIM_GetAlerts(cInfos, allocLen);
|
||||
std::vector<AlertInfo> infos;
|
||||
infos.reserve(len);
|
||||
for (int32_t i = 0; i < len; ++i) {
|
||||
const auto& cInfo = cInfos[i];
|
||||
infos.emplace_back(
|
||||
cInfo.handle, std::string{wpi::util::to_string_view(&cInfo.group)},
|
||||
std::string{wpi::util::to_string_view(&cInfo.text)},
|
||||
cInfo.activeStartTime, static_cast<Alert::Level>(cInfo.level));
|
||||
}
|
||||
HALSIM_FreeAlerts(cInfos, len < allocLen ? len : allocLen);
|
||||
delete[] cInfos;
|
||||
return infos;
|
||||
}
|
||||
|
||||
void AlertSim::ResetData() {
|
||||
HALSIM_ResetAlertData();
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
// 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 "wpi/util/Alert.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "wpi/nt/NTSendable.hpp"
|
||||
#include "wpi/nt/NTSendableBuilder.hpp"
|
||||
#include "wpi/smartdashboard/SmartDashboard.hpp"
|
||||
#include "wpi/system/Errors.hpp"
|
||||
#include "wpi/system/RobotController.hpp"
|
||||
#include "wpi/util/StringMap.hpp"
|
||||
#include "wpi/util/sendable/SendableHelper.hpp"
|
||||
#include "wpi/util/sendable/SendableRegistry.hpp"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
class Alert::PublishedAlert {
|
||||
public:
|
||||
PublishedAlert(uint64_t timestamp, std::string_view text)
|
||||
: timestamp{timestamp}, text{text} {}
|
||||
uint64_t timestamp;
|
||||
std::string text;
|
||||
auto operator<=>(const PublishedAlert& other) const {
|
||||
if (timestamp != other.timestamp) {
|
||||
return other.timestamp <=> timestamp;
|
||||
} else {
|
||||
return text <=> other.text;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Alert::SendableAlerts : public wpi::nt::NTSendable,
|
||||
public wpi::util::SendableHelper<SendableAlerts> {
|
||||
public:
|
||||
SendableAlerts() { m_alerts.fill({}); }
|
||||
|
||||
void InitSendable(wpi::nt::NTSendableBuilder& builder) override {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the set of active alerts for the given type.
|
||||
* @param type the type
|
||||
* @return reference to the set of active alerts for the type
|
||||
*/
|
||||
std::set<PublishedAlert>& GetActiveAlertsStorage(AlertType type) {
|
||||
return const_cast<std::set<Alert::PublishedAlert>&>(
|
||||
std::as_const(*this).GetActiveAlertsStorage(type));
|
||||
}
|
||||
|
||||
const std::set<PublishedAlert>& GetActiveAlertsStorage(AlertType type) const {
|
||||
switch (type) {
|
||||
case AlertType::kInfo:
|
||||
case AlertType::kWarning:
|
||||
case AlertType::kError:
|
||||
return m_alerts[static_cast<int32_t>(type)];
|
||||
default:
|
||||
throw WPILIB_MakeError(wpi::err::InvalidParameter,
|
||||
"Invalid Alert Type: {}", type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SendableAlerts for a given group, initializing and publishing
|
||||
* if it does not already exist.
|
||||
* @param group the group name
|
||||
* @return the SendableAlerts for the group
|
||||
*/
|
||||
static SendableAlerts& ForGroup(std::string_view group) {
|
||||
SendableAlerts* salert = nullptr;
|
||||
try {
|
||||
auto* sendable = wpi::SmartDashboard::GetData(group);
|
||||
salert = dynamic_cast<SendableAlerts*>(sendable);
|
||||
} catch (wpi::RuntimeError&) {
|
||||
}
|
||||
if (!salert) {
|
||||
// this leaks if ResetSmartDashboardInstance is called, but that's fine
|
||||
salert = new Alert::SendableAlerts;
|
||||
wpi::SmartDashboard::PutData(group, salert);
|
||||
}
|
||||
return *salert;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> GetStrings(AlertType type) const {
|
||||
auto& set = GetActiveAlertsStorage(type);
|
||||
std::vector<std::string> output;
|
||||
output.reserve(set.size());
|
||||
for (auto& alert : set) {
|
||||
output.emplace_back(alert.text);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
std::array<std::set<PublishedAlert>, 3> m_alerts;
|
||||
};
|
||||
|
||||
Alert::Alert(std::string_view text, AlertType type)
|
||||
: Alert("Alerts", text, type) {}
|
||||
|
||||
Alert::Alert(std::string_view group, std::string_view text, AlertType type)
|
||||
: m_type(type),
|
||||
m_text(text),
|
||||
m_activeAlerts{
|
||||
&SendableAlerts::ForGroup(group).GetActiveAlertsStorage(m_type)} {}
|
||||
|
||||
Alert::Alert(Alert&& other)
|
||||
: m_type{other.m_type},
|
||||
m_text{std::move(other.m_text)},
|
||||
m_activeAlerts{std::exchange(other.m_activeAlerts, nullptr)},
|
||||
m_active{std::exchange(other.m_active, false)},
|
||||
m_activeStartTime{other.m_activeStartTime} {}
|
||||
|
||||
Alert& Alert::operator=(Alert&& other) {
|
||||
if (&other != this) {
|
||||
// We want to destroy current state after the move is done
|
||||
Alert tmp{std::move(*this)};
|
||||
// Now, swap moved-from state with other state
|
||||
std::swap(m_type, other.m_type);
|
||||
std::swap(m_text, other.m_text);
|
||||
std::swap(m_activeAlerts, other.m_activeAlerts);
|
||||
std::swap(m_active, other.m_active);
|
||||
std::swap(m_activeStartTime, other.m_activeStartTime);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Alert::~Alert() {
|
||||
Set(false);
|
||||
}
|
||||
|
||||
void Alert::Set(bool active) {
|
||||
if (active == m_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
m_activeStartTime = wpi::RobotController::GetTime();
|
||||
m_activeAlerts->emplace(m_activeStartTime, m_text);
|
||||
} else {
|
||||
m_activeAlerts->erase({m_activeStartTime, m_text});
|
||||
}
|
||||
m_active = active;
|
||||
}
|
||||
|
||||
void Alert::SetText(std::string_view text) {
|
||||
if (text == m_text) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string oldText = std::move(m_text);
|
||||
m_text = text;
|
||||
|
||||
if (m_active) {
|
||||
auto iter = m_activeAlerts->find({m_activeStartTime, oldText});
|
||||
auto hint = m_activeAlerts->erase(iter);
|
||||
m_activeAlerts->emplace_hint(hint, m_activeStartTime, m_text);
|
||||
}
|
||||
}
|
||||
|
||||
std::string wpi::format_as(Alert::AlertType type) {
|
||||
switch (type) {
|
||||
case Alert::AlertType::kInfo:
|
||||
return "kInfo";
|
||||
case Alert::AlertType::kWarning:
|
||||
return "kWarning";
|
||||
case Alert::AlertType::kError:
|
||||
return "kError";
|
||||
default:
|
||||
return std::to_string(static_cast<int>(type));
|
||||
}
|
||||
}
|
||||
@@ -4,30 +4,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "wpi/hal/Alert.h"
|
||||
#include "wpi/hal/Types.h"
|
||||
|
||||
namespace wpi {
|
||||
|
||||
/**
|
||||
* 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, with newly activated alerts first.
|
||||
* Persistent alert to be sent to the driver station. Alerts are tagged with a
|
||||
* type of HIGH/ERROR, MEDIUM/WARNING, or LOW/INFO to denote urgency. See
|
||||
* Alert::Level 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, with newly activated alerts first.
|
||||
*
|
||||
* 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 {
|
||||
* wpi::Alert alert{"Something went wrong", wpi::Alert::AlertType::kWarning};
|
||||
* wpi::Alert alert{"Something went wrong", wpi::Alert::Level::WARNING};
|
||||
* }
|
||||
*
|
||||
* Robot::periodic() {
|
||||
@@ -40,28 +38,36 @@ class Alert {
|
||||
/**
|
||||
* Represents an alert's level of urgency.
|
||||
*/
|
||||
enum class AlertType {
|
||||
enum class Level {
|
||||
/**
|
||||
* High priority alert - displayed first on the dashboard with a red "X"
|
||||
* High priority alert - displayed first with a red "X"
|
||||
* symbol. Use this type for problems which will seriously affect the
|
||||
* robot's functionality and thus require immediate attention.
|
||||
*/
|
||||
kError,
|
||||
HIGH = HAL_ALERT_HIGH,
|
||||
|
||||
/** Alternate name for a high priority alert. */
|
||||
ERROR = HIGH,
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Medium priority alert - displayed second with a yellow "!" symbol.
|
||||
* Use this type for problems which could affect the robot's functionality
|
||||
* but do not necessarily require immediate attention.
|
||||
*/
|
||||
kWarning,
|
||||
MEDIUM = HAL_ALERT_MEDIUM,
|
||||
|
||||
/** Alternate name for a medium priority alert. */
|
||||
WARNING = MEDIUM,
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Low priority alert - displayed last 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
|
||||
LOW = HAL_ALERT_LOW,
|
||||
|
||||
/** Alternate name for a low priority alert. */
|
||||
INFO = LOW
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -69,9 +75,9 @@ class Alert {
|
||||
* 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.
|
||||
* @param level Alert urgency level.
|
||||
*/
|
||||
Alert(std::string_view text, AlertType type);
|
||||
Alert(std::string_view text, Level level);
|
||||
|
||||
/**
|
||||
* Creates a new alert. If this is the first to be instantiated in its group,
|
||||
@@ -79,17 +85,9 @@ class Alert {
|
||||
*
|
||||
* @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.
|
||||
* @param level Alert urgency level.
|
||||
*/
|
||||
Alert(std::string_view group, std::string_view text, AlertType type);
|
||||
|
||||
Alert(Alert&&);
|
||||
Alert& operator=(Alert&&);
|
||||
|
||||
Alert(const Alert&) = default;
|
||||
Alert& operator=(const Alert&) = default;
|
||||
|
||||
~Alert();
|
||||
Alert(std::string_view group, std::string_view text, Level level);
|
||||
|
||||
/**
|
||||
* Sets whether the alert should currently be displayed. This method can be
|
||||
@@ -103,7 +101,7 @@ class Alert {
|
||||
* Gets whether the alert is active.
|
||||
* @return whether the alert is active.
|
||||
*/
|
||||
bool Get() const { return m_active; }
|
||||
bool Get() const;
|
||||
|
||||
/**
|
||||
* Updates current alert text. Use this method to dynamically change the
|
||||
@@ -117,25 +115,17 @@ class Alert {
|
||||
* Gets the current alert text.
|
||||
* @return the current text.
|
||||
*/
|
||||
std::string GetText() const { return m_text; }
|
||||
std::string GetText() const;
|
||||
|
||||
/**
|
||||
* Get the type of this alert.
|
||||
* @return the type
|
||||
*/
|
||||
AlertType GetType() const { return m_type; }
|
||||
Level GetType() const { return m_type; }
|
||||
|
||||
private:
|
||||
class PublishedAlert;
|
||||
class SendableAlerts;
|
||||
|
||||
AlertType m_type;
|
||||
std::string m_text;
|
||||
std::set<PublishedAlert>* m_activeAlerts;
|
||||
bool m_active = false;
|
||||
uint64_t m_activeStartTime;
|
||||
Level m_type;
|
||||
wpi::hal::Handle<HAL_AlertHandle, HAL_DestroyAlert> m_handle;
|
||||
};
|
||||
|
||||
std::string format_as(Alert::AlertType type);
|
||||
|
||||
} // namespace wpi
|
||||
70
wpilibc/src/main/native/include/wpi/simulation/AlertSim.hpp
Normal file
70
wpilibc/src/main/native/include/wpi/simulation/AlertSim.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// 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 <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "wpi/driverstation/Alert.hpp"
|
||||
#include "wpi/hal/Types.h"
|
||||
|
||||
namespace wpi::sim {
|
||||
|
||||
/**
|
||||
* Class to get info on simulated alerts.
|
||||
*/
|
||||
class AlertSim final {
|
||||
public:
|
||||
AlertSim() = delete;
|
||||
|
||||
/** Information about an alert. */
|
||||
struct AlertInfo {
|
||||
/** The handle of the alert. */
|
||||
HAL_AlertHandle handle;
|
||||
|
||||
/** The group of the alert. */
|
||||
std::string group;
|
||||
|
||||
/** The text of the alert. */
|
||||
std::string text;
|
||||
|
||||
/** The time the alert became active. 0 if not active. */
|
||||
int64_t activeStartTime;
|
||||
|
||||
/** The level of the alert (HIGH, MEDIUM, or LOW). */
|
||||
Alert::Level level;
|
||||
|
||||
/**
|
||||
* Returns whether the alert is currently active.
|
||||
*
|
||||
* @return true if the alert is active, false otherwise
|
||||
*/
|
||||
bool isActive() const { return activeStartTime != 0; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the number of alerts. Note: this is not guaranteed to be consistent
|
||||
* with the number of alerts returned by GetAll.
|
||||
*
|
||||
* @return the number of alerts
|
||||
*/
|
||||
static int32_t GetCount();
|
||||
|
||||
/**
|
||||
* Gets detailed information about each alert.
|
||||
*
|
||||
* @return Alerts
|
||||
*/
|
||||
static std::vector<AlertInfo> GetAll();
|
||||
|
||||
/**
|
||||
* Resets all alert simulation data.
|
||||
*/
|
||||
static void ResetData();
|
||||
};
|
||||
|
||||
} // namespace wpi::sim
|
||||
Reference in New Issue
Block a user