From e1f5820aba8f0bcb391d09cc6d0b4a6ec797ca54 Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Fri, 3 May 2024 00:35:09 -0400 Subject: [PATCH] Add registerSimValue callbacks - Fixes #90 --- .../gen/simulation/SimDeviceData.yml | 67 ++++++++++++++++++- .../robotpy-hal/hal/simulation/main.cpp | 5 ++ .../robotpy-hal/hal/simulation/sim_value_cb.h | 37 ++++++++++ .../robotpy-hal/tests/test_hal_simulation.py | 40 ++++++++++- 4 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 subprojects/robotpy-hal/hal/simulation/sim_value_cb.h diff --git a/subprojects/robotpy-hal/gen/simulation/SimDeviceData.yml b/subprojects/robotpy-hal/gen/simulation/SimDeviceData.yml index e6a28dc1..793bac0a 100644 --- a/subprojects/robotpy-hal/gen/simulation/SimDeviceData.yml +++ b/subprojects/robotpy-hal/gen/simulation/SimDeviceData.yml @@ -1,5 +1,9 @@ --- +extra_includes: +- sim_value_cb.h +- pybind11/functional.h + strip_prefixes: - HALSIM_ @@ -9,26 +13,83 @@ functions: HALSIM_RegisterSimDeviceCreatedCallback: ignore: true HALSIM_CancelSimDeviceCreatedCallback: + ignore: true HALSIM_RegisterSimDeviceFreedCallback: ignore: true HALSIM_CancelSimDeviceCreatedCallback: + ignore: true HALSIM_CancelSimDeviceFreedCallback: + ignore: true HALSIM_GetSimDeviceHandle: HALSIM_GetSimDeviceName: HALSIM_GetSimValueDeviceHandle: HALSIM_EnumerateSimDevices: ignore: true HALSIM_RegisterSimValueCreatedCallback: - ignore: true + param_override: + param: + ignore: true + cpp_code: | + [](hal::SimDevice &simdevice, std::function fn, bool initialNotify) -> std::unique_ptr { + auto cb = std::make_unique(fn, HALSIM_CancelSimDeviceCreatedCallback); + auto uid = HALSIM_RegisterSimValueCreatedCallback(simdevice, cb.get(), + [](const char* name, void* param, + HAL_SimValueHandle handle, + int32_t direction, + const struct HAL_Value* value) { + ((SimValueCB*)param)->m_fn(name, handle, (HAL_SimValueDirection)direction, *value); + }, initialNotify); + cb->SetUID(uid); + return std::move(cb); + } HALSIM_CancelSimDeviceCreatedCallback: + ignore: true HALSIM_CancelSimValueCreatedCallback: - HALSIM_RegisterSimValueChangedCallback: ignore: true + HALSIM_RegisterSimValueChangedCallback: + param_override: + handle: + name: value + param: + ignore: true + cpp_code: | + [](hal::SimValue &simvalue, std::function fn, bool initialNotify) -> std::unique_ptr { + auto cb = std::make_unique(fn, HALSIM_CancelSimValueChangedCallback); + auto uid = HALSIM_RegisterSimValueChangedCallback(simvalue, cb.get(), + [](const char* name, void* param, + HAL_SimValueHandle handle, + int32_t direction, + const struct HAL_Value* value) { + ((SimValueCB*)param)->m_fn(name, handle, (HAL_SimValueDirection)direction, *value); + }, initialNotify); + cb->SetUID(uid); + return std::move(cb); + } HALSIM_CancelSimDeviceCreatedCallback: + ignore: true HALSIM_CancelSimValueChangedCallback: - HALSIM_RegisterSimValueResetCallback: ignore: true + HALSIM_RegisterSimValueResetCallback: + param_override: + handle: + name: value + param: + ignore: true + cpp_code: | + [](hal::SimValue &simvalue, std::function fn, bool initialNotify) -> std::unique_ptr { + auto cb = std::make_unique(fn, HALSIM_CancelSimValueResetCallback); + auto uid = HALSIM_RegisterSimValueChangedCallback(simvalue, cb.get(), + [](const char* name, void* param, + HAL_SimValueHandle handle, + int32_t direction, + const struct HAL_Value* value) { + ((SimValueCB*)param)->m_fn(name, handle, (HAL_SimValueDirection)direction, *value); + }, initialNotify); + cb->SetUID(uid); + return std::move(cb); + } HALSIM_CancelSimValueResetCallback: + ignore: true HALSIM_GetSimValueHandle: HALSIM_EnumerateSimValues: ignore: true diff --git a/subprojects/robotpy-hal/hal/simulation/main.cpp b/subprojects/robotpy-hal/hal/simulation/main.cpp index affebc05..354b75c1 100644 --- a/subprojects/robotpy-hal/hal/simulation/main.cpp +++ b/subprojects/robotpy-hal/hal/simulation/main.cpp @@ -3,6 +3,7 @@ #include #include "sim_cb.h" +#include "sim_value_cb.h" void HALSIM_ResetGlobalHandles(); @@ -12,6 +13,10 @@ RPYBUILD_PYBIND11_MODULE(m) { cls_SimCB.doc() = "Simulation callback handle"; cls_SimCB.def("cancel", &SimCB::Cancel, py::doc("Cancel the callback")); + py::class_ cls_SimValueCB(m, "SimValueCB"); + cls_SimValueCB.doc() = "Simulation callback handle"; + cls_SimValueCB.def("cancel", &SimValueCB::Cancel, py::doc("Cancel the callback")); + initWrapper(m); m.def( diff --git a/subprojects/robotpy-hal/hal/simulation/sim_value_cb.h b/subprojects/robotpy-hal/hal/simulation/sim_value_cb.h new file mode 100644 index 00000000..d7477caa --- /dev/null +++ b/subprojects/robotpy-hal/hal/simulation/sim_value_cb.h @@ -0,0 +1,37 @@ + +#pragma once + +#include + +class SimValueCB { +public: + + using FnType = std::function; + + SimValueCB(FnType fn, std::function cancel) : + m_fn(fn), + m_cancel(cancel) + {} + + void SetUID(int32_t uid) { + m_uid = uid; + } + + ~SimValueCB() { + Cancel(); + } + + void Cancel() { + if (m_valid) { + m_cancel(m_uid); + m_valid = false; + } + } + + FnType m_fn; + +private: + bool m_valid = true; + int32_t m_uid; + std::function m_cancel; +}; \ No newline at end of file diff --git a/subprojects/robotpy-hal/tests/test_hal_simulation.py b/subprojects/robotpy-hal/tests/test_hal_simulation.py index ea8ddc66..f9fd666b 100644 --- a/subprojects/robotpy-hal/tests/test_hal_simulation.py +++ b/subprojects/robotpy-hal/tests/test_hal_simulation.py @@ -1,5 +1,41 @@ +import hal import hal.simulation +import typing -def test_hal_simulation(): - pass + +def test_value_changed_callback(): + + recv: typing.Optional[typing.Tuple[bool, str, int]] = None + + def created_cb( + name: str, handle: int, direction: hal.SimValueDirection, value: hal.Value + ): + nonlocal recv + recv = (True, name, value.value) + + def cb(name: str, handle: int, direction: hal.SimValueDirection, value: hal.Value): + nonlocal recv + recv = (False, name, value.value) + + dev = hal.SimDevice("simd") + + # Must keep the returned value alive or the callback will be unregistered + devunused = hal.simulation.registerSimValueCreatedCallback(dev, created_cb, True) + assert recv is None + + val = dev.createInt("answer", 0, 42) + + assert recv == (True, "answer", 42) + recv = None + + # Must keep the returned value alive or the callback will be unregistered + unused = hal.simulation.registerSimValueChangedCallback(val, cb, True) + + assert recv == (False, "answer", 42) + recv = None + + val.set(84) + + assert recv == (False, "answer", 84) + recv = None