2020-12-26 14:12:05 -08:00
|
|
|
// 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.
|
2019-09-23 00:24:10 -07:00
|
|
|
|
|
|
|
|
#include "SimDeviceGui.h"
|
|
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
#include <glass/other/DeviceTree.h>
|
2019-09-23 00:24:10 -07:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
|
|
#include <hal/SimDevice.h>
|
2020-06-27 22:11:24 -07:00
|
|
|
#include <hal/simulation/SimDeviceData.h>
|
2020-08-14 20:02:35 -07:00
|
|
|
#include <wpi/DenseMap.h>
|
2019-09-23 00:24:10 -07:00
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
#include "HALDataSource.h"
|
2019-09-23 00:24:10 -07:00
|
|
|
#include "HALSimGui.h"
|
|
|
|
|
|
|
|
|
|
using namespace halsimgui;
|
|
|
|
|
|
|
|
|
|
namespace {
|
2020-09-12 10:55:46 -07:00
|
|
|
class SimValueSource : public glass::DataSource {
|
2020-08-14 20:02:35 -07:00
|
|
|
public:
|
|
|
|
|
explicit SimValueSource(HAL_SimValueHandle handle, const char* device,
|
|
|
|
|
const char* name)
|
2020-09-12 10:55:46 -07:00
|
|
|
: DataSource(wpi::Twine{device} + wpi::Twine{'-'} + name),
|
2020-08-14 20:02:35 -07:00
|
|
|
m_callback{HALSIM_RegisterSimValueChangedCallback(
|
|
|
|
|
handle, this, CallbackFunc, true)} {}
|
2020-12-28 00:10:13 -08:00
|
|
|
~SimValueSource() override {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (m_callback != 0) {
|
|
|
|
|
HALSIM_CancelSimValueChangedCallback(m_callback);
|
|
|
|
|
}
|
2020-08-14 20:02:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
static void CallbackFunc(const char*, void* param, HAL_SimValueHandle,
|
2020-12-23 15:54:11 -08:00
|
|
|
int32_t, const HAL_Value* value) {
|
2020-08-14 20:02:35 -07:00
|
|
|
auto source = static_cast<SimValueSource*>(param);
|
|
|
|
|
if (value->type == HAL_BOOLEAN) {
|
|
|
|
|
source->SetValue(value->data.v_boolean);
|
|
|
|
|
source->SetDigital(true);
|
|
|
|
|
} else if (value->type == HAL_DOUBLE) {
|
|
|
|
|
source->SetValue(value->data.v_double);
|
|
|
|
|
source->SetDigital(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t m_callback;
|
|
|
|
|
};
|
|
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
class SimDevicesModel : public glass::Model {
|
|
|
|
|
public:
|
|
|
|
|
void Update() override;
|
|
|
|
|
bool Exists() override { return true; }
|
|
|
|
|
|
|
|
|
|
glass::DataSource* GetSource(HAL_SimValueHandle handle) {
|
|
|
|
|
return m_sources[handle].get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
wpi::DenseMap<HAL_SimValueHandle, std::unique_ptr<SimValueSource>> m_sources;
|
|
|
|
|
};
|
2019-09-23 00:24:10 -07:00
|
|
|
} // namespace
|
|
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
static SimDevicesModel* gSimDevicesModel;
|
2021-02-21 16:35:49 -08:00
|
|
|
static bool gSimDevicesShowPrefix = false;
|
2020-08-14 20:02:35 -07:00
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
void SimDevicesModel::Update() {
|
2020-08-14 20:02:35 -07:00
|
|
|
HALSIM_EnumerateSimDevices(
|
2020-09-12 10:55:46 -07:00
|
|
|
"", this, [](const char* name, void* self, HAL_SimDeviceHandle handle) {
|
|
|
|
|
struct Data {
|
|
|
|
|
SimDevicesModel* self;
|
|
|
|
|
const char* device;
|
|
|
|
|
} data = {static_cast<SimDevicesModel*>(self), name};
|
2020-08-14 20:02:35 -07:00
|
|
|
HALSIM_EnumerateSimValues(
|
2020-09-12 10:55:46 -07:00
|
|
|
handle, &data,
|
|
|
|
|
[](const char* name, void* dataV, HAL_SimValueHandle handle,
|
2020-12-23 15:54:11 -08:00
|
|
|
int32_t direction, const HAL_Value* value) {
|
2020-09-12 10:55:46 -07:00
|
|
|
auto data = static_cast<Data*>(dataV);
|
|
|
|
|
auto& source = data->self->m_sources[handle];
|
2020-08-14 20:02:35 -07:00
|
|
|
if (!source) {
|
2020-09-12 10:55:46 -07:00
|
|
|
source = std::make_unique<SimValueSource>(handle, data->device,
|
|
|
|
|
name);
|
2020-08-14 20:02:35 -07:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
2019-09-23 00:24:10 -07:00
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
static void DisplaySimValue(const char* name, void* data,
|
2020-12-23 15:54:11 -08:00
|
|
|
HAL_SimValueHandle handle, int32_t direction,
|
2020-09-12 10:55:46 -07:00
|
|
|
const HAL_Value* value) {
|
|
|
|
|
auto model = static_cast<SimDevicesModel*>(data);
|
2019-09-23 00:24:10 -07:00
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
HAL_Value valueCopy = *value;
|
2019-09-23 00:24:10 -07:00
|
|
|
|
|
|
|
|
switch (value->type) {
|
|
|
|
|
case HAL_BOOLEAN: {
|
2020-09-12 10:55:46 -07:00
|
|
|
bool v = value->data.v_boolean;
|
2020-12-23 15:54:11 -08:00
|
|
|
if (glass::DeviceBoolean(name, direction == HAL_SimValueOutput, &v,
|
|
|
|
|
model->GetSource(handle))) {
|
2020-09-12 10:55:46 -07:00
|
|
|
valueCopy.data.v_boolean = v ? 1 : 0;
|
|
|
|
|
HAL_SetSimValue(handle, valueCopy);
|
2019-09-23 00:24:10 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-09-12 10:55:46 -07:00
|
|
|
case HAL_DOUBLE:
|
2020-12-23 15:54:11 -08:00
|
|
|
if (glass::DeviceDouble(name, direction == HAL_SimValueOutput,
|
|
|
|
|
&valueCopy.data.v_double,
|
2020-09-12 10:55:46 -07:00
|
|
|
model->GetSource(handle))) {
|
|
|
|
|
HAL_SetSimValue(handle, valueCopy);
|
|
|
|
|
}
|
2019-09-23 00:24:10 -07:00
|
|
|
break;
|
|
|
|
|
case HAL_ENUM: {
|
2020-09-12 10:55:46 -07:00
|
|
|
int32_t numOptions = 0;
|
|
|
|
|
const char** options = HALSIM_GetSimValueEnumOptions(handle, &numOptions);
|
2020-12-23 15:54:11 -08:00
|
|
|
if (glass::DeviceEnum(name, direction == HAL_SimValueOutput,
|
|
|
|
|
&valueCopy.data.v_enum, options, numOptions,
|
|
|
|
|
model->GetSource(handle))) {
|
2020-09-12 10:55:46 -07:00
|
|
|
HAL_SetSimValue(handle, valueCopy);
|
2019-09-23 00:24:10 -07:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-09-12 10:55:46 -07:00
|
|
|
case HAL_INT:
|
2020-12-23 15:54:11 -08:00
|
|
|
if (glass::DeviceInt(name, direction == HAL_SimValueOutput,
|
|
|
|
|
&valueCopy.data.v_int, model->GetSource(handle))) {
|
2020-09-12 10:55:46 -07:00
|
|
|
HAL_SetSimValue(handle, valueCopy);
|
|
|
|
|
}
|
2019-09-23 00:24:10 -07:00
|
|
|
break;
|
2020-09-12 10:55:46 -07:00
|
|
|
case HAL_LONG:
|
2020-12-23 15:54:11 -08:00
|
|
|
if (glass::DeviceLong(name, direction == HAL_SimValueOutput,
|
|
|
|
|
&valueCopy.data.v_long, model->GetSource(handle))) {
|
2020-09-12 10:55:46 -07:00
|
|
|
HAL_SetSimValue(handle, valueCopy);
|
|
|
|
|
}
|
2019-09-23 00:24:10 -07:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
static void DisplaySimDevice(const char* name, void* data,
|
|
|
|
|
HAL_SimDeviceHandle handle) {
|
2021-02-21 16:35:49 -08:00
|
|
|
wpi::StringRef id{name};
|
|
|
|
|
if (!gSimDevicesShowPrefix) {
|
|
|
|
|
// only show "Foo" portion of "Accel:Foo"
|
|
|
|
|
wpi::StringRef type;
|
|
|
|
|
std::tie(type, id) = id.split(':');
|
|
|
|
|
if (id.empty()) {
|
|
|
|
|
id = type;
|
|
|
|
|
}
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2020-12-23 15:54:11 -08:00
|
|
|
if (glass::BeginDevice(id.data())) {
|
2020-09-12 10:55:46 -07:00
|
|
|
HALSIM_EnumerateSimValues(handle, data, DisplaySimValue);
|
|
|
|
|
glass::EndDevice();
|
2019-09-23 00:24:10 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SimDeviceGui::Initialize() {
|
2020-09-12 10:55:46 -07:00
|
|
|
HALSimGui::halProvider.Register(
|
|
|
|
|
"Other Devices", [] { return true; },
|
|
|
|
|
[] { return std::make_unique<glass::DeviceTreeModel>(); },
|
|
|
|
|
[](glass::Window* win, glass::Model* model) {
|
|
|
|
|
win->SetDefaultPos(1025, 20);
|
|
|
|
|
win->SetDefaultSize(250, 695);
|
2021-02-21 16:35:49 -08:00
|
|
|
win->DisableRenamePopup();
|
|
|
|
|
return glass::MakeFunctionView([=] {
|
|
|
|
|
if (ImGui::BeginPopupContextItem()) {
|
|
|
|
|
ImGui::Checkbox("Show prefix", &gSimDevicesShowPrefix);
|
|
|
|
|
ImGui::EndPopup();
|
|
|
|
|
}
|
|
|
|
|
static_cast<glass::DeviceTreeModel*>(model)->Display();
|
|
|
|
|
});
|
2020-09-12 10:55:46 -07:00
|
|
|
});
|
2020-12-24 12:24:36 -08:00
|
|
|
HALSimGui::halProvider.ShowDefault("Other Devices");
|
2019-09-23 00:24:10 -07:00
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
auto model = std::make_unique<SimDevicesModel>();
|
|
|
|
|
gSimDevicesModel = model.get();
|
|
|
|
|
GetDeviceTree().Add(std::move(model), [](glass::Model* model) {
|
|
|
|
|
HALSIM_EnumerateSimDevices("", static_cast<SimDevicesModel*>(model),
|
|
|
|
|
DisplaySimDevice);
|
|
|
|
|
});
|
2019-09-23 00:24:10 -07:00
|
|
|
}
|
|
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
glass::DataSource* SimDeviceGui::GetValueSource(HAL_SimValueHandle handle) {
|
|
|
|
|
return gSimDevicesModel->GetSource(handle);
|
2019-09-23 00:24:10 -07:00
|
|
|
}
|
|
|
|
|
|
2020-09-12 10:55:46 -07:00
|
|
|
glass::DeviceTreeModel& SimDeviceGui::GetDeviceTree() {
|
|
|
|
|
static auto model = HALSimGui::halProvider.GetModel("Other Devices");
|
|
|
|
|
assert(model);
|
|
|
|
|
return *static_cast<glass::DeviceTreeModel*>(model);
|
2019-09-23 00:24:10 -07:00
|
|
|
}
|