From 07d1a9ad752deccac34f237a94a82e3abd822568 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 | 50 ++++++++++++++++++- .../robotpy-hal/hal/simulation/main.cpp | 5 ++ .../robotpy-hal/hal/simulation/sim_value_cb.h | 37 ++++++++++++++ .../robotpy-hal/tests/test_hal_simulation.py | 31 +++++++++++- 4 files changed, 119 insertions(+), 4 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..f229803e 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,10 +13,13 @@ 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: @@ -21,14 +28,53 @@ functions: HALSIM_RegisterSimValueCreatedCallback: ignore: true 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..55a70275 100644 --- a/subprojects/robotpy-hal/tests/test_hal_simulation.py +++ b/subprojects/robotpy-hal/tests/test_hal_simulation.py @@ -1,5 +1,32 @@ +import hal import hal.simulation +import typing -def test_hal_simulation(): - pass + +def test_value_changed_callback(): + + recv_name: typing.Optional[str] = None + recv_value: typing.Optional[hal.Value] = None + + def cb(name: str, handle: int, direction: hal.SimValueDirection, value: hal.Value): + nonlocal recv_name, recv_value + recv_name = name + recv_value = value + print(name, value) + + dev = hal.SimDevice("simd") + val = dev.createInt("answer", 0, 42) + + # Must keep the returned value alive or the callback will be unregistered + unused = hal.simulation.registerSimValueChangedCallback(val, cb, True) + + assert recv_name == "answer" + assert recv_value is not None + assert recv_value.value == 42 + + val.set(84) + + assert recv_name == "answer" + assert recv_value is not None + assert recv_value.value == 84