/* * threads_actor.hpp * * Created on: Jun 11, 2021 * Author: erki */ #ifndef SKULLC_THREADS_ACTOR_HPP_ #define SKULLC_THREADS_ACTOR_HPP_ #include #include #include "threads_primitivethread.hpp" #include "threads_signal.hpp" namespace Threads { template class Actor { public: using value_type = T; static_assert(std::is_trivially_constructible_v, "T must be trivially constructible."); static_assert(std::is_trivially_copyable_v, "T must be trivially copyable."); Actor(const std::uint32_t queue_size, const char* name, const osPriority_t priority, const std::uint32_t stack_size) : thread_([](void* d) { auto* dd = static_cast*>(d); (*dd)(); }, this, name, priority, stack_size), msg_queue_(xQueueCreate(queue_size, sizeof(value_type))), signal_(*this) { assert(msg_queue_); } Signallable* getSignal() { return &signal_; } protected: virtual void init() = 0; virtual void onSignal(const T& data) = 0; private: PrimitiveThread thread_; QueueHandle_t msg_queue_; void operator()() { init(); value_type data; while (true) { const BaseType_t got = xQueueReceive(msg_queue_, &data, portMAX_DELAY); if (got) { onSignal(data); } } } friend struct Signal_; struct Signal_ : Signallable { using parent = Actor; parent& q; explicit Signal_(parent& q) : q(q) {} bool emit(const value_type& data) override { const BaseType_t success = xQueueSend(q.msg_queue_, &data, 0); return success == pdTRUE; } std::pair emitFromIsr(const value_type& data) override { BaseType_t was_awoken = pdFALSE; const BaseType_t success = xQueueSendFromISR(q.msg_queue_, &data, &was_awoken); return {success == pdTRUE, was_awoken}; } }; Signal_ signal_; }; }// namespace Threads #endif /* SKULLC_THREADS_ACTOR_HPP_ */