mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
246 lines
7.2 KiB
C++
246 lines
7.2 KiB
C++
// 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 "DIOSimGui.hpp"
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "EncoderSimGui.hpp"
|
|
#include "wpi/glass/hardware/DIO.hpp"
|
|
#include "wpi/glass/hardware/Encoder.hpp"
|
|
#include "wpi/hal/Ports.h"
|
|
#include "wpi/hal/simulation/DIOData.h"
|
|
#include "wpi/hal/simulation/DigitalPWMData.h"
|
|
#include "wpi/hal/simulation/DutyCycleData.h"
|
|
#include "wpi/hal/simulation/EncoderData.h"
|
|
#include "wpi/hal/simulation/SimDeviceData.h"
|
|
#include "wpi/halsim/gui/HALDataSource.hpp"
|
|
#include "wpi/halsim/gui/HALSimGui.hpp"
|
|
|
|
using namespace halsimgui;
|
|
|
|
namespace {
|
|
HALSIMGUI_DATASOURCE_BOOLEAN_INDEXED(DIOValue, "DIO");
|
|
HALSIMGUI_DATASOURCE_DOUBLE_INDEXED(DigitalPWMDutyCycle, "DPWM");
|
|
HALSIMGUI_DATASOURCE_DOUBLE_INDEXED(DutyCycleOutput, "DutyCycle");
|
|
|
|
class DPWMSimModel : public wpi::glass::DPWMModel {
|
|
public:
|
|
DPWMSimModel(int32_t index, int32_t dioChannel)
|
|
: m_dioChannel{dioChannel}, m_index{index}, m_valueData{index} {}
|
|
|
|
void Update() override {}
|
|
|
|
bool Exists() override { return HALSIM_GetDigitalPWMInitialized(m_index); }
|
|
|
|
const char* GetSimDevice() const override {
|
|
if (auto simDevice = HALSIM_GetDIOSimDevice(m_dioChannel)) {
|
|
return HALSIM_GetSimDeviceName(simDevice);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
wpi::glass::DoubleSource* GetValueData() override { return &m_valueData; }
|
|
|
|
void SetValue(double val) override {
|
|
HALSIM_SetDigitalPWMDutyCycle(m_index, val);
|
|
}
|
|
|
|
private:
|
|
int32_t m_dioChannel;
|
|
int32_t m_index;
|
|
DigitalPWMDutyCycleSource m_valueData;
|
|
};
|
|
|
|
class DutyCycleSimModel : public wpi::glass::DutyCycleModel {
|
|
public:
|
|
explicit DutyCycleSimModel(int32_t index)
|
|
: m_index{index}, m_valueData{index} {}
|
|
|
|
void Update() override {}
|
|
|
|
bool Exists() override { return HALSIM_GetDutyCycleInitialized(m_index); }
|
|
|
|
const char* GetSimDevice() const override {
|
|
if (auto simDevice = HALSIM_GetDutyCycleSimDevice(m_index)) {
|
|
return HALSIM_GetSimDeviceName(simDevice);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
wpi::glass::DoubleSource* GetValueData() override { return &m_valueData; }
|
|
|
|
void SetValue(double val) override {
|
|
HALSIM_SetDutyCycleOutput(m_index, val);
|
|
}
|
|
|
|
private:
|
|
int32_t m_index;
|
|
DutyCycleOutputSource m_valueData;
|
|
};
|
|
|
|
class DIOSimModel : public wpi::glass::DIOModel {
|
|
public:
|
|
explicit DIOSimModel(int32_t channel)
|
|
: m_channel{channel}, m_valueData{channel} {}
|
|
|
|
void Update() override {}
|
|
|
|
bool Exists() override { return HALSIM_GetDIOInitialized(m_channel); }
|
|
|
|
bool IsReadOnly() override { return !IsInput(); }
|
|
|
|
const char* GetName() const override { return ""; }
|
|
|
|
const char* GetSimDevice() const override {
|
|
if (auto simDevice = HALSIM_GetDIOSimDevice(m_channel)) {
|
|
return HALSIM_GetSimDeviceName(simDevice);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
DPWMSimModel* GetDPWM() override { return m_dpwmSource; }
|
|
DutyCycleSimModel* GetDutyCycle() override { return m_dutyCycleSource; }
|
|
wpi::glass::EncoderModel* GetEncoder() override { return m_encoderSource; }
|
|
|
|
void SetDPWM(DPWMSimModel* model) { m_dpwmSource = model; }
|
|
void SetDutyCycle(DutyCycleSimModel* model) { m_dutyCycleSource = model; }
|
|
void SetEncoder(wpi::glass::EncoderModel* model) { m_encoderSource = model; }
|
|
|
|
bool IsInput() const override { return HALSIM_GetDIOIsInput(m_channel); }
|
|
|
|
wpi::glass::BooleanSource* GetValueData() override { return &m_valueData; }
|
|
|
|
void SetValue(bool val) override { HALSIM_SetDIOValue(m_channel, val); }
|
|
|
|
private:
|
|
int32_t m_channel;
|
|
DIOValueSource m_valueData;
|
|
DPWMSimModel* m_dpwmSource = nullptr;
|
|
DutyCycleSimModel* m_dutyCycleSource = nullptr;
|
|
wpi::glass::EncoderModel* m_encoderSource = nullptr;
|
|
};
|
|
|
|
class DIOsSimModel : public wpi::glass::DIOsModel {
|
|
public:
|
|
DIOsSimModel()
|
|
: m_dioModels(HAL_GetNumDigitalChannels()),
|
|
m_dpwmModels(HAL_GetNumDigitalPWMOutputs()),
|
|
m_dutyCycleModels(HAL_GetNumDutyCycles()) {}
|
|
|
|
void Update() override;
|
|
|
|
bool Exists() override { return true; }
|
|
|
|
void ForEachDIO(
|
|
wpi::util::function_ref<void(wpi::glass::DIOModel& model, int index)>
|
|
func) override;
|
|
|
|
private:
|
|
// indexed by channel
|
|
std::vector<std::unique_ptr<DIOSimModel>> m_dioModels;
|
|
// indexed by index
|
|
std::vector<std::unique_ptr<DPWMSimModel>> m_dpwmModels;
|
|
std::vector<std::unique_ptr<DutyCycleSimModel>> m_dutyCycleModels;
|
|
};
|
|
} // namespace
|
|
|
|
void DIOsSimModel::Update() {
|
|
const int32_t numDIO = m_dioModels.size();
|
|
for (int i = 0; i < numDIO; ++i) {
|
|
auto& model = m_dioModels[i];
|
|
if (HALSIM_GetDIOInitialized(i)) {
|
|
if (!model) {
|
|
model = std::make_unique<DIOSimModel>(i);
|
|
}
|
|
model->SetDPWM(nullptr);
|
|
model->SetDutyCycle(nullptr);
|
|
model->SetEncoder(nullptr);
|
|
} else {
|
|
model.reset();
|
|
}
|
|
}
|
|
|
|
const int32_t numPWM = m_dpwmModels.size();
|
|
for (int32_t i = 0; i < numPWM; ++i) {
|
|
auto& model = m_dpwmModels[i];
|
|
if (HALSIM_GetDigitalPWMInitialized(i)) {
|
|
if (!model) {
|
|
int channel = HALSIM_GetDigitalPWMPin(i);
|
|
if (channel >= 0 && channel < numDIO && m_dioModels[channel]) {
|
|
model = std::make_unique<DPWMSimModel>(i, channel);
|
|
m_dioModels[channel]->SetDPWM(model.get());
|
|
}
|
|
}
|
|
} else {
|
|
model.reset();
|
|
}
|
|
}
|
|
|
|
const int32_t numDutyCycle = m_dutyCycleModels.size();
|
|
for (int32_t i = 0; i < numDutyCycle; ++i) {
|
|
auto& model = m_dutyCycleModels[i];
|
|
if (HALSIM_GetDutyCycleInitialized(i)) {
|
|
if (!model) {
|
|
int channel = i;
|
|
if (channel >= 0 && channel < numDIO && m_dioModels[channel]) {
|
|
model = std::make_unique<DutyCycleSimModel>(i);
|
|
m_dioModels[channel]->SetDutyCycle(model.get());
|
|
}
|
|
}
|
|
} else {
|
|
model.reset();
|
|
}
|
|
}
|
|
|
|
EncoderSimGui::GetEncodersModel().ForEachEncoder([&](auto& encoder, int i) {
|
|
int channel = encoder.GetChannelA();
|
|
if (channel >= 0 && channel < numDIO && m_dioModels[channel]) {
|
|
m_dioModels[channel]->SetEncoder(&encoder);
|
|
}
|
|
channel = encoder.GetChannelB();
|
|
if (channel >= 0 && channel < numDIO && m_dioModels[channel]) {
|
|
m_dioModels[channel]->SetEncoder(&encoder);
|
|
}
|
|
});
|
|
}
|
|
|
|
void DIOsSimModel::ForEachDIO(
|
|
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()) {
|
|
func(*model, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool DIOAnyInitialized() {
|
|
static const int32_t num = HAL_GetNumDigitalChannels();
|
|
for (int32_t i = 0; i < num; ++i) {
|
|
if (HALSIM_GetDIOInitialized(i)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void DIOSimGui::Initialize() {
|
|
HALSimGui::halProvider->Register(
|
|
"DIO", DIOAnyInitialized, [] { return std::make_unique<DIOsSimModel>(); },
|
|
[](wpi::glass::Window* win, wpi::glass::Model* model) {
|
|
win->SetFlags(ImGuiWindowFlags_AlwaysAutoResize);
|
|
win->SetDefaultPos(470, 20);
|
|
return wpi::glass::MakeFunctionView([=] {
|
|
wpi::glass::DisplayDIOs(static_cast<DIOsSimModel*>(model),
|
|
HALSimGui::halProvider->AreOutputsEnabled());
|
|
});
|
|
});
|
|
}
|