Update LiveWindow to provide continuous telemetry. (#771)

LiveWindow.updateValues() is now called from IterativeRobotBase on every
loop iteration.  Telemetry for all WPILib classes is enabled by default;
it can be disabled for specific classes using LiveWindow.disableTelemetry(),
or all telemetry can be disabled using LiveWindow.disableAllTelemetry().

This necessitated changing the hook methodology into other classes to
be more property-based rather than each class providing multiple functions.
This had the benefit of reducing boilerplate and increasing consistency.

- Remove NamedSendable, add name to Sendable.

- Provide SendableBase abstract class.

- Deprecate LiveWindow addSensor/addActuator interfaces.

- Add LiveWindow support to drive classes.

- Add addChild() helper functions to Subsystem.

- Fix inheritance hierarchy.  Now only sensors inherit from SensorBase.
  Other devices inherit from some combination of SendableBase, ErrorBase, or
  nothing.
This commit is contained in:
Peter Johnson
2017-12-04 23:28:33 -08:00
committed by GitHub
parent 3befc7015b
commit f9bece2ffb
213 changed files with 3704 additions and 3758 deletions

View File

@@ -0,0 +1,91 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 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. */
/*----------------------------------------------------------------------------*/
#include "SmartDashboard/SendableBase.h"
#include "LiveWindow/LiveWindow.h"
using namespace frc;
/**
* Creates an instance of the sensor base.
*
* @param addLiveWindow if true, add this Sendable to LiveWindow
*/
SendableBase::SendableBase(bool addLiveWindow) {
if (addLiveWindow) LiveWindow::GetInstance()->Add(this);
}
/**
* Free the resources used by this object.
*/
SendableBase::~SendableBase() { LiveWindow::GetInstance()->Remove(this); }
std::string SendableBase::GetName() const {
std::lock_guard<wpi::mutex> lock(m_mutex);
return m_name;
}
void SendableBase::SetName(const llvm::Twine& name) {
std::lock_guard<wpi::mutex> lock(m_mutex);
m_name = name.str();
}
std::string SendableBase::GetSubsystem() const {
std::lock_guard<wpi::mutex> lock(m_mutex);
return m_subsystem;
}
void SendableBase::SetSubsystem(const llvm::Twine& subsystem) {
std::lock_guard<wpi::mutex> lock(m_mutex);
m_subsystem = subsystem.str();
}
/**
* Add a child component.
*
* @param child child component
*/
void SendableBase::AddChild(std::shared_ptr<Sendable> child) {
LiveWindow::GetInstance()->AddChild(this, child);
}
/**
* Add a child component.
*
* @param child child component
*/
void SendableBase::AddChild(void* child) {
LiveWindow::GetInstance()->AddChild(this, child);
}
/**
* Sets the name of the sensor with a channel number.
*
* @param moduleType A string that defines the module name in the label for the
* value
* @param channel The channel number the device is plugged into
*/
void SendableBase::SetName(const llvm::Twine& moduleType, int channel) {
SetName(moduleType + llvm::Twine('[') + llvm::Twine(channel) +
llvm::Twine(']'));
}
/**
* Sets the name of the sensor with a module and channel number.
*
* @param moduleType A string that defines the module name in the label for
* the value
* @param moduleNumber The number of the particular module type
* @param channel The channel number the device is plugged into (usually
* PWM)
*/
void SendableBase::SetName(const llvm::Twine& moduleType, int moduleNumber,
int channel) {
SetName(moduleType + llvm::Twine('[') + llvm::Twine(moduleNumber) +
llvm::Twine(',') + llvm::Twine(channel) + llvm::Twine(']'));
}

View File

@@ -0,0 +1,365 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 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. */
/*----------------------------------------------------------------------------*/
#include "SmartDashboard/SendableBuilderImpl.h"
#include <llvm/SmallString.h>
#include "ntcore_cpp.h"
using namespace frc;
void SendableBuilderImpl::SetTable(std::shared_ptr<nt::NetworkTable> table) {
m_table = table;
}
std::shared_ptr<nt::NetworkTable> SendableBuilderImpl::GetTable() {
return m_table;
}
void SendableBuilderImpl::UpdateTable() {
uint64_t time = nt::Now();
for (auto& property : m_properties) {
if (property.update) property.update(property.entry, time);
}
if (m_updateTable) m_updateTable();
}
void SendableBuilderImpl::StartLiveWindowMode() {
if (m_safeState) m_safeState();
for (auto& property : m_properties) property.StartListener();
}
void SendableBuilderImpl::StopLiveWindowMode() {
if (m_safeState) m_safeState();
for (auto& property : m_properties) property.StopListener();
}
void SendableBuilderImpl::SetSmartDashboardType(const llvm::Twine& type) {
m_table->GetEntry(".type").SetString(type);
}
void SendableBuilderImpl::SetSafeState(std::function<void()> func) {
m_safeState = func;
}
void SendableBuilderImpl::SetUpdateTable(std::function<void()> func) {
m_updateTable = func;
}
nt::NetworkTableEntry SendableBuilderImpl::GetEntry(const llvm::Twine& key) {
return m_table->GetEntry(key);
}
void SendableBuilderImpl::AddBooleanProperty(const llvm::Twine& key,
std::function<bool()> getter,
std::function<void(bool)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
entry.SetValue(nt::Value::MakeBoolean(getter(), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsBoolean()) return;
setter(event.value->GetBoolean());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddDoubleProperty(
const llvm::Twine& key, std::function<double()> getter,
std::function<void(double)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
entry.SetValue(nt::Value::MakeDouble(getter(), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsDouble()) return;
setter(event.value->GetDouble());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddStringProperty(
const llvm::Twine& key, std::function<std::string()> getter,
std::function<void(llvm::StringRef)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
entry.SetValue(nt::Value::MakeString(getter(), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsString()) return;
setter(event.value->GetString());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddBooleanArrayProperty(
const llvm::Twine& key, std::function<std::vector<int>()> getter,
std::function<void(llvm::ArrayRef<int>)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
entry.SetValue(nt::Value::MakeBooleanArray(getter(), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsBooleanArray()) return;
setter(event.value->GetBooleanArray());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddDoubleArrayProperty(
const llvm::Twine& key, std::function<std::vector<double>()> getter,
std::function<void(llvm::ArrayRef<double>)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
entry.SetValue(nt::Value::MakeDoubleArray(getter(), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsDoubleArray()) return;
setter(event.value->GetDoubleArray());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddStringArrayProperty(
const llvm::Twine& key, std::function<std::vector<std::string>()> getter,
std::function<void(llvm::ArrayRef<std::string>)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
entry.SetValue(nt::Value::MakeStringArray(getter(), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsStringArray()) return;
setter(event.value->GetStringArray());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddRawProperty(
const llvm::Twine& key, std::function<std::string()> getter,
std::function<void(llvm::StringRef)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
entry.SetValue(nt::Value::MakeRaw(getter(), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsRaw()) return;
setter(event.value->GetRaw());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddValueProperty(
const llvm::Twine& key, std::function<std::shared_ptr<nt::Value>()> getter,
std::function<void(std::shared_ptr<nt::Value>)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
entry.SetValue(getter());
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) { setter(event.value); },
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddSmallStringProperty(
const llvm::Twine& key,
std::function<llvm::StringRef(llvm::SmallVectorImpl<char>& buf)> getter,
std::function<void(llvm::StringRef)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
llvm::SmallString<128> buf;
entry.SetValue(nt::Value::MakeString(getter(buf), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsString()) return;
setter(event.value->GetString());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddSmallBooleanArrayProperty(
const llvm::Twine& key,
std::function<llvm::ArrayRef<int>(llvm::SmallVectorImpl<int>& buf)> getter,
std::function<void(llvm::ArrayRef<int>)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
llvm::SmallVector<int, 16> buf;
entry.SetValue(nt::Value::MakeBooleanArray(getter(buf), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsBooleanArray()) return;
setter(event.value->GetBooleanArray());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddSmallDoubleArrayProperty(
const llvm::Twine& key,
std::function<llvm::ArrayRef<double>(llvm::SmallVectorImpl<double>& buf)>
getter,
std::function<void(llvm::ArrayRef<double>)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
llvm::SmallVector<double, 16> buf;
entry.SetValue(nt::Value::MakeDoubleArray(getter(buf), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsDoubleArray()) return;
setter(event.value->GetDoubleArray());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddSmallStringArrayProperty(
const llvm::Twine& key,
std::function<
llvm::ArrayRef<std::string>(llvm::SmallVectorImpl<std::string>& buf)>
getter,
std::function<void(llvm::ArrayRef<std::string>)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
llvm::SmallVector<std::string, 16> buf;
entry.SetValue(nt::Value::MakeStringArray(getter(buf), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsStringArray()) return;
setter(event.value->GetStringArray());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}
void SendableBuilderImpl::AddSmallRawProperty(
const llvm::Twine& key,
std::function<llvm::StringRef(llvm::SmallVectorImpl<char>& buf)> getter,
std::function<void(llvm::StringRef)> setter) {
m_properties.emplace_back(*m_table, key);
if (getter) {
m_properties.back().update = [=](nt::NetworkTableEntry entry,
uint64_t time) {
llvm::SmallVector<char, 128> buf;
entry.SetValue(nt::Value::MakeRaw(getter(buf), time));
};
}
if (setter) {
m_properties.back().createListener =
[=](nt::NetworkTableEntry entry) -> NT_EntryListener {
return entry.AddListener(
[=](const nt::EntryNotification& event) {
if (!event.value->IsRaw()) return;
setter(event.value->GetRaw());
},
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_NEW | NT_NOTIFY_UPDATE);
};
}
}

View File

@@ -12,7 +12,3 @@ using namespace frc;
const char* SendableChooserBase::kDefault = "default";
const char* SendableChooserBase::kOptions = "options";
const char* SendableChooserBase::kSelected = "selected";
std::string SendableChooserBase::GetSmartDashboardType() const {
return "String Chooser";
}

View File

@@ -7,18 +7,28 @@
#include "SmartDashboard/SmartDashboard.h"
#include <map>
#include <llvm/StringMap.h>
#include <support/mutex.h>
#include "HLUsageReporting.h"
#include "SmartDashboard/NamedSendable.h"
#include "SmartDashboard/Sendable.h"
#include "SmartDashboard/SendableBuilderImpl.h"
#include "WPIErrors.h"
#include "networktables/NetworkTable.h"
#include "networktables/NetworkTableInstance.h"
using namespace frc;
namespace {
struct SmartDashboardData {
Sendable* sendable = nullptr;
SendableBuilderImpl builder;
};
} // namespace
static std::shared_ptr<nt::NetworkTable> s_table;
static std::map<std::shared_ptr<nt::NetworkTable>, Sendable*> s_tablesToData;
static llvm::StringMap<SmartDashboardData> s_tablesToData;
static wpi::mutex s_tablesToDataMutex;
void SmartDashboard::init() {
s_table = nt::NetworkTableInstance::GetDefault().GetTable("SmartDashboard");
@@ -126,22 +136,26 @@ void SmartDashboard::PutData(llvm::StringRef key, Sendable* data) {
wpi_setGlobalWPIErrorWithContext(NullParameter, "value");
return;
}
std::shared_ptr<nt::NetworkTable> dataTable(s_table->GetSubTable(key));
dataTable->GetEntry(".type").SetString(data->GetSmartDashboardType());
data->InitTable(dataTable);
s_tablesToData[dataTable] = data;
std::lock_guard<wpi::mutex> lock(s_tablesToDataMutex);
auto& sddata = s_tablesToData[key];
if (!sddata.sendable || sddata.sendable != data) {
sddata.sendable = data;
sddata.builder.SetTable(s_table->GetSubTable(key));
data->InitSendable(sddata.builder);
}
sddata.builder.UpdateTable();
}
/**
* Maps the specified key (where the key is the name of the
* {@link SmartDashboardNamedData} to the specified value in this table.
* Maps the specified key (where the key is the name of the Sendable)
* to the specified value in this table.
*
* The value can be retrieved by calling the get method with a key that is equal
* to the original key.
*
* @param value the value
*/
void SmartDashboard::PutData(NamedSendable* value) {
void SmartDashboard::PutData(Sendable* value) {
if (value == nullptr) {
wpi_setGlobalWPIErrorWithContext(NullParameter, "value");
return;
@@ -156,13 +170,13 @@ void SmartDashboard::PutData(NamedSendable* value) {
* @return the value
*/
Sendable* SmartDashboard::GetData(llvm::StringRef key) {
std::shared_ptr<nt::NetworkTable> subtable(s_table->GetSubTable(key));
Sendable* data = s_tablesToData[subtable];
if (data == nullptr) {
std::lock_guard<wpi::mutex> lock(s_tablesToDataMutex);
auto data = s_tablesToData.find(key);
if (data == s_tablesToData.end()) {
wpi_setGlobalWPIErrorWithContext(SmartDashboardMissingKey, key);
return nullptr;
}
return data;
return data->getValue().sendable;
}
/**