mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
SCRIPT: wpiformat
This commit is contained in:
committed by
Peter Johnson
parent
ae6bdc9d25
commit
2109161534
@@ -152,8 +152,8 @@ static void SetupUdp(wpi::net::uv::Loop& loop) {
|
||||
outAddr.sin_port = htons(1150);
|
||||
|
||||
wpi::util::SmallVector<wpi::net::uv::Buffer, 4> sendBufs;
|
||||
wpi::net::raw_uv_ostream stream{sendBufs,
|
||||
[] { return GetBufferPool().Allocate(); }};
|
||||
wpi::net::raw_uv_ostream stream{
|
||||
sendBufs, [] { return GetBufferPool().Allocate(); }};
|
||||
ds->SetupSendBuffer(stream);
|
||||
|
||||
udpLocal->Send(outAddr, sendBufs, [](auto bufs, Error err) {
|
||||
|
||||
@@ -48,9 +48,9 @@ class AddressableLEDsModel : public wpi::glass::LEDDisplaysModel {
|
||||
|
||||
size_t GetNumLEDDisplays() override { return m_models.size(); }
|
||||
|
||||
void ForEachLEDDisplay(
|
||||
wpi::util::function_ref<void(wpi::glass::LEDDisplayModel& model, int channel)> func)
|
||||
override;
|
||||
void ForEachLEDDisplay(wpi::util::function_ref<
|
||||
void(wpi::glass::LEDDisplayModel& model, int channel)>
|
||||
func) override;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<AddressableLEDModel>> m_models;
|
||||
@@ -83,7 +83,9 @@ bool AddressableLEDsModel::Exists() {
|
||||
}
|
||||
|
||||
void AddressableLEDsModel::ForEachLEDDisplay(
|
||||
wpi::util::function_ref<void(wpi::glass::LEDDisplayModel& model, int channel)> func) {
|
||||
wpi::util::function_ref<void(wpi::glass::LEDDisplayModel& model,
|
||||
int channel)>
|
||||
func) {
|
||||
for (int i = 0; i < static_cast<int>(m_models.size()); ++i) {
|
||||
if (m_models[i]) {
|
||||
func(*m_models[i], i);
|
||||
@@ -109,7 +111,8 @@ void AddressableLEDGui::Initialize() {
|
||||
win->SetFlags(ImGuiWindowFlags_AlwaysAutoResize);
|
||||
win->SetDefaultPos(290, 100);
|
||||
return wpi::glass::MakeFunctionView([=] {
|
||||
wpi::glass::DisplayLEDDisplays(static_cast<AddressableLEDsModel*>(model));
|
||||
wpi::glass::DisplayLEDDisplays(
|
||||
static_cast<AddressableLEDsModel*>(model));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,9 +56,9 @@ class AnalogInputsSimModel : public wpi::glass::AnalogInputsModel {
|
||||
|
||||
bool Exists() override { return true; }
|
||||
|
||||
void ForEachAnalogInput(
|
||||
wpi::util::function_ref<void(wpi::glass::AnalogInputModel& model, int index)> func)
|
||||
override;
|
||||
void ForEachAnalogInput(wpi::util::function_ref<
|
||||
void(wpi::glass::AnalogInputModel& model, int index)>
|
||||
func) override;
|
||||
|
||||
private:
|
||||
// indexed by channel
|
||||
@@ -81,7 +81,9 @@ void AnalogInputsSimModel::Update() {
|
||||
}
|
||||
|
||||
void AnalogInputsSimModel::ForEachAnalogInput(
|
||||
wpi::util::function_ref<void(wpi::glass::AnalogInputModel& model, int index)> func) {
|
||||
wpi::util::function_ref<void(wpi::glass::AnalogInputModel& model,
|
||||
int index)>
|
||||
func) {
|
||||
for (int32_t i = 0, iend = static_cast<int32_t>(m_models.size()); i < iend;
|
||||
++i) {
|
||||
if (auto model = m_models[i].get()) {
|
||||
@@ -108,7 +110,8 @@ void AnalogInputSimGui::Initialize() {
|
||||
win->SetFlags(ImGuiWindowFlags_AlwaysAutoResize);
|
||||
win->SetDefaultPos(640, 20);
|
||||
return wpi::glass::MakeFunctionView([=] {
|
||||
wpi::glass::DisplayAnalogInputs(static_cast<AnalogInputsSimModel*>(model));
|
||||
wpi::glass::DisplayAnalogInputs(
|
||||
static_cast<AnalogInputsSimModel*>(model));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,7 +138,8 @@ class DIOsSimModel : public wpi::glass::DIOsModel {
|
||||
bool Exists() override { return true; }
|
||||
|
||||
void ForEachDIO(
|
||||
wpi::util::function_ref<void(wpi::glass::DIOModel& model, int index)> func) override;
|
||||
wpi::util::function_ref<void(wpi::glass::DIOModel& model, int index)>
|
||||
func) override;
|
||||
|
||||
private:
|
||||
// indexed by channel
|
||||
@@ -210,7 +211,8 @@ void DIOsSimModel::Update() {
|
||||
}
|
||||
|
||||
void DIOsSimModel::ForEachDIO(
|
||||
wpi::util::function_ref<void(wpi::glass::DIOModel& model, int index)> func) {
|
||||
wpi::util::function_ref<void(wpi::glass::DIOModel& model, int index)>
|
||||
func) {
|
||||
const int32_t numDIO = m_dioModels.size();
|
||||
for (int32_t i = 0; i < numDIO; ++i) {
|
||||
if (auto model = m_dioModels[i].get()) {
|
||||
@@ -237,7 +239,7 @@ void DIOSimGui::Initialize() {
|
||||
win->SetDefaultPos(470, 20);
|
||||
return wpi::glass::MakeFunctionView([=] {
|
||||
wpi::glass::DisplayDIOs(static_cast<DIOsSimModel*>(model),
|
||||
HALSimGui::halProvider->AreOutputsEnabled());
|
||||
HALSimGui::halProvider->AreOutputsEnabled());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -214,8 +214,12 @@ class FMSSimModel : public wpi::glass::FMSModel {
|
||||
public:
|
||||
FMSSimModel();
|
||||
|
||||
wpi::glass::BooleanSource* GetFmsAttachedData() override { return &m_fmsAttached; }
|
||||
wpi::glass::BooleanSource* GetDsAttachedData() override { return &m_dsAttached; }
|
||||
wpi::glass::BooleanSource* GetFmsAttachedData() override {
|
||||
return &m_fmsAttached;
|
||||
}
|
||||
wpi::glass::BooleanSource* GetDsAttachedData() override {
|
||||
return &m_dsAttached;
|
||||
}
|
||||
wpi::glass::IntegerSource* GetAllianceStationIdData() override {
|
||||
return &m_allianceStationId;
|
||||
}
|
||||
@@ -223,7 +227,9 @@ class FMSSimModel : public wpi::glass::FMSModel {
|
||||
wpi::glass::BooleanSource* GetEStopData() override { return &m_estop; }
|
||||
wpi::glass::BooleanSource* GetEnabledData() override { return &m_enabled; }
|
||||
wpi::glass::BooleanSource* GetTestData() override { return &m_test; }
|
||||
wpi::glass::BooleanSource* GetAutonomousData() override { return &m_autonomous; }
|
||||
wpi::glass::BooleanSource* GetAutonomousData() override {
|
||||
return &m_autonomous;
|
||||
}
|
||||
wpi::glass::StringSource* GetGameSpecificMessageData() override {
|
||||
return &m_gameMessage;
|
||||
}
|
||||
@@ -562,10 +568,11 @@ void KeyboardJoystick::EditKey(const char* label, int* key) {
|
||||
|
||||
char editLabel[32];
|
||||
if (s_keyEdit == key) {
|
||||
wpi::util::format_to_n_c_str(editLabel, sizeof(editLabel), "(press key)###edit");
|
||||
wpi::util::format_to_n_c_str(editLabel, sizeof(editLabel),
|
||||
"(press key)###edit");
|
||||
} else {
|
||||
wpi::util::format_to_n_c_str(editLabel, sizeof(editLabel), "{}###edit",
|
||||
GetKeyName(*key));
|
||||
GetKeyName(*key));
|
||||
}
|
||||
|
||||
if (ImGui::SmallButton(editLabel)) {
|
||||
@@ -842,7 +849,8 @@ void KeyboardJoystick::ClearKey(int key) {
|
||||
}
|
||||
}
|
||||
|
||||
GlfwKeyboardJoystick::GlfwKeyboardJoystick(wpi::glass::Storage& storage, int index)
|
||||
GlfwKeyboardJoystick::GlfwKeyboardJoystick(wpi::glass::Storage& storage,
|
||||
int index)
|
||||
: KeyboardJoystick{storage, index} {
|
||||
// set up a default keyboard config for 0, 1, and 2
|
||||
if (index == 0) {
|
||||
@@ -1216,7 +1224,8 @@ bool FMSSimModel::IsReadOnly() {
|
||||
|
||||
static void DisplaySystemJoystick(SystemJoystick& joy, int i) {
|
||||
char label[64];
|
||||
wpi::util::format_to_n_c_str(label, sizeof(label), "{}: {}", i, joy.GetName());
|
||||
wpi::util::format_to_n_c_str(label, sizeof(label), "{}: {}", i,
|
||||
joy.GetName());
|
||||
|
||||
// highlight if any buttons pressed
|
||||
bool anyButtonPressed = joy.IsAnyButtonPressed();
|
||||
@@ -1250,7 +1259,8 @@ static void DisplaySystemJoysticks() {
|
||||
DisplaySystemJoystick(*joy, i + GLFW_JOYSTICK_LAST + 1);
|
||||
if (ImGui::BeginPopupContextItem()) {
|
||||
char buf[64];
|
||||
wpi::util::format_to_n_c_str(buf, sizeof(buf), "{} Settings", joy->GetName());
|
||||
wpi::util::format_to_n_c_str(buf, sizeof(buf), "{} Settings",
|
||||
joy->GetName());
|
||||
|
||||
if (ImGui::MenuItem(buf)) {
|
||||
if (auto win = DriverStationGui::dsManager->GetWindow(buf)) {
|
||||
@@ -1300,8 +1310,8 @@ static void DisplayJoysticks() {
|
||||
joy.sys = payload_sys;
|
||||
joy.guid = payload_sys->GetGUID();
|
||||
std::string_view name{payload_sys->GetName()};
|
||||
joy.useGamepad =
|
||||
wpi::util::starts_with(name, "Xbox") || wpi::util::contains(name, "pad");
|
||||
joy.useGamepad = wpi::util::starts_with(name, "Xbox") ||
|
||||
wpi::util::contains(name, "pad");
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
@@ -1460,7 +1470,7 @@ void DriverStationGui::GlobalInit() {
|
||||
for (auto&& joy : gKeyboardJoysticks) {
|
||||
char label[64];
|
||||
wpi::util::format_to_n_c_str(label, sizeof(label), "{} Settings",
|
||||
joy->GetName());
|
||||
joy->GetName());
|
||||
|
||||
if (auto win = dsManager->AddWindow(
|
||||
label, [j = joy.get()] { j->SettingsDisplay(); },
|
||||
|
||||
@@ -93,7 +93,9 @@ class EncoderSimModel : public wpi::glass::EncoderModel {
|
||||
}
|
||||
wpi::glass::IntegerSource* GetCountData() override { return &m_count; }
|
||||
wpi::glass::DoubleSource* GetPeriodData() override { return &m_period; }
|
||||
wpi::glass::BooleanSource* GetDirectionData() override { return &m_direction; }
|
||||
wpi::glass::BooleanSource* GetDirectionData() override {
|
||||
return &m_direction;
|
||||
}
|
||||
wpi::glass::DoubleSource* GetDistanceData() override { return &m_distance; }
|
||||
wpi::glass::DoubleSource* GetRateData() override { return &m_rate; }
|
||||
|
||||
@@ -201,8 +203,8 @@ class EncodersSimModel : public wpi::glass::EncodersModel {
|
||||
bool Exists() override { return true; }
|
||||
|
||||
void ForEachEncoder(
|
||||
wpi::util::function_ref<void(wpi::glass::EncoderModel& model, int index)> func)
|
||||
override;
|
||||
wpi::util::function_ref<void(wpi::glass::EncoderModel& model, int index)>
|
||||
func) override;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<EncoderSimModel>> m_models;
|
||||
@@ -224,7 +226,8 @@ void EncodersSimModel::Update() {
|
||||
}
|
||||
|
||||
void EncodersSimModel::ForEachEncoder(
|
||||
wpi::util::function_ref<void(wpi::glass::EncoderModel& model, int index)> func) {
|
||||
wpi::util::function_ref<void(wpi::glass::EncoderModel& model, int index)>
|
||||
func) {
|
||||
for (int32_t i = 0, iend = static_cast<int32_t>(m_models.size()); i < iend;
|
||||
++i) {
|
||||
if (auto model = m_models[i].get()) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace wpi::glass {
|
||||
class EncodersModel;
|
||||
} // namespace glass
|
||||
} // namespace wpi::glass
|
||||
|
||||
namespace halsimgui {
|
||||
|
||||
|
||||
@@ -95,9 +95,9 @@ void HALProvider::Show(ViewEntry* entry, wpi::glass::Window* window) {
|
||||
|
||||
// the window might exist and we're just not associated to it yet
|
||||
if (!window) {
|
||||
window = GetOrAddWindow(
|
||||
entry->name, true,
|
||||
entry->showDefault ? wpi::glass::Window::kShow : wpi::glass::Window::kHide);
|
||||
window = GetOrAddWindow(entry->name, true,
|
||||
entry->showDefault ? wpi::glass::Window::kShow
|
||||
: wpi::glass::Window::kHide);
|
||||
}
|
||||
if (!window) {
|
||||
return;
|
||||
|
||||
@@ -23,9 +23,10 @@ void NetworkTablesSimGui::Initialize() {
|
||||
wpi::gui::AddEarlyExecute([] { gNetworkTablesModel->Update(); });
|
||||
|
||||
gNetworkTablesWindow = std::make_unique<wpi::glass::Window>(
|
||||
wpi::glass::GetStorageRoot().GetChild("NetworkTables View"), "NetworkTables");
|
||||
gNetworkTablesWindow->SetView(
|
||||
std::make_unique<wpi::glass::NetworkTablesView>(gNetworkTablesModel.get()));
|
||||
wpi::glass::GetStorageRoot().GetChild("NetworkTables View"),
|
||||
"NetworkTables");
|
||||
gNetworkTablesWindow->SetView(std::make_unique<wpi::glass::NetworkTablesView>(
|
||||
gNetworkTablesModel.get()));
|
||||
gNetworkTablesWindow->SetDefaultPos(250, 277);
|
||||
gNetworkTablesWindow->SetDefaultSize(750, 185);
|
||||
gNetworkTablesWindow->DisableRenamePopup();
|
||||
@@ -35,8 +36,9 @@ void NetworkTablesSimGui::Initialize() {
|
||||
gNetworkTablesInfoWindow = std::make_unique<wpi::glass::Window>(
|
||||
wpi::glass::GetStorageRoot().GetChild("NetworkTables Info"),
|
||||
"NetworkTables Info");
|
||||
gNetworkTablesInfoWindow->SetView(wpi::glass::MakeFunctionView(
|
||||
[&] { wpi::glass::DisplayNetworkTablesInfo(gNetworkTablesModel.get()); }));
|
||||
gNetworkTablesInfoWindow->SetView(wpi::glass::MakeFunctionView([&] {
|
||||
wpi::glass::DisplayNetworkTablesInfo(gNetworkTablesModel.get());
|
||||
}));
|
||||
gNetworkTablesInfoWindow->SetDefaultPos(250, 130);
|
||||
gNetworkTablesInfoWindow->SetDefaultSize(750, 145);
|
||||
gNetworkTablesInfoWindow->SetDefaultVisibility(wpi::glass::Window::kHide);
|
||||
|
||||
@@ -103,8 +103,8 @@ class PCMSimModel : public wpi::glass::PneumaticControlModel {
|
||||
CompressorSimModel* GetCompressor() override { return &m_compressor; }
|
||||
|
||||
void ForEachSolenoid(
|
||||
wpi::util::function_ref<void(wpi::glass::SolenoidModel& model, int index)> func)
|
||||
override;
|
||||
wpi::util::function_ref<void(wpi::glass::SolenoidModel& model, int index)>
|
||||
func) override;
|
||||
|
||||
std::string_view GetName() override { return "PCM"; }
|
||||
|
||||
@@ -126,7 +126,8 @@ class PCMsSimModel : public wpi::glass::PneumaticControlsModel {
|
||||
bool Exists() override { return true; }
|
||||
|
||||
void ForEachPneumaticControl(
|
||||
wpi::util::function_ref<void(wpi::glass::PneumaticControlModel& model, int index)>
|
||||
wpi::util::function_ref<void(wpi::glass::PneumaticControlModel& model,
|
||||
int index)>
|
||||
func) override;
|
||||
|
||||
private:
|
||||
@@ -151,7 +152,8 @@ void PCMSimModel::Update() {
|
||||
}
|
||||
|
||||
void PCMSimModel::ForEachSolenoid(
|
||||
wpi::util::function_ref<void(wpi::glass::SolenoidModel& model, int index)> func) {
|
||||
wpi::util::function_ref<void(wpi::glass::SolenoidModel& model, int index)>
|
||||
func) {
|
||||
if (m_solenoidInitCount == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -179,7 +181,8 @@ void PCMsSimModel::Update() {
|
||||
}
|
||||
|
||||
void PCMsSimModel::ForEachPneumaticControl(
|
||||
wpi::util::function_ref<void(wpi::glass::PneumaticControlModel& model, int index)>
|
||||
wpi::util::function_ref<void(wpi::glass::PneumaticControlModel& model,
|
||||
int index)>
|
||||
func) {
|
||||
int32_t numCTREPCMs = m_models.size();
|
||||
for (int32_t i = 0; i < numCTREPCMs; ++i) {
|
||||
@@ -220,7 +223,8 @@ void PCMSimGui::Initialize() {
|
||||
[] { return std::make_unique<PCMsSimModel>(); });
|
||||
|
||||
SimDeviceGui::GetDeviceTree().Add(
|
||||
HALSimGui::halProvider->GetModel("CTREPCMs"), [](wpi::glass::Model* model) {
|
||||
HALSimGui::halProvider->GetModel("CTREPCMs"),
|
||||
[](wpi::glass::Model* model) {
|
||||
wpi::glass::DisplayCompressorsDevice(
|
||||
static_cast<PCMsSimModel*>(model),
|
||||
HALSimGui::halProvider->AreOutputsEnabled());
|
||||
|
||||
@@ -98,8 +98,8 @@ class PHSimModel : public wpi::glass::PneumaticControlModel {
|
||||
CompressorSimModel* GetCompressor() override { return &m_compressor; }
|
||||
|
||||
void ForEachSolenoid(
|
||||
wpi::util::function_ref<void(wpi::glass::SolenoidModel& model, int index)> func)
|
||||
override;
|
||||
wpi::util::function_ref<void(wpi::glass::SolenoidModel& model, int index)>
|
||||
func) override;
|
||||
|
||||
std::string_view GetName() override { return "PH"; }
|
||||
|
||||
@@ -121,7 +121,8 @@ class PHsSimModel : public wpi::glass::PneumaticControlsModel {
|
||||
bool Exists() override { return true; }
|
||||
|
||||
void ForEachPneumaticControl(
|
||||
wpi::util::function_ref<void(wpi::glass::PneumaticControlModel& model, int index)>
|
||||
wpi::util::function_ref<void(wpi::glass::PneumaticControlModel& model,
|
||||
int index)>
|
||||
func) override;
|
||||
|
||||
private:
|
||||
@@ -146,7 +147,8 @@ void PHSimModel::Update() {
|
||||
}
|
||||
|
||||
void PHSimModel::ForEachSolenoid(
|
||||
wpi::util::function_ref<void(wpi::glass::SolenoidModel& model, int index)> func) {
|
||||
wpi::util::function_ref<void(wpi::glass::SolenoidModel& model, int index)>
|
||||
func) {
|
||||
if (m_solenoidInitCount == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -174,7 +176,8 @@ void PHsSimModel::Update() {
|
||||
}
|
||||
|
||||
void PHsSimModel::ForEachPneumaticControl(
|
||||
wpi::util::function_ref<void(wpi::glass::PneumaticControlModel& model, int index)>
|
||||
wpi::util::function_ref<void(wpi::glass::PneumaticControlModel& model,
|
||||
int index)>
|
||||
func) {
|
||||
int32_t numREVPHs = m_models.size();
|
||||
for (int32_t i = 0; i < numREVPHs; ++i) {
|
||||
|
||||
@@ -47,7 +47,8 @@ class PWMsSimModel : public wpi::glass::PWMsModel {
|
||||
bool Exists() override { return true; }
|
||||
|
||||
void ForEachPWM(
|
||||
wpi::util::function_ref<void(wpi::glass::PWMModel& model, int index)> func) override;
|
||||
wpi::util::function_ref<void(wpi::glass::PWMModel& model, int index)>
|
||||
func) override;
|
||||
|
||||
private:
|
||||
// indexed by channel
|
||||
@@ -70,7 +71,8 @@ void PWMsSimModel::Update() {
|
||||
}
|
||||
|
||||
void PWMsSimModel::ForEachPWM(
|
||||
wpi::util::function_ref<void(wpi::glass::PWMModel& model, int index)> func) {
|
||||
wpi::util::function_ref<void(wpi::glass::PWMModel& model, int index)>
|
||||
func) {
|
||||
const int32_t numPWM = m_sources.size();
|
||||
for (int32_t i = 0; i < numPWM; ++i) {
|
||||
if (auto model = m_sources[i].get()) {
|
||||
@@ -98,7 +100,7 @@ void PWMSimGui::Initialize() {
|
||||
win->SetDefaultPos(910, 20);
|
||||
return wpi::glass::MakeFunctionView([=] {
|
||||
wpi::glass::DisplayPWMs(static_cast<PWMsSimModel*>(model),
|
||||
HALSimGui::halProvider->AreOutputsEnabled());
|
||||
HALSimGui::halProvider->AreOutputsEnabled());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ class PowerDistributionsSimModel : public wpi::glass::PowerDistributionsModel {
|
||||
bool Exists() override { return true; }
|
||||
|
||||
void ForEachPowerDistribution(
|
||||
wpi::util::function_ref<void(wpi::glass::PowerDistributionModel& model, int index)>
|
||||
wpi::util::function_ref<void(wpi::glass::PowerDistributionModel& model,
|
||||
int index)>
|
||||
func) override;
|
||||
|
||||
private:
|
||||
@@ -101,7 +102,8 @@ void PowerDistributionsSimModel::Update() {
|
||||
}
|
||||
|
||||
void PowerDistributionsSimModel::ForEachPowerDistribution(
|
||||
wpi::util::function_ref<void(wpi::glass::PowerDistributionModel& model, int index)>
|
||||
wpi::util::function_ref<void(wpi::glass::PowerDistributionModel& model,
|
||||
int index)>
|
||||
func) {
|
||||
for (int32_t i = 0, iend = static_cast<int32_t>(m_models.size()); i < iend;
|
||||
++i) {
|
||||
|
||||
@@ -48,9 +48,13 @@ class RoboRioSimModel : public wpi::glass::RoboRioModel {
|
||||
|
||||
bool Exists() override { return true; }
|
||||
|
||||
wpi::glass::RoboRioRailModel* GetUser3V3Rail() override { return &m_user3V3Rail; }
|
||||
wpi::glass::RoboRioRailModel* GetUser3V3Rail() override {
|
||||
return &m_user3V3Rail;
|
||||
}
|
||||
|
||||
wpi::glass::DoubleSource* GetVInVoltageData() override { return &m_vInVoltage; }
|
||||
wpi::glass::DoubleSource* GetVInVoltageData() override {
|
||||
return &m_vInVoltage;
|
||||
}
|
||||
wpi::glass::DoubleSource* GetBrownoutVoltage() override {
|
||||
return &m_brownoutVoltage;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ using namespace halsimgui;
|
||||
|
||||
namespace {
|
||||
#define DEFINE_SIMVALUESOURCE(Type, TYPE, v_type) \
|
||||
class Sim##Type##ValueSource : public wpi::glass::Type##Source { \
|
||||
class Sim##Type##ValueSource : public wpi::glass::Type##Source { \
|
||||
public: \
|
||||
explicit Sim##Type##ValueSource(HAL_SimValueHandle handle, \
|
||||
const char* device, const char* name) \
|
||||
@@ -90,7 +90,8 @@ class SimDevicesModel : public wpi::glass::Model {
|
||||
}
|
||||
|
||||
private:
|
||||
wpi::util::DenseMap<HAL_SimValueHandle, std::unique_ptr<wpi::glass::DataSource>>
|
||||
wpi::util::DenseMap<HAL_SimValueHandle,
|
||||
std::unique_ptr<wpi::glass::DataSource>>
|
||||
m_sources;
|
||||
};
|
||||
} // namespace
|
||||
@@ -151,7 +152,7 @@ static void DisplaySimValue(const char* name, void* data,
|
||||
case HAL_BOOLEAN: {
|
||||
bool v = value->data.v_boolean;
|
||||
if (wpi::glass::DeviceBoolean(name, direction == HAL_SimValueOutput, &v,
|
||||
model->GetSource(handle))) {
|
||||
model->GetSource(handle))) {
|
||||
valueCopy.data.v_boolean = v ? 1 : 0;
|
||||
HAL_SetSimValue(handle, valueCopy);
|
||||
}
|
||||
@@ -159,8 +160,8 @@ static void DisplaySimValue(const char* name, void* data,
|
||||
}
|
||||
case HAL_DOUBLE:
|
||||
if (wpi::glass::DeviceDouble(name, direction == HAL_SimValueOutput,
|
||||
&valueCopy.data.v_double,
|
||||
model->GetSource(handle))) {
|
||||
&valueCopy.data.v_double,
|
||||
model->GetSource(handle))) {
|
||||
HAL_SetSimValue(handle, valueCopy);
|
||||
}
|
||||
break;
|
||||
@@ -168,21 +169,23 @@ static void DisplaySimValue(const char* name, void* data,
|
||||
int32_t numOptions = 0;
|
||||
const char** options = HALSIM_GetSimValueEnumOptions(handle, &numOptions);
|
||||
if (wpi::glass::DeviceEnum(name, direction == HAL_SimValueOutput,
|
||||
&valueCopy.data.v_enum, options, numOptions,
|
||||
model->GetSource(handle))) {
|
||||
&valueCopy.data.v_enum, options, numOptions,
|
||||
model->GetSource(handle))) {
|
||||
HAL_SetSimValue(handle, valueCopy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HAL_INT:
|
||||
if (wpi::glass::DeviceInt(name, direction == HAL_SimValueOutput,
|
||||
&valueCopy.data.v_int, model->GetSource(handle))) {
|
||||
&valueCopy.data.v_int,
|
||||
model->GetSource(handle))) {
|
||||
HAL_SetSimValue(handle, valueCopy);
|
||||
}
|
||||
break;
|
||||
case HAL_LONG:
|
||||
if (wpi::glass::DeviceLong(name, direction == HAL_SimValueOutput,
|
||||
&valueCopy.data.v_long, model->GetSource(handle))) {
|
||||
&valueCopy.data.v_long,
|
||||
model->GetSource(handle))) {
|
||||
HAL_SetSimValue(handle, valueCopy);
|
||||
}
|
||||
break;
|
||||
@@ -234,7 +237,8 @@ void SimDeviceGui::Initialize() {
|
||||
});
|
||||
}
|
||||
|
||||
wpi::glass::DataSource* SimDeviceGui::GetValueSource(HAL_SimValueHandle handle) {
|
||||
wpi::glass::DataSource* SimDeviceGui::GetValueSource(
|
||||
HAL_SimValueHandle handle) {
|
||||
return gSimDevicesModel->GetSource(handle);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,9 +64,9 @@ int HALSIM_InitExtension(void) {
|
||||
HAL_RegisterExtension(
|
||||
HALSIMGUI_EXT_GETGUICONTEXT,
|
||||
reinterpret_cast<void*>((GetGuiContextFn)&gui::GetCurrentContext));
|
||||
HAL_RegisterExtension(
|
||||
HALSIMGUI_EXT_GETGLASSCONTEXT,
|
||||
reinterpret_cast<void*>((GetGlassContextFn)&wpi::glass::GetCurrentContext));
|
||||
HAL_RegisterExtension(HALSIMGUI_EXT_GETGLASSCONTEXT,
|
||||
reinterpret_cast<void*>(
|
||||
(GetGlassContextFn)&wpi::glass::GetCurrentContext));
|
||||
|
||||
HALSimGui::GlobalInit();
|
||||
DriverStationGui::GlobalInit();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "wpi/glass/DataSource.hpp"
|
||||
|
||||
#define HALSIMGUI_DATASOURCE(cbname, id, TYPE, Type, vtype) \
|
||||
class cbname##Source : public ::wpi::glass::Type##Source { \
|
||||
class cbname##Source : public ::wpi::glass::Type##Source { \
|
||||
public: \
|
||||
cbname##Source() \
|
||||
: Type##Source{id}, \
|
||||
@@ -39,11 +39,11 @@
|
||||
HALSIMGUI_DATASOURCE(cbname, id, INT, Integer, int)
|
||||
|
||||
#define HALSIMGUI_DATASOURCE_INDEXED(cbname, id, TYPE, Type, vtype) \
|
||||
class cbname##Source : public ::wpi::glass::Type##Source { \
|
||||
class cbname##Source : public ::wpi::glass::Type##Source { \
|
||||
public: \
|
||||
explicit cbname##Source(int32_t index, int channel = -1) \
|
||||
: Type##Source{::wpi::glass::MakeSourceId(id, \
|
||||
channel < 0 ? index : channel)}, \
|
||||
: Type##Source{::wpi::glass::MakeSourceId( \
|
||||
id, channel < 0 ? index : channel)}, \
|
||||
m_index{index}, \
|
||||
m_channel{channel < 0 ? index : channel}, \
|
||||
m_callback{HALSIM_Register##cbname##Callback(index, CallbackFunc, \
|
||||
@@ -77,10 +77,10 @@
|
||||
HALSIMGUI_DATASOURCE_INDEXED(cbname, id, DOUBLE, Double, double)
|
||||
|
||||
#define HALSIMGUI_DATASOURCE_INDEXED2(cbname, id, TYPE, Type, vtype) \
|
||||
class cbname##Source : public ::wpi::glass::Type##Source { \
|
||||
class cbname##Source : public ::wpi::glass::Type##Source { \
|
||||
public: \
|
||||
explicit cbname##Source(int32_t index, int32_t channel) \
|
||||
: Type##Source{::wpi::glass::MakeSourceId(id, index, channel)}, \
|
||||
: Type##Source{::wpi::glass::MakeSourceId(id, index, channel)}, \
|
||||
m_index{index}, \
|
||||
m_channel{channel}, \
|
||||
m_callback{HALSIM_Register##cbname##Callback( \
|
||||
|
||||
@@ -10,7 +10,7 @@ struct ImGuiContext;
|
||||
|
||||
namespace wpi::glass {
|
||||
class Context;
|
||||
} // namespace glass
|
||||
} // namespace wpi::glass
|
||||
|
||||
namespace wpi::gui {
|
||||
struct Context;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace wpi::glass {
|
||||
class DataSource;
|
||||
class DeviceTreeModel;
|
||||
} // namespace glass
|
||||
} // namespace wpi::glass
|
||||
|
||||
namespace halsimgui {
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@ bool HALSimWS::Initialize() {
|
||||
try {
|
||||
m_port = std::stoi(port);
|
||||
} catch (const std::invalid_argument& err) {
|
||||
wpi::util::print(stderr, "Error decoding HALSIMWS_PORT ({})\n", err.what());
|
||||
wpi::util::print(stderr, "Error decoding HALSIMWS_PORT ({})\n",
|
||||
err.what());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -71,8 +72,9 @@ bool HALSimWS::Initialize() {
|
||||
const char* msgFilters = std::getenv("HALSIMWS_FILTERS");
|
||||
if (msgFilters != nullptr) {
|
||||
m_useMsgFiltering = true;
|
||||
wpi::util::split(wpi::util::trim(msgFilters), ',', -1, false,
|
||||
[&](auto val) { m_msgFilters[wpi::util::trim(val)] = true; });
|
||||
wpi::util::split(
|
||||
wpi::util::trim(msgFilters), ',', -1, false,
|
||||
[&](auto val) { m_msgFilters[wpi::util::trim(val)] = true; });
|
||||
} else {
|
||||
m_useMsgFiltering = false;
|
||||
}
|
||||
@@ -112,7 +114,7 @@ void HALSimWS::Start() {
|
||||
|
||||
// Set up the connection timer
|
||||
wpi::util::print("Will attempt to connect to ws://{}:{}{}\n", m_host, m_port,
|
||||
m_uri);
|
||||
m_uri);
|
||||
|
||||
// Set up the timer to attempt connection
|
||||
m_connect_timer->timeout.connect([this] { AttemptConnect(); });
|
||||
|
||||
@@ -89,9 +89,9 @@ void HALSimWSClientConnection::OnSimValueChanged(const wpi::util::json& msg) {
|
||||
|
||||
wpi::util::SmallVector<uv::Buffer, 4> sendBufs;
|
||||
wpi::net::raw_uv_ostream os{sendBufs, [this]() -> uv::Buffer {
|
||||
std::lock_guard lock(m_buffers_mutex);
|
||||
return m_buffers.Allocate();
|
||||
}};
|
||||
std::lock_guard lock(m_buffers_mutex);
|
||||
return m_buffers.Allocate();
|
||||
}};
|
||||
|
||||
os << msg;
|
||||
|
||||
|
||||
@@ -23,8 +23,9 @@ class HALSimWSClientConnection
|
||||
: public HALSimBaseWebSocketConnection,
|
||||
public std::enable_shared_from_this<HALSimWSClientConnection> {
|
||||
public:
|
||||
explicit HALSimWSClientConnection(std::shared_ptr<HALSimWS> client,
|
||||
std::shared_ptr<wpi::net::uv::Stream> stream)
|
||||
explicit HALSimWSClientConnection(
|
||||
std::shared_ptr<HALSimWS> client,
|
||||
std::shared_ptr<wpi::net::uv::Stream> stream)
|
||||
: m_client(std::move(client)),
|
||||
m_stream(std::move(stream)),
|
||||
m_buffers(128) {}
|
||||
|
||||
@@ -122,7 +122,8 @@ void HALSimWSProviderDriverStation::DoCancelCallbacks() {
|
||||
m_matchTimeCbKey = 0;
|
||||
}
|
||||
|
||||
void HALSimWSProviderDriverStation::OnNetValueChanged(const wpi::util::json& json) {
|
||||
void HALSimWSProviderDriverStation::OnNetValueChanged(
|
||||
const wpi::util::json& json) {
|
||||
// ignore if DS connected
|
||||
if (gDSSocketConnected && *gDSSocketConnected) {
|
||||
return;
|
||||
|
||||
@@ -115,8 +115,8 @@ void HALSimWSProviderJoystick::OnNetValueChanged(const wpi::util::json& json) {
|
||||
|
||||
if ((it = json.find(">buttons")) != json.end()) {
|
||||
HAL_JoystickButtons buttons{};
|
||||
wpi::util::json::size_type buttonsCount =
|
||||
std::min(it.value().size(), static_cast<wpi::util::json::size_type>(64));
|
||||
wpi::util::json::size_type buttonsCount = std::min(
|
||||
it.value().size(), static_cast<wpi::util::json::size_type>(64));
|
||||
if (buttonsCount < 64) {
|
||||
buttons.available = (1ULL << buttonsCount) - 1;
|
||||
} else {
|
||||
|
||||
@@ -250,7 +250,8 @@ void HALSimWSProviderSimDevice::OnValueReset(SimDeviceValueData* valueData,
|
||||
}
|
||||
}
|
||||
|
||||
void HALSimWSProviderSimDevice::ProcessHalCallback(const wpi::util::json& payload) {
|
||||
void HALSimWSProviderSimDevice::ProcessHalCallback(
|
||||
const wpi::util::json& payload) {
|
||||
auto ws = m_ws.lock();
|
||||
if (ws) {
|
||||
wpi::util::json netValue = {
|
||||
|
||||
@@ -91,9 +91,9 @@ void HALSimHttpConnection::OnSimValueChanged(const wpi::util::json& msg) {
|
||||
// render json to buffers
|
||||
wpi::util::SmallVector<uv::Buffer, 4> sendBufs;
|
||||
wpi::net::raw_uv_ostream os{sendBufs, [this]() -> uv::Buffer {
|
||||
std::lock_guard lock(m_buffers_mutex);
|
||||
return m_buffers.Allocate();
|
||||
}};
|
||||
std::lock_guard lock(m_buffers_mutex);
|
||||
return m_buffers.Allocate();
|
||||
}};
|
||||
os << msg;
|
||||
|
||||
// call the websocket send function on the uv loop
|
||||
@@ -154,7 +154,7 @@ void HALSimHttpConnection::SendFileResponse(int code, std::string_view codeText,
|
||||
|
||||
void HALSimHttpConnection::ProcessRequest() {
|
||||
wpi::net::UrlParser url{m_request.GetUrl(),
|
||||
m_request.GetMethod() == wpi::net::HTTP_CONNECT};
|
||||
m_request.GetMethod() == wpi::net::HTTP_CONNECT};
|
||||
if (!url.IsValid()) {
|
||||
// failed to parse URL
|
||||
MySendError(400, "Invalid URL");
|
||||
@@ -166,17 +166,18 @@ void HALSimHttpConnection::ProcessRequest() {
|
||||
path = url.GetPath();
|
||||
}
|
||||
|
||||
if (m_request.GetMethod() == wpi::net::HTTP_GET && wpi::util::starts_with(path, '/') &&
|
||||
!wpi::util::contains(path, "..") && !wpi::util::contains(path, "//")) {
|
||||
if (m_request.GetMethod() == wpi::net::HTTP_GET &&
|
||||
wpi::util::starts_with(path, '/') && !wpi::util::contains(path, "..") &&
|
||||
!wpi::util::contains(path, "//")) {
|
||||
// convert to fs native representation
|
||||
fs::path nativePath;
|
||||
if (auto userPath = wpi::util::remove_prefix(path, "/user/")) {
|
||||
nativePath = fs::path{m_server->GetWebrootSys()} /
|
||||
fs::path{*userPath, fs::path::format::generic_format};
|
||||
} else {
|
||||
nativePath =
|
||||
fs::path{m_server->GetWebrootSys()} /
|
||||
fs::path{wpi::util::drop_front(path), fs::path::format::generic_format};
|
||||
nativePath = fs::path{m_server->GetWebrootSys()} /
|
||||
fs::path{wpi::util::drop_front(path),
|
||||
fs::path::format::generic_format};
|
||||
}
|
||||
|
||||
if (fs::is_directory(nativePath)) {
|
||||
@@ -202,5 +203,5 @@ void HALSimHttpConnection::MySendError(int code, std::string_view message) {
|
||||
void HALSimHttpConnection::Log(int code) {
|
||||
auto method = wpi::net::http_method_str(m_request.GetMethod());
|
||||
wpi::util::print(stderr, "{} {} HTTP/{}.{} {}\n", method, m_request.GetUrl(),
|
||||
m_request.GetMajor(), m_request.GetMinor(), code);
|
||||
m_request.GetMajor(), m_request.GetMinor(), code);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,8 @@ bool HALSimWeb::Initialize() {
|
||||
try {
|
||||
m_port = std::stoi(port);
|
||||
} catch (const std::invalid_argument& err) {
|
||||
wpi::util::print(stderr, "Error decoding HALSIMWS_PORT ({})\n", err.what());
|
||||
wpi::util::print(stderr, "Error decoding HALSIMWS_PORT ({})\n",
|
||||
err.what());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -82,8 +83,9 @@ bool HALSimWeb::Initialize() {
|
||||
const char* msgFilters = std::getenv("HALSIMWS_FILTERS");
|
||||
if (msgFilters != nullptr) {
|
||||
m_useMsgFiltering = true;
|
||||
wpi::util::split(wpi::util::trim(msgFilters), ',', -1, false,
|
||||
[&](auto val) { m_msgFilters[wpi::util::trim(val)] = true; });
|
||||
wpi::util::split(
|
||||
wpi::util::trim(msgFilters), ',', -1, false,
|
||||
[&](auto val) { m_msgFilters[wpi::util::trim(val)] = true; });
|
||||
} else {
|
||||
m_useMsgFiltering = false;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ class HALSimHttpConnection
|
||||
public:
|
||||
HALSimHttpConnection(std::shared_ptr<HALSimWeb> server,
|
||||
std::shared_ptr<wpi::net::uv::Stream> stream)
|
||||
: wpi::net::HttpWebSocketServerConnection<HALSimHttpConnection>(stream, {}),
|
||||
: wpi::net::HttpWebSocketServerConnection<HALSimHttpConnection>(stream,
|
||||
{}),
|
||||
m_server(std::move(server)),
|
||||
m_buffers(128) {}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace wpilibws {
|
||||
void WebServerClientTest::InitializeWebSocket(const std::string& host, int port,
|
||||
const std::string& uri) {
|
||||
wpi::util::print("Will attempt to connect to: {}:{}{}\n", host, port, uri);
|
||||
m_websocket = wpi::net::WebSocket::CreateClient(*m_tcp_client.get(), uri,
|
||||
fmt::format("{}:{}", host, port));
|
||||
m_websocket = wpi::net::WebSocket::CreateClient(
|
||||
*m_tcp_client.get(), uri, fmt::format("{}:{}", host, port));
|
||||
|
||||
// Hook up events
|
||||
m_websocket->open.connect_extended([this](auto conn, auto) {
|
||||
@@ -68,8 +68,9 @@ void WebServerClientTest::InitializeWebSocket(const std::string& host, int port,
|
||||
|
||||
// Create tcp client, specify callbacks, and create timers for loop
|
||||
bool WebServerClientTest::Initialize() {
|
||||
m_loop.error.connect(
|
||||
[](uv::Error err) { wpi::util::print(stderr, "uv Error: {}\n", err.str()); });
|
||||
m_loop.error.connect([](uv::Error err) {
|
||||
wpi::util::print(stderr, "uv Error: {}\n", err.str());
|
||||
});
|
||||
|
||||
m_tcp_client = uv::Tcp::Create(m_loop);
|
||||
if (!m_tcp_client) {
|
||||
@@ -135,9 +136,9 @@ void WebServerClientTest::SendMessage(const wpi::util::json& msg) {
|
||||
wpi::util::SmallVector<uv::Buffer, 4> sendBufs;
|
||||
|
||||
wpi::net::raw_uv_ostream os{sendBufs, [this]() -> uv::Buffer {
|
||||
std::lock_guard lock(m_buffers_mutex);
|
||||
return m_buffers->Allocate();
|
||||
}};
|
||||
std::lock_guard lock(m_buffers_mutex);
|
||||
return m_buffers->Allocate();
|
||||
}};
|
||||
os << msg;
|
||||
|
||||
// Call the websocket send function on the uv loop
|
||||
|
||||
@@ -58,7 +58,7 @@ TEST_F(WebServerIntegrationTest, DISABLED_DigitalOutput) {
|
||||
}
|
||||
if (IsConnectedClientWS()) {
|
||||
wpi::util::print("***** Setting DIO value for pin {} to {}\n", PIN,
|
||||
(EXPECTED_VALUE ? "true" : "false"));
|
||||
(EXPECTED_VALUE ? "true" : "false"));
|
||||
HALSIM_SetDIOValue(PIN, EXPECTED_VALUE);
|
||||
done = true;
|
||||
}
|
||||
@@ -109,8 +109,8 @@ TEST_F(WebServerIntegrationTest, DISABLED_DigitalInput) {
|
||||
}
|
||||
if (IsConnectedClientWS()) {
|
||||
wpi::util::json msg = {{"type", "DIO"},
|
||||
{"device", std::to_string(PIN)},
|
||||
{"data", {{"<>value", EXPECTED_VALUE}}}};
|
||||
{"device", std::to_string(PIN)},
|
||||
{"data", {{"<>value", EXPECTED_VALUE}}}};
|
||||
wpi::util::print("***** Input JSON: {}\n", msg.dump());
|
||||
m_webserverClient->SendMessage(msg);
|
||||
done = true;
|
||||
|
||||
@@ -52,7 +52,8 @@ bool HALSimXRP::Initialize() {
|
||||
try {
|
||||
m_port = std::stoi(port);
|
||||
} catch (const std::invalid_argument& err) {
|
||||
wpi::util::print(stderr, "Error decoding HALSIMXRP_PORT ({})\n", err.what());
|
||||
wpi::util::print(stderr, "Error decoding HALSIMXRP_PORT ({})\n",
|
||||
err.what());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -145,9 +146,9 @@ uv::SimpleBufferPool<4>& HALSimXRP::GetBufferPool() {
|
||||
void HALSimXRP::SendStateToXRP() {
|
||||
wpi::util::SmallVector<uv::Buffer, 4> sendBufs;
|
||||
wpi::net::raw_uv_ostream stream{sendBufs, [&] {
|
||||
std::lock_guard lock(m_buffer_mutex);
|
||||
return GetBufferPool().Allocate();
|
||||
}};
|
||||
std::lock_guard lock(m_buffer_mutex);
|
||||
return GetBufferPool().Allocate();
|
||||
}};
|
||||
m_xrp.SetupXRPSendBuffer(stream);
|
||||
|
||||
m_exec->Send([this, sendBufs]() mutable {
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
using namespace wpilibxrp;
|
||||
|
||||
XRP::XRP()
|
||||
: m_gyro_name{"XRPGyro"}, m_wpilib_update_func([](const wpi::util::json&) {}) {
|
||||
: m_gyro_name{"XRPGyro"},
|
||||
m_wpilib_update_func([](const wpi::util::json&) {}) {
|
||||
// Set up the inputs and outputs
|
||||
m_motor_outputs.emplace(0, 0.0f);
|
||||
m_motor_outputs.emplace(1, 0.0f);
|
||||
@@ -246,8 +247,8 @@ void XRP::SetupMotorTag(wpi::net::raw_uv_ostream& buf) {
|
||||
<< static_cast<uint8_t>(motor.first); // Channel
|
||||
|
||||
// Convert the value
|
||||
wpi::util::support::endian::write32be(value,
|
||||
std::bit_cast<uint32_t>(motor.second));
|
||||
wpi::util::support::endian::write32be(
|
||||
value, std::bit_cast<uint32_t>(motor.second));
|
||||
buf << value[0] << value[1] << value[2] << value[3];
|
||||
}
|
||||
}
|
||||
@@ -262,8 +263,8 @@ void XRP::SetupServoTag(wpi::net::raw_uv_ostream& buf) {
|
||||
<< static_cast<uint8_t>(servo.first); // Channel
|
||||
|
||||
// Convert the value
|
||||
wpi::util::support::endian::write32be(value,
|
||||
std::bit_cast<uint32_t>(servo.second));
|
||||
wpi::util::support::endian::write32be(
|
||||
value, std::bit_cast<uint32_t>(servo.second));
|
||||
buf << value[0] << value[1] << value[2] << value[3];
|
||||
}
|
||||
}
|
||||
@@ -374,7 +375,8 @@ void XRP::ReadEncoderTag(std::span<const uint8_t> packet) {
|
||||
period = -period;
|
||||
}
|
||||
|
||||
encJson["data"].push_back({wpi::util::json(">period"), wpi::util::json(period)});
|
||||
encJson["data"].push_back(
|
||||
{wpi::util::json(">period"), wpi::util::json(period)});
|
||||
}
|
||||
|
||||
m_wpilib_update_func(encJson);
|
||||
|
||||
Reference in New Issue
Block a user