Skip to content

Commit

Permalink
Most of c++ impl
Browse files Browse the repository at this point in the history
Need to look it over some more and write some more comprehensive tests
  • Loading branch information
rzblue committed Oct 18, 2024
1 parent f925ef3 commit 1417755
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 32 deletions.
98 changes: 75 additions & 23 deletions wpilibc/src/main/native/cpp/Alert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,71 @@

#include "frc/Alert.h"

#include <frc/RobotController.h>

#include <algorithm>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include <fmt/format.h>
#include <networktables/NTSendableBuilder.h>

#include "frc/Timer.h"
#include "frc/Errors.h"
#include "frc/smartdashboard/SmartDashboard.h"

using namespace frc;

wpi::StringMap<Alert::SendableAlerts> Alert::groups;

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) {
: m_type(type), m_text(text), m_group{group} {
if (!groups.contains(group)) {
groups[group] = SendableAlerts();
frc::SmartDashboard::PutData(group, &groups[group]);
frc::SmartDashboard::PutData(group,
&groups.try_emplace(group).first->getValue());
}
groups[group].m_alerts.push_back(std::shared_ptr<Alert>(this));
}

Alert::~Alert() {
Set(false);
}

void Alert::Set(bool active) {
if (active && !m_active) {
m_activeStartTime = frc::Timer::GetFPGATimestamp();
if (active == m_active) {
return;
}

if (active) {
m_activeStartTime = frc::RobotController::GetFPGATime();
groups[m_group].GetSetForType(m_type).emplace(m_activeStartTime, m_text);
} else {
groups[m_group].GetSetForType(m_type).erase({m_activeStartTime, m_text});
}
m_active = active;
}

void Alert::SetText(std::string_view text) {
if (text == m_text) {
return;
}

if (m_active) {
auto set = groups[m_group].GetSetForType(m_type);
auto iter = set.find({m_activeStartTime, m_text});
auto hint = set.erase(iter);
set.emplace_hint(hint, m_activeStartTime, m_text);
}
m_text = text;
}

Alert::SendableAlerts::SendableAlerts() {
m_alerts.fill({});
}

void Alert::SendableAlerts::InitSendable(nt::NTSendableBuilder& builder) {
builder.SetSmartDashboardType("Alerts");
builder.AddStringArrayProperty(
Expand All @@ -51,22 +80,45 @@ void Alert::SendableAlerts::InitSendable(nt::NTSendableBuilder& builder) {
"infos", [this]() { return GetStrings(AlertType::kInfo); }, nullptr);
}

std::vector<std::string> Alert::SendableAlerts::GetStrings(
std::set<Alert::PublishedAlert>& Alert::SendableAlerts::GetSetForType(
AlertType type) {
return const_cast<std::set<Alert::PublishedAlert>&>(
std::as_const(*this).GetSetForType(type));
}

const std::set<Alert::PublishedAlert>& Alert::SendableAlerts::GetSetForType(
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);
}
switch (type) {
case AlertType::kInfo:
case AlertType::kWarning:
case AlertType::kError:
return m_alerts[static_cast<int32_t>(type)];
default:
throw FRC_MakeError(frc::err::InvalidParameter, "Invalid Alert Type: {}",
type);
}
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;
}

std::vector<std::string> Alert::SendableAlerts::GetStrings(
AlertType type) const {
auto set = GetSetForType(type);
std::vector<std::string> output;
output.reserve(set.size());
for (auto& alert : set) {
output.emplace_back(alert.text);
}
return output;
}

std::string frc::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 fmt::format("{}", fmt::underlying(type));
}
}
31 changes: 27 additions & 4 deletions wpilibc/src/main/native/include/frc/Alert.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@

#pragma once

#include <stdint.h>

#include <array>
#include <memory>
#include <set>
#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>
Expand Down Expand Up @@ -88,6 +91,11 @@ class Alert {
*/
Alert(std::string_view group, std::string_view text, AlertType type);

Alert(Alert&&) = default;
Alert& operator=(Alert&&) = default;

~Alert();

/**
* Sets whether the alert should currently be displayed. This method can be
* safely called periodically.
Expand All @@ -106,21 +114,36 @@ class Alert {

private:
AlertType m_type;
std::string m_text;
std::string m_group; // todo: could store iterator or reference to the actual
// SendableAlerts, would remove lookup
bool m_active = false;
units::second_t m_activeStartTime;
std::string_view m_text;
uint64_t m_activeStartTime;
class PublishedAlert {
public:
uint64_t timestamp;
std::string text; // todo: This could be a string_view since deleting the
// Alert will erase this from the set
auto operator<=>(const PublishedAlert&) const = default;
};

class SendableAlerts : public nt::NTSendable,
public wpi::SendableHelper<SendableAlerts> {
public:
wpi::SmallVector<std::shared_ptr<Alert>> m_alerts;
SendableAlerts();
void InitSendable(nt::NTSendableBuilder& builder) override;

std::set<PublishedAlert>& GetSetForType(AlertType type);
const std::set<PublishedAlert>& GetSetForType(AlertType type) const;

private:
std::vector<std::string> GetStrings(AlertType type) const;
std::array<std::set<PublishedAlert>, 3> m_alerts;
};

static wpi::StringMap<SendableAlerts> groups;
};

std::string format_as(Alert::AlertType type);

} // namespace frc
18 changes: 13 additions & 5 deletions wpilibc/src/test/native/cpp/AlertsTest.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
#include <gtest/gtest.h>
// 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 <fmt/format.h>

#include <chrono>
TEST(AlertsTest, SmokeTest) {

#include <fmt/format.h>
#include <gtest/gtest.h>

TEST(AlertsTest, Smoke) {
{ frc::Alert("Thing A", frc::Alert::AlertType::kError); }
frc::Alert a{"", frc::Alert::AlertType::kInfo};
{
std::string s = fmt::format("{}", std::chrono::steady_clock::now().time_since_epoch().count());
std::string s = fmt::format(
"{}", std::chrono::steady_clock::now().time_since_epoch().count());
a = frc::Alert(s, frc::Alert::AlertType::kError);
}
}
}

0 comments on commit 1417755

Please sign in to comment.