From 4625f56c6eb3dac67f80ba88e5c4a558db8b3c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominic=20H=C3=B6glinger?= Date: Fri, 26 Sep 2025 17:41:34 +0200 Subject: [PATCH] Radio: Add state PubSub, generalize PubSub --- .../Include/Tactility/hal/radio/PubSub.h | 49 +++++++++++++++++++ .../Include/Tactility/hal/radio/RadioDevice.h | 45 ++++++++++------- Tactility/Source/hal/radio/RadioDevice.cpp | 9 ++-- TactilityC/Include/tt_hal_radio.h | 10 ++++ TactilityC/Source/tt_hal_radio.cpp | 9 ++++ TactilityC/Source/tt_init.cpp | 1 + 6 files changed, 102 insertions(+), 21 deletions(-) create mode 100644 Tactility/Include/Tactility/hal/radio/PubSub.h diff --git a/Tactility/Include/Tactility/hal/radio/PubSub.h b/Tactility/Include/Tactility/hal/radio/PubSub.h new file mode 100644 index 00000000..ab2bf785 --- /dev/null +++ b/Tactility/Include/Tactility/hal/radio/PubSub.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +namespace tt::hal::radio { + +// Proposed PubSub class, can be moved elsewhere +template +class PubSub +{ +public: + typedef int SubscriptionId; + using Notifier = std::function; + +protected: + struct Subscription { + SubscriptionId id; + std::shared_ptr notifier; + }; + + SubscriptionId lastSubscriptionId = 0; + std::vector subscriptions; + +public: + + PubSub() {} + virtual ~PubSub() = default; + + SubscriptionId subscribe(Notifier onPublish) { + subscriptions.push_back({ + .id = ++lastSubscriptionId, + .notifier = std::make_shared(onPublish) + }); + return lastSubscriptionId; + } + + void unsubscribe(SubscriptionId subscriptionId) { + std::erase_if(subscriptions, [subscriptionId](auto& subscription) { return subscription.id == subscriptionId; }); + } + + void publish(Ts... pargs) { + for (auto& subscription : subscriptions) { + (*subscription.notifier)(pargs...); + } + } +}; + +} diff --git a/Tactility/Include/Tactility/hal/radio/RadioDevice.h b/Tactility/Include/Tactility/hal/radio/RadioDevice.h index c3c53277..ea0781bf 100644 --- a/Tactility/Include/Tactility/hal/radio/RadioDevice.h +++ b/Tactility/Include/Tactility/hal/radio/RadioDevice.h @@ -1,6 +1,7 @@ #pragma once #include "../Device.h" +#include "PubSub.h" #include "Unit.h" #include @@ -52,10 +53,6 @@ public: Success }; - typedef int RxSubscriptionId; - typedef int TxId; - - enum class State { PendingOn, On, @@ -72,6 +69,15 @@ public: Error }; + typedef int TxId; + + using StatePubSub = PubSub; + using RxPubSub = PubSub; + using StateSubscriptionId = StatePubSub::SubscriptionId; + using RxSubscriptionId = RxPubSub::SubscriptionId; + + using StateCallback = StatePubSub::Notifier; + using RxCallback = RxPubSub::Notifier; using TxStateCallback = std::function; protected: @@ -82,18 +88,13 @@ protected: }; private: - struct RxSubscription { - RxSubscriptionId id; - std::shared_ptr> onData; - }; - State state; Modulation modulation; Mutex mutex = Mutex(Mutex::Type::Recursive); - std::vector rxSubscriptions; + StatePubSub statePubSub; + RxPubSub rxPubSub; std::deque txQueue; TxId lastTxId = 0; - RxSubscriptionId lastRxSubscriptionId = 0; protected: const Mutex &getMutex() const { return mutex; } @@ -150,20 +151,28 @@ public: return txId; } - RxSubscriptionId subscribeRx(const std::function& onData) { + StateSubscriptionId subscribeStateChange(StateCallback onChange) { auto lock = mutex.asScopedLock(); lock.lock(); - rxSubscriptions.push_back({ - .id = ++lastRxSubscriptionId, - .onData = std::make_shared>(onData) - }); - return lastRxSubscriptionId; + return statePubSub.subscribe(onChange); + } + + void unsubscribeStateChange(StateSubscriptionId subscriptionId) { + auto lock = mutex.asScopedLock(); + lock.lock(); + return rxPubSub.unsubscribe(subscriptionId); + } + + RxSubscriptionId subscribeRx(const RxCallback& onData) { + auto lock = mutex.asScopedLock(); + lock.lock(); + return rxPubSub.subscribe(onData); } void unsubscribeRx(RxSubscriptionId subscriptionId) { auto lock = mutex.asScopedLock(); lock.lock(); - std::erase_if(rxSubscriptions, [subscriptionId](auto& subscription) { return subscription.id == subscriptionId; }); + return rxPubSub.unsubscribe(subscriptionId); } State getState() const; diff --git a/Tactility/Source/hal/radio/RadioDevice.cpp b/Tactility/Source/hal/radio/RadioDevice.cpp index 243da6fd..d2738fbb 100644 --- a/Tactility/Source/hal/radio/RadioDevice.cpp +++ b/Tactility/Source/hal/radio/RadioDevice.cpp @@ -39,14 +39,17 @@ RadioDevice::State RadioDevice::getState() const { void RadioDevice::setState(State newState) { auto lock = mutex.asScopedLock(); lock.lock(); + + if (state != newState) { + statePubSub.publish(getId(), newState); + } + state = newState; } void RadioDevice::publishRx(const RxPacket& packet) { mutex.lock(); - for (auto& subscription : rxSubscriptions) { - (*subscription.onData)(getId(), packet); - } + rxPubSub.publish(getId(), packet); mutex.unlock(); } diff --git a/TactilityC/Include/tt_hal_radio.h b/TactilityC/Include/tt_hal_radio.h index aa3b321a..7c47d0b3 100644 --- a/TactilityC/Include/tt_hal_radio.h +++ b/TactilityC/Include/tt_hal_radio.h @@ -52,6 +52,7 @@ enum RadioTxState { }; typedef int32_t RadioRxSubscriptionId; +typedef int32_t RadioStateSubscriptionId; typedef int32_t RadioTxId; struct RadioRxPacket { @@ -67,6 +68,7 @@ struct RadioTxPacket { uint32_t address; }; +typedef void (*RadioStateCallback)(DeviceId id, RadioState state); typedef void (*RadioTxStateCallback)(RadioTxId id, RadioTxState state); typedef void (*RadioOnReceiveCallback)(DeviceId id, const RadioRxPacket* packet); @@ -203,6 +205,14 @@ RadioTxId tt_hal_radio_transmit(RadioHandle handle, RadioTxPacket packet, RadioT */ RadioRxSubscriptionId tt_hal_radio_subscribe_receive(RadioHandle handle, RadioOnReceiveCallback callback); +/** + * Subscribe for any state change of the radio driver object. + * @param[in] handle the radio driver handle + * @param[in] callback function to call when the state of the radio changes + * @return the identifier for the subscription + */ +RadioStateSubscriptionId tt_hal_radio_subscribe_state(RadioHandle handle, RadioStateCallback callback); + /** * Unsubscribe for any received packet that the radio driver object receives. * @param[in] handle the radio driver handle diff --git a/TactilityC/Source/tt_hal_radio.cpp b/TactilityC/Source/tt_hal_radio.cpp index b903a18d..58d4bd29 100644 --- a/TactilityC/Source/tt_hal_radio.cpp +++ b/TactilityC/Source/tt_hal_radio.cpp @@ -129,6 +129,15 @@ extern "C" { }); } + RadioStateSubscriptionId tt_hal_radio_subscribe_state(RadioHandle handle, RadioStateCallback callback) { + auto wrapper = static_cast(handle); + return wrapper->device->subscribeStateChange([callback](tt::hal::Device::Id id, tt::hal::radio::RadioDevice::State state) { + if (callback) { + callback(id, fromCpp(state)); + } + }); + } + RadioRxSubscriptionId tt_hal_radio_subscribe_receive(RadioHandle handle, RadioOnReceiveCallback callback) { auto wrapper = static_cast(handle); return wrapper->device->subscribeRx([callback](tt::hal::Device::Id id, const tt::hal::radio::RxPacket& ttPacket) { diff --git a/TactilityC/Source/tt_init.cpp b/TactilityC/Source/tt_init.cpp index dae9af86..ac0ffc90 100644 --- a/TactilityC/Source/tt_init.cpp +++ b/TactilityC/Source/tt_init.cpp @@ -282,6 +282,7 @@ const esp_elfsym elf_symbols[] { ESP_ELFSYM_EXPORT(tt_hal_radio_start), ESP_ELFSYM_EXPORT(tt_hal_radio_stop), ESP_ELFSYM_EXPORT(tt_hal_radio_transmit), + ESP_ELFSYM_EXPORT(tt_hal_radio_subscribe_state), ESP_ELFSYM_EXPORT(tt_hal_radio_subscribe_receive), ESP_ELFSYM_EXPORT(tt_hal_radio_unsubscribe_receive), ESP_ELFSYM_EXPORT(tt_hal_touch_driver_get_touched_points),