// 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 "PCMSimGui.hpp" #include #include #include #include "wpi/glass/hardware/Pneumatic.hpp" #include "wpi/glass/other/DeviceTree.hpp" #include "wpi/hal/Ports.h" #include "wpi/hal/Value.h" #include "wpi/hal/simulation/CTREPCMData.h" #include "wpi/halsim/gui/HALDataSource.hpp" #include "wpi/halsim/gui/HALSimGui.hpp" #include "wpi/halsim/gui/SimDeviceGui.hpp" using namespace halsimgui; namespace { HALSIMGUI_DATASOURCE_BOOLEAN_INDEXED(CTREPCMCompressorOn, "Compressor On"); HALSIMGUI_DATASOURCE_BOOLEAN_INDEXED(CTREPCMClosedLoopEnabled, "Closed Loop"); HALSIMGUI_DATASOURCE_BOOLEAN_INDEXED(CTREPCMPressureSwitch, "Pressure Switch"); HALSIMGUI_DATASOURCE_DOUBLE_INDEXED(CTREPCMCompressorCurrent, "Compressor Current"); HALSIMGUI_DATASOURCE_BOOLEAN_INDEXED2(CTREPCMSolenoidOutput, "Solenoid"); class CompressorSimModel : public wpi::glass::CompressorModel { public: explicit CompressorSimModel(int32_t index) : m_index{index}, m_running{index}, m_enabled{index}, m_pressureSwitch{index}, m_current{index} {} void Update() override {} bool Exists() override { return HALSIM_GetCTREPCMInitialized(m_index); } wpi::glass::BooleanSource* GetRunningData() override { return &m_running; } wpi::glass::BooleanSource* GetEnabledData() override { return &m_enabled; } wpi::glass::BooleanSource* GetPressureSwitchData() override { return &m_pressureSwitch; } wpi::glass::DoubleSource* GetCurrentData() override { return &m_current; } void SetRunning(bool val) override { HALSIM_SetCTREPCMCompressorOn(m_index, val); } void SetEnabled(bool val) override { HALSIM_SetCTREPCMClosedLoopEnabled(m_index, val); } void SetPressureSwitch(bool val) override { HALSIM_SetCTREPCMPressureSwitch(m_index, val); } void SetCurrent(double val) override { HALSIM_SetCTREPCMCompressorCurrent(m_index, val); } private: int32_t m_index; CTREPCMCompressorOnSource m_running; CTREPCMClosedLoopEnabledSource m_enabled; CTREPCMPressureSwitchSource m_pressureSwitch; CTREPCMCompressorCurrentSource m_current; }; class SolenoidSimModel : public wpi::glass::SolenoidModel { public: SolenoidSimModel(int32_t index, int32_t channel) : m_index{index}, m_channel{channel}, m_output{index, channel} {} void Update() override {} bool Exists() override { return HALSIM_GetCTREPCMInitialized(m_index); } wpi::glass::BooleanSource* GetOutputData() override { return &m_output; } void SetOutput(bool val) override { HALSIM_SetCTREPCMSolenoidOutput(m_index, m_channel, val); } private: int32_t m_index; int32_t m_channel; CTREPCMSolenoidOutputSource m_output; }; class PCMSimModel : public wpi::glass::PneumaticControlModel { public: explicit PCMSimModel(int32_t index) : m_index{index}, m_compressor{index}, m_solenoids(HAL_GetNumCTRESolenoidChannels()) {} void Update() override; bool Exists() override { return true; } CompressorSimModel* GetCompressor() override { return &m_compressor; } void ForEachSolenoid( wpi::util::function_ref func) override; std::string_view GetName() override { return "PCM"; } int GetNumSolenoids() const { return m_solenoidInitCount; } private: int32_t m_index; CompressorSimModel m_compressor; std::vector> m_solenoids; int m_solenoidInitCount = 0; }; class PCMsSimModel : public wpi::glass::PneumaticControlsModel { public: PCMsSimModel() : m_models(HAL_GetNumCTREPCMModules()) {} void Update() override; bool Exists() override { return true; } void ForEachPneumaticControl( wpi::util::function_ref func) override; private: std::vector> m_models; }; } // namespace void PCMSimModel::Update() { int32_t numChannels = m_solenoids.size(); m_solenoidInitCount = 0; for (int32_t i = 0; i < numChannels; ++i) { auto& model = m_solenoids[i]; if (HALSIM_GetCTREPCMInitialized(m_index)) { if (!model) { model = std::make_unique(m_index, i); } ++m_solenoidInitCount; } else { model.reset(); } } } void PCMSimModel::ForEachSolenoid( wpi::util::function_ref func) { if (m_solenoidInitCount == 0) { return; } int32_t numSolenoids = m_solenoids.size(); for (int32_t i = 0; i < numSolenoids; ++i) { if (auto model = m_solenoids[i].get()) { func(*model, i); } } } void PCMsSimModel::Update() { for (int32_t i = 0, iend = static_cast(m_models.size()); i < iend; ++i) { auto& model = m_models[i]; if (HALSIM_GetCTREPCMInitialized(i)) { if (!model) { model = std::make_unique(i); } model->Update(); } else { model.reset(); } } } void PCMsSimModel::ForEachPneumaticControl( wpi::util::function_ref func) { int32_t numCTREPCMs = m_models.size(); for (int32_t i = 0; i < numCTREPCMs; ++i) { if (auto model = m_models[i].get()) { func(*model, i); } } } bool PCMSimGui::PCMsAnyInitialized() { static const int32_t num = HAL_GetNumCTREPCMModules(); for (int32_t i = 0; i < num; ++i) { if (HALSIM_GetCTREPCMInitialized(i)) { return true; } } return false; } bool PCMSimGui::PCMsAnySolenoids(wpi::glass::PneumaticControlsModel* model) { bool any = false; static_cast(model)->ForEachPneumaticControl( [&](wpi::glass::PneumaticControlModel& CTREPCM, int) { if (static_cast(&CTREPCM)->GetNumSolenoids() > 0) { any = true; } }); return any; } std::unique_ptr PCMSimGui::GetPCMsModel() { return std::make_unique(); } void PCMSimGui::Initialize() { HALSimGui::halProvider->RegisterModel( "CTREPCMs", PCMSimGui::PCMsAnyInitialized, [] { return std::make_unique(); }); SimDeviceGui::GetDeviceTree().Add( HALSimGui::halProvider->GetModel("CTREPCMs"), [](wpi::glass::Model* model) { wpi::glass::DisplayCompressorsDevice( static_cast(model), HALSimGui::halProvider->AreOutputsEnabled()); }); }