#pragma once #include "event_bus.hpp" #include #include #include #include #include "topic.hpp" #ifndef MAX_CID #define MAX_CID 64 #endif enum class MsgKind : uint8_t { Connect = 0, Disconnect = 1, Event = 2, Ping = 3, Pong = 4 }; template (Topic::COUNT)> class CommBase { using Bits = std::bitset; std::array subs_; portMUX_TYPE mux_ portMUX_INITIALIZER_UNLOCKED; std::array subscriptionHandle {}; static constexpr size_t invalid = SIZE_MAX; static constexpr size_t idx(Topic t) { size_t i = static_cast(t); return i < NTopics ? i : invalid; } template void encode(JsonDocument& d, const typename TopicTraits::Msg& m) { auto a = d.to(); a.add(static_cast(MsgKind::Event)); a.add(static_cast(T)); toJson(a.add(), m); } protected: virtual void send(size_t cid, const char* data, size_t len) = 0; template auto& getHandle(Topic topic) { using H = typename EventBus::Handle; static H dummy; auto* p = static_cast(subscriptionHandle[size_t(topic)]); return p ? *p : dummy; } template void setHandle(Topic topic, typename EventBus::Handle&& h) { using H = typename EventBus::Handle; subscriptionHandle[size_t(topic)] = new H(std::move(h)); } public: void subscribe(Topic t, size_t cid) { size_t i = idx(t); if (i == invalid) return; portENTER_CRITICAL(&mux_); subs_[i].set(cid); portEXIT_CRITICAL(&mux_); } void unsubscribe(Topic t, size_t cid) { size_t i = idx(t); if (i == invalid) return; portENTER_CRITICAL(&mux_); subs_[i].reset(cid); portEXIT_CRITICAL(&mux_); } bool has(Topic t) const { size_t i = idx(t); return i == invalid ? false : subs_[i].any(); } template void emit(const typename TopicTraits::Msg& m) { constexpr size_t i = idx(T); if (i == invalid) return; if (!subs_[i].any()) return; JsonDocument doc; encode(doc, m); String out; #if USE_MSGPACK serializeMsgPack(doc, out); #else serializeJson(doc, out); #endif auto& b = subs_[i]; for (size_t cid = 0; cid < MaxCid; ++cid) if (b.test(cid)) send(cid, out.c_str(), out.length()); } };