diff --git a/.drone.yml b/.drone.yml index 0c6f33e..8459a83 100644 --- a/.drone.yml +++ b/.drone.yml @@ -9,7 +9,6 @@ steps: commands: - mkdir -p build - cd build - - conan install .. --build=missing - cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON - ninja - ctest . --output-on-failure diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f5c83f..b47f745 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,19 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR) -set(version 0.1.0) +set(SKULLC_VERSION 0.1.0) project(skullc - VERSION ${version} + VERSION ${SKULLC_VERSION} LANGUAGES C CXX ) -list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) +#list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/) -set(CMAKE_CXX_STANDARD 17) -list(APPEND CMAKE_CXX_FLAGS "-Wall -Wextra") - -option(WITH_TESTS "Enable unit testing." OFF) -option(WITH_HAL "Enable the compiling and deployment of the HAL dependent sections." OFF) +option(SKULLC_WITH_TESTS "Enable unit testing." OFF) +option(SKULLC_WITH_HAL "Enable the compiling and deployment of the HAL dependent sections." OFF) include(skullc-install) @@ -24,7 +21,7 @@ add_subdirectory(Peripherals) add_subdirectory(Utility) add_subdirectory(Messaging) -if(WITH_TESTS) +if(SKULLC_WITH_TESTS) enable_testing() add_subdirectory(Tests) endif() diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..a5e0ff9 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,50 @@ +pipeline { + agent { + label 'ubuntu' + } + + stages { + stage("build && test") { + steps { + echo "Workspace: ${env.WORKSPACE}" + sh 'mkdir -p build' + + dir("build") { + sh 'ls' + sh 'cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DSKULLC_WITH_TESTS=ON' + sh 'ninja' + sh 'ctest . -T test --output-on-failure --no-compress-output' + } + } + } + } + + post { + always { + archiveArtifacts ( + artifacts: 'build/Testing/**/*.xml', + fingerprint: true + ) + + // Process the CTest xml output with the xUnit plugin + xunit ( + testTimeMargin: '3000', + thresholdMode: 1, + thresholds: [ + skipped(failureThreshold: '0'), + failed(failureThreshold: '0') + ], + tools: [CTest( + pattern: 'build/Testing/**/*.xml', + deleteOutputFiles: true, + failIfNotNew: false, + skipNoTestFiles: true, + stopProcessingIfError: true + )] + ) + + // Clear the source and build dirs before next run + deleteDir() + } + } +} diff --git a/Messaging/CMakeLists.txt b/Messaging/CMakeLists.txt index 761c997..ad8e4e3 100644 --- a/Messaging/CMakeLists.txt +++ b/Messaging/CMakeLists.txt @@ -5,9 +5,9 @@ add_library(messaging INTERFACE) add_library(skullc::messaging ALIAS messaging) target_include_directories(messaging - INTERFACE + INTERFACE $ $ - ) +) -skullc_install_packages(skullc messaging ${version}) +skullc_install_packages(skullc messaging ${SKULLC_VERSION}) diff --git a/Peripherals/CMakeLists.txt b/Peripherals/CMakeLists.txt index a143b86..4928c42 100644 --- a/Peripherals/CMakeLists.txt +++ b/Peripherals/CMakeLists.txt @@ -11,4 +11,4 @@ target_include_directories(peripherals ) ## INSTALL -skullc_install_packages(skullc peripherals ${version}) +skullc_install_packages(skullc peripherals ${SKULLC_VERSION}) diff --git a/Peripherals/Inc/peripherals_imu_icm.hpp b/Peripherals/Inc/peripherals_imu_icm.hpp index 9c02218..4c3a3b7 100644 --- a/Peripherals/Inc/peripherals_imu_icm.hpp +++ b/Peripherals/Inc/peripherals_imu_icm.hpp @@ -74,11 +74,12 @@ public: const std::uint8_t new_gyro_conf = (std::uint32_t(scale_gyro_) << 3); registers.writeRegister(Registers_::GYRO_CONFIG & Registers_::WRITE_MASK, - new_gyro_conf); + new_gyro_conf); const std::uint8_t new_accel_config = (std::uint32_t(scale_accel_) << 3); registers.writeRegister(Registers_::ACCEL_CONFIG & Registers_::WRITE_MASK, - new_accel_config); + new_accel_config); + // ACCEL_FCHOICE_B = 0, A_DLPF_CFG = 3 filter=44.8/61.5 rate=1KHz registers.writeRegister(Registers_::ACCEL_CONFIG2 & Registers_::WRITE_MASK, diff --git a/Peripherals/Inc/peripherals_utility.hpp b/Peripherals/Inc/peripherals_utility.hpp index 34b2691..0ab29af 100644 --- a/Peripherals/Inc/peripherals_utility.hpp +++ b/Peripherals/Inc/peripherals_utility.hpp @@ -15,10 +15,6 @@ namespace Peripherals { -#define SKULLC_CONCAT_IMPL(x, y) x##y -#define SKULLC_CONCAT(x, y) SKULLC_CONCAT_IMPL(x, y) -#define SKULLC_TAG struct SKULLC_CONCAT(SkullCTag_, __COUNTER__) - template constexpr const T& clamp(const T& v, const T& lo, const T& hi) { diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index cdb718a..53eedd7 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1,10 +1,16 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR) -option(TESTS_WITH_SANITIZERS "Enable sanitizers for tests." ON) +option(SKULLC_TESTS_WITH_SANITIZERS "Enable sanitizers for tests." ON) -find_package(Catch2 REQUIRED) +include(FetchContent) -if(TESTS_WITH_SANITIZERS) +FetchContent_Declare(Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v2.13.8 +) +FetchContent_MakeAvailable(Catch2) + +if(SKULLC_TESTS_WITH_SANITIZERS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -fno-sanitize-recover") set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -fno-sanitize-recover") endif() @@ -18,7 +24,12 @@ add_executable(tests rand.cpp fixedpoint.cpp pixelbuffer.cpp - pixelbuffer_effects.cpp function.cpp) + pixelbuffer_effects.cpp + function.cpp + assert_ndebug.cpp + assert.cpp + enum_helpers.cpp +) target_link_libraries(tests PUBLIC @@ -28,6 +39,12 @@ target_link_libraries(tests Catch2::Catch2 ) +set_target_properties(tests + PROPERTIES + CXX_STANDARD 17 +) + +list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/contrib) include(CTest) include(Catch) catch_discover_tests(tests) \ No newline at end of file diff --git a/Tests/assert.cpp b/Tests/assert.cpp new file mode 100644 index 0000000..ee606f3 --- /dev/null +++ b/Tests/assert.cpp @@ -0,0 +1,68 @@ +// +// Created by erki on 29.06.22. +// + +#include + +#ifdef NDEBUG +#undef NDEBUG +#define NDEBUG_WAS_SET +#endif + +#include "utility_assert.hpp" + +#ifdef NDEBUG_WAS_SET +#define NDEBUG +#endif + +namespace +{ + +bool assert_flag = false; + +void assertCallback(const char*, const char*, const int) +{ + assert_flag = true; +} + +}// namespace + +TEST_CASE("Assert debug without NDEBUG gets triggered if check is false.", "[utility],[assert]") +{ + assert_flag = false; + Utility::Assert::setHandler(assertCallback); + + SKULLC_ASSERT_DEBUG(false); + + CHECK(assert_flag == true); +} + +TEST_CASE("Assert debug without NDEBUG doesn't get triggered if check is true.", "[utility],[assert]") +{ + assert_flag = false; + Utility::Assert::setHandler(assertCallback); + + SKULLC_ASSERT_DEBUG(true); + + CHECK(assert_flag == false); +} + +TEST_CASE("Assert safe without NDEBUG gets triggered if check is false.", "[utility],[assert]") +{ + assert_flag = false; + Utility::Assert::setHandler(assertCallback); + + SKULLC_ASSERT_SAFE(false); + + CHECK(assert_flag == true); +} + +TEST_CASE("Assert safe without NDEBUG doesn't get triggered if check is true.", "[utility],[assert]") +{ + assert_flag = false; + Utility::Assert::setHandler(assertCallback); + + SKULLC_ASSERT_SAFE(true); + + CHECK(assert_flag == false); +} diff --git a/Tests/assert_ndebug.cpp b/Tests/assert_ndebug.cpp new file mode 100644 index 0000000..e921a1c --- /dev/null +++ b/Tests/assert_ndebug.cpp @@ -0,0 +1,62 @@ +// +// Created by erki on 29.06.22. +// + +#include + +#ifndef NDEBUG +#define NDEBUG +#define NDEBUG_WAS_NOT_DEFINED +#endif + +#include "utility_assert.hpp" + +#ifdef NDEBUG_WAS_NOT_DEFINED +#undef NDEBUG +#endif + +namespace +{ + +bool assert_flag = false; + +void assertCallback(const char*, const char*, const int) +{ + assert_flag = true; +} + +}// namespace + +TEST_CASE("Assert debug with NDEBUG is a null-opt.", "[utility],[assert]") +{ + assert_flag = false; + Utility::Assert::setHandler(assertCallback); + + int check_number = 0; + SKULLC_ASSERT_DEBUG(check_number++ == 0); + + CHECK(check_number == 0); + CHECK(assert_flag == false); +} + +TEST_CASE("Assert safe with NDEBUG gets triggered if check is false.", "[utility],[assert]") +{ + assert_flag = false; + Utility::Assert::setHandler(assertCallback); + + int check_number = 0; + SKULLC_ASSERT_SAFE(check_number++ == 1); + + CHECK(check_number == 1); + CHECK(assert_flag == true); +} + +TEST_CASE("Assert safe with NDEBUG doesn't get triggered if check is true.", "[utility],[assert]") +{ + assert_flag = false; + Utility::Assert::setHandler(assertCallback); + + SKULLC_ASSERT_SAFE(true); + + CHECK(assert_flag == false); +} diff --git a/Tests/enum_helpers.cpp b/Tests/enum_helpers.cpp new file mode 100644 index 0000000..1d8df14 --- /dev/null +++ b/Tests/enum_helpers.cpp @@ -0,0 +1,41 @@ +// +// Created by erki on 15.07.22. +// + +#include + +#include "utility_enum_helpers.hpp" + +namespace +{ + +enum class TestEnum : unsigned +{ + FLAG_0 = 1, + FLAG_1 = 2, + FLAG_2 = 4 +}; + +SKULLC_ENUM_DECLARE_BITFLAG_OPERATORS(TestEnum) + +}// namespace + +TEST_CASE("OR operator works as expected.", "[utility],[enum_helpers]") +{ + const TestEnum a = TestEnum::FLAG_0; + const TestEnum b = TestEnum::FLAG_1; + + const TestEnum sum = a | b; + CHECK(unsigned(sum) == 3u); +} + +TEST_CASE("AND operator works as expected.", "[utility],[enum_helpers]") +{ + const TestEnum a = TestEnum::FLAG_0 | TestEnum::FLAG_1; + + const TestEnum masked_1 = a & TestEnum::FLAG_0; + CHECK(masked_1 == TestEnum::FLAG_0); + + const TestEnum masked_2 = a & TestEnum::FLAG_2; + CHECK(masked_2 != TestEnum::FLAG_2); +} diff --git a/Tests/function.cpp b/Tests/function.cpp index a9dbe19..c7383fc 100644 --- a/Tests/function.cpp +++ b/Tests/function.cpp @@ -5,6 +5,7 @@ #include #include +#include TEST_CASE("Function calls function appropriately.", "[utility],[function]") { @@ -38,6 +39,26 @@ TEST_CASE("Function passes arguments appropriately.", "[utility],[function]") REQUIRE(bool_to_set == true); } +TEST_CASE("Function works with toStaticFunction.", "[utility],[function]") +{ + static int int_to_set = 0; + static bool bool_to_set = false; + + auto func_to_call = [](const int i, const bool b) { + int_to_set = i; + bool_to_set = b; + }; + + Utility::Function function(func_to_call); + using signature = void (*)(int, bool); + + signature func_pointer = function.toStaticFunction(); + func_pointer(10, true); + + REQUIRE(int_to_set == 10); + REQUIRE(bool_to_set == true); +} + TEST_CASE("FunctionOwned calls function appropriately.", "[utility],[function]") { struct S @@ -82,3 +103,29 @@ TEST_CASE("FunctionOwned passes arguments appropriately.", "[utility],[function] REQUIRE(subject.int_to_set == 10); REQUIRE(subject.bool_to_set == false); } + +TEST_CASE("FunctionOwned works with toStaticFunction.", "[utility],[function]") +{ + struct S + { + int int_to_set = 0; + bool bool_to_set = true; + + void toCall(const int i, const bool b) + { + int_to_set = i; + bool_to_set = b; + } + }; + + S subject; + + Utility::FunctionOwned function(subject, &S::toCall); + using signature = void (*)(int, bool); + + signature func_pointer = function.toStaticFunction(); + func_pointer(10, true); + + REQUIRE(subject.int_to_set == 10); + REQUIRE(subject.bool_to_set == true); +} diff --git a/Threads/Inc/threads_actor.hpp b/Threads/Inc/threads_actor.hpp index 41037a1..fb81899 100644 --- a/Threads/Inc/threads_actor.hpp +++ b/Threads/Inc/threads_actor.hpp @@ -15,15 +15,15 @@ #include #include -#include "threads_primitivethread.hpp" -#include "threads_signal.hpp" -#include "threads_timer.hpp" +#include +#include +#include namespace Threads { template -class Actor +class Actor : public IActor { public: using value_type = std::variant; @@ -31,14 +31,11 @@ public: static_assert(std::is_default_constructible_v, "Ts must be default constructible."); static_assert(std::is_trivially_copyable_v, "Ts 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_(&Actor::threadHandler_, this, name, priority, stack_size), - msg_queue_(xQueueCreate(queue_size, sizeof(value_type))), signal_(this) - { - assert(msg_queue_); - } + Actor() : IActor(sizeof(value_type)), + signal_(this) + {} - virtual ~Actor() {} + ~Actor() override {} template struct Signal : Signallable @@ -59,17 +56,13 @@ public: void emit(const T& data) override { parent::value_type to_send = data; - xQueueSend(q_->msg_queue_, &to_send, 0); + q_->dispatchEvent(to_send); } BaseType_t emitFromIsr(const T& data) override { parent::value_type to_send = data; - BaseType_t was_awoken = pdFALSE; - - xQueueSendFromISR(q_->msg_queue_, &to_send, &was_awoken); - - return was_awoken; + return q_->dispatchEventFromIsr(to_send); } private: @@ -97,13 +90,12 @@ public: return &signal_; } -protected: - virtual void init() = 0; + void dispatchSignal(const char* data) final + { + dispatchImpl_(data); + } private: - PrimitiveThread thread_; - QueueHandle_t msg_queue_; - struct Visitor_ { using parent = Actor; @@ -121,113 +113,15 @@ private: } }; - void operator()() + void dispatchImpl_(const char* data) { - init(); - - value_type data{}; - - while (true) - { - const BaseType_t got = xQueueReceive(msg_queue_, &data, portMAX_DELAY); - - if (got == pdTRUE) - { - std::visit(Visitor_{this}, data); - } - } - } - - static void threadHandler_(void* d) - { - auto* dd = static_cast*>(d); - (*dd)(); + const value_type* signal_data = reinterpret_cast(data); + std::visit(Visitor_{this}, *signal_data); } Signal signal_; }; -template -class Actor -{ -public: - using value_type = void; - - 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(int))), signal_(*this) - { - assert(msg_queue_); - } - - virtual ~Actor() {} - - Signallable* getSignal() - { - return &signal_; - } - -protected: - virtual void init() = 0; - -private: - PrimitiveThread thread_; - QueueHandle_t msg_queue_; - - void operator()() - { - init(); - - int data; - - while (true) - { - const BaseType_t got = xQueueReceive(msg_queue_, &data, portMAX_DELAY); - - if (got == pdTRUE) - { - auto* crtp = static_cast(this); - crtp->onSignal(); - } - } - } - - friend struct Signal_; - - struct Signal_ : Signallable - { - using parent = Actor; - parent& q; - - explicit Signal_(parent& q) - : q(q) - {} - - void emit() override - { - const int data = 0; - - xQueueSend(q.msg_queue_, &data, 0); - } - - BaseType_t emitFromIsr() override - { - const int data = 0; - - BaseType_t was_awoken = pdFALSE; - xQueueSendFromISR(q.msg_queue_, &data, &was_awoken); - - return was_awoken; - } - }; - - Signal_ signal_; -}; - }// namespace Threads diff --git a/Threads/Inc/threads_actor_thread.hpp b/Threads/Inc/threads_actor_thread.hpp new file mode 100644 index 0000000..4929b66 --- /dev/null +++ b/Threads/Inc/threads_actor_thread.hpp @@ -0,0 +1,50 @@ +/* + * threads_actor_thread.hpp + * + * Created on: Nov 13, 2021 + * Author: erki + */ + +#ifndef SKULLC_THREADS_ACTOR_THREAD_HPP_ +#define SKULLC_THREADS_ACTOR_THREAD_HPP_ + +#include +#include + +#include +#include + +#include + +namespace Threads +{ + +class IActor; + +class ActorThread : public Thread +{ +public: + ActorThread(const std::size_t queue_length, const char* name, const osPriority_t priority, const std::uint32_t stack_size); + + void operator()(); + +private: + void init_(); + void doMessageLoop_(); + + friend class IActor; + std::size_t acceptActor_(IActor* actor); + + std::size_t queue_length_; + std::size_t queue_item_length_ = 0; + + QueueHandle_t queue_ = nullptr; + char* rx_buffer_ = nullptr; + char* tx_buffer_ = nullptr; + std::array actors_; +}; + +}// namespace Threads + + +#endif /* SKULLC_THREADS_ACTOR_THREAD_HPP_ */ diff --git a/Threads/Inc/threads_iactor.hpp b/Threads/Inc/threads_iactor.hpp new file mode 100644 index 0000000..011f448 --- /dev/null +++ b/Threads/Inc/threads_iactor.hpp @@ -0,0 +1,68 @@ +/* + * threads_iactor.hpp + * + * Created on: Nov 14, 2021 + * Author: erki + */ + +#ifndef SKULLC_THREADS_IACTOR_HPP_ +#define SKULLC_THREADS_IACTOR_HPP_ + +#include + +#include + +namespace Threads +{ + +class ActorThread; + +class IActor +{ +public: + IActor(const std::size_t signal_size) + : signal_size_(signal_size) + {} + + virtual ~IActor() {} + + virtual void init() = 0; + virtual void dispatchSignal(const char* data) = 0; + + void moveToThread(ActorThread* thread); + + std::size_t actorIndex() const + { + return actor_index_; + } + + std::size_t signalSize() const + { + return signal_size_; + } + +protected: + template + void dispatchEvent(const T& data) + { + dispatchEventImpl_(&data, sizeof(T)); + } + + template + BaseType_t dispatchEventFromIsr(const T& data) + { + return dispatchEventFromIsrImpl_(&data, sizeof(T)); + } + +private: + ActorThread* parent_thread_ = nullptr; + std::size_t actor_index_ = 0; + std::size_t signal_size_; + + void dispatchEventImpl_(const void* data, const std::size_t data_size); + BaseType_t dispatchEventFromIsrImpl_(const void* data, const std::size_t data_size); +}; + +}// namespace Threads + +#endif /* SKULLC_THREADS_IACTOR_HPP_ */ diff --git a/Threads/Src/threads_actor_thread.cpp b/Threads/Src/threads_actor_thread.cpp new file mode 100644 index 0000000..c68812d --- /dev/null +++ b/Threads/Src/threads_actor_thread.cpp @@ -0,0 +1,110 @@ +/* + * threads_actor_thread.cpp + * + * Created on: Nov 13, 2021 + * Author: erki + */ + + +#include "threads_actor_thread.hpp" + +#include +#include +#include + +#include + +namespace +{ + +struct SignalMessage +{ + std::size_t actor_index; + const char* data; + + static SignalMessage fromData(char* data) + { + SignalMessage message; + std::memcpy(&message.actor_index, data, sizeof(message.actor_index)); + message.data = data + sizeof(message.actor_index); + + return message; + } +}; + +}// namespace + +namespace Threads +{ + +ActorThread::ActorThread(const std::size_t queue_length, const char* name, const osPriority_t priority, const std::uint32_t stack_size) + : Thread(name, priority, stack_size), queue_length_(queue_length), queue_(nullptr) +{ + actors_.fill(nullptr); +} + +void ActorThread::operator()() +{ + init_(); + + osThreadYield(); + + while (true) + { + doMessageLoop_(); + + osThreadYield(); + } +} + +void ActorThread::init_() +{ + for (IActor* actor : actors_) + { + if (actor != nullptr) + { + queue_item_length_ = std::max(queue_item_length_, actor->signalSize()); + + actor->init(); + } + } + + queue_ = xQueueCreate(queue_length_, queue_item_length_ + sizeof(std::size_t)); + assert(queue_ != nullptr); + + rx_buffer_ = new char[queue_item_length_ + sizeof(std::size_t)]; + tx_buffer_ = new char[queue_item_length_ + sizeof(std::size_t)]; +} + +void ActorThread::doMessageLoop_() +{ + const BaseType_t has_data = xQueueReceive(queue_, rx_buffer_, portMAX_DELAY); + + if (has_data == pdTRUE) + { + const SignalMessage message = SignalMessage::fromData(rx_buffer_); + assert(message.actor_index <= actors_.size()); + + IActor* actor = actors_[message.actor_index]; + assert(actor != nullptr); + + actor->dispatchSignal(message.data); + } +} + +std::size_t ActorThread::acceptActor_(IActor* actor) +{ + for (auto it = actors_.begin(); it != actors_.end(); ++it) + { + if (*it == nullptr) + { + *it = actor; + return std::distance(actors_.begin(), it); + } + } + + assert(false); + return -1; +} + +}// namespace Threads diff --git a/Threads/Src/threads_iactor.cpp b/Threads/Src/threads_iactor.cpp new file mode 100644 index 0000000..3131010 --- /dev/null +++ b/Threads/Src/threads_iactor.cpp @@ -0,0 +1,55 @@ +/* + * threads_iactor.cpp + * + * Created on: Nov 14, 2021 + * Author: erki + */ + + +#include "threads_iactor.hpp" + +#include + +#include + +#include "threads_actor_thread.hpp" + +namespace Threads +{ + +void IActor::moveToThread(ActorThread* thread) +{ + actor_index_ = thread->acceptActor_(this); + parent_thread_ = thread; +} + +void IActor::dispatchEventImpl_(const void* data, const std::size_t data_size) +{ + taskENTER_CRITICAL(); + + std::memcpy(parent_thread_->tx_buffer_, &actor_index_, sizeof(std::size_t)); + char* data_dest = parent_thread_->tx_buffer_ + sizeof(std::size_t); + std::memcpy(data_dest, data, data_size); + + xQueueSend(parent_thread_->queue_, parent_thread_->tx_buffer_, 0); + + taskEXIT_CRITICAL(); +} + +BaseType_t IActor::dispatchEventFromIsrImpl_(const void* data, const std::size_t data_size) +{ + const auto isr_data = taskENTER_CRITICAL_FROM_ISR(); + + std::memcpy(parent_thread_->tx_buffer_, &actor_index_, sizeof(std::size_t)); + char* data_dest = parent_thread_->tx_buffer_ + sizeof(std::size_t); + std::memcpy(data_dest, data, data_size); + + BaseType_t task_awoken = pdFALSE; + xQueueSendFromISR(parent_thread_->queue_, parent_thread_->tx_buffer_, &task_awoken); + + taskEXIT_CRITICAL_FROM_ISR(isr_data); + + return task_awoken; +} + +}// namespace Threads diff --git a/Utility/CMakeLists.txt b/Utility/CMakeLists.txt index 34b11ff..1114ce1 100644 --- a/Utility/CMakeLists.txt +++ b/Utility/CMakeLists.txt @@ -1,13 +1,9 @@ cmake_minimum_required(VERSION 3.8 FATAL_ERROR) -#if(WITH_HAL) -# set(additional_sources -# ) -#endif() - add_library(utility STATIC Src/utility_logging.cpp Src/utility_rand.cpp + Src/utility_assert.cpp ${additional_sources} ) @@ -18,5 +14,9 @@ target_include_directories(utility $ $ ) +set_target_properties(utility + PROPERTIES + CXX_STANDARD 17 +) -skullc_install_packages(skullc utility ${version}) +skullc_install_packages(skullc utility ${SKULLC_VERSION}) diff --git a/Utility/Inc/utility_assert.hpp b/Utility/Inc/utility_assert.hpp new file mode 100644 index 0000000..a292dc4 --- /dev/null +++ b/Utility/Inc/utility_assert.hpp @@ -0,0 +1,33 @@ +// +// Created by erki on 29.06.22. +// + +#ifndef SKULLC_UTILITY_ASSERT_HPP_ +#define SKULLC_UTILITY_ASSERT_HPP_ + +namespace Utility::Assert::Detail +{ + +void assertImpl(const char* expression, const char* file, const int line); + +} + +#ifndef NDEBUG +#define SKULLC_ASSERT_DEBUG(e) (!(e) ? Utility::Assert::Detail::assertImpl(#e, __FILE__, __LINE__) : ((void) 0)) +#else +#define SKULLC_ASSERT_DEBUG(e) +#endif + +#define SKULLC_ASSERT_SAFE(e) (!(e) ? Utility::Assert::Detail::assertImpl(#e, __FILE__, __LINE__) : ((void) 0)) + +namespace Utility::Assert +{ + +using assert_cb = void (*)(const char* expression, const char* file, const int line); + +void setHandler(assert_cb callback); +assert_cb getHandler(); + +}// namespace Utility::Assert + +#endif// SKULLC_UTILITY_ASSERT_HPP_ diff --git a/Utility/Inc/utility_enum_helpers.hpp b/Utility/Inc/utility_enum_helpers.hpp new file mode 100644 index 0000000..62d7e7a --- /dev/null +++ b/Utility/Inc/utility_enum_helpers.hpp @@ -0,0 +1,22 @@ +// +// Created by erki on 15.07.22. +// + +#ifndef SKULLC_UTILITY_ENUM_HELPERS_HPP_ +#define SKULLC_UTILITY_ENUM_HELPERS_HPP_ + +#include + +#define SKULLC_ENUM_DECLARE_BITFLAG_OPERATORS(E) \ + inline E operator|(const E& lhs, const E& rhs) \ + { \ + using T = std::underlying_type_t; \ + return static_cast(static_cast(lhs) | static_cast(rhs)); \ + } \ + inline E operator&(const E& lhs, const E& rhs) \ + { \ + using T = std::underlying_type_t; \ + return static_cast(static_cast(lhs) & static_cast(rhs)); \ + } + +#endif//SKULLC_UTILITY_ENUM_HELPERS_HPP_ diff --git a/Utility/Inc/utility_function.hpp b/Utility/Inc/utility_function.hpp index 4d9f200..0d62c67 100644 --- a/Utility/Inc/utility_function.hpp +++ b/Utility/Inc/utility_function.hpp @@ -8,6 +8,8 @@ #ifndef SKULLC_UTILITY_FUNCTION_HPP_ #define SKULLC_UTILITY_FUNCTION_HPP_ +#include + namespace Utility { @@ -19,11 +21,19 @@ class IFunction { public: using result_type = R; + using static_signature = R (*)(Args...); virtual ~IFunction() {} virtual result_type operator()(Args... args) = 0; + + template + static_signature toStaticFunction() + { + static decltype(this) h = this; + return +[](Args... args) { (*h)(args...); }; + } }; template @@ -41,7 +51,7 @@ public: explicit Function(signature callable) : callable_(callable) { - assert(callable_); + SKULLC_ASSERT_DEBUG(callable_); } ~Function() override @@ -73,7 +83,7 @@ public: explicit FunctionOwned(source& src, signature callable) : src_(&src), callable_(callable) { - assert(callable_); + SKULLC_ASSERT_DEBUG(callable_); } ~FunctionOwned() override diff --git a/Utility/Inc/utility_staticpointer.hpp b/Utility/Inc/utility_staticpointer.hpp index b8dba5e..4556faf 100644 --- a/Utility/Inc/utility_staticpointer.hpp +++ b/Utility/Inc/utility_staticpointer.hpp @@ -8,8 +8,11 @@ #ifndef SKULLC_UTILITY_STATICPOINTER_HPP_ #define SKULLC_UTILITY_STATICPOINTER_HPP_ +#include #include +#include + namespace Utility { @@ -57,6 +60,18 @@ struct StaticPointer return initialized_; } + value_type* get() + { + SKULLC_ASSERT_DEBUG(initialized_); + return reinterpret_cast(storage); + } + + const value_type* get() const + { + SKULLC_ASSERT_DEBUG(initialized_); + return reinterpret_cast(storage); + } + private: bool initialized_ = false; }; diff --git a/Utility/Inc/utility_tag.hpp b/Utility/Inc/utility_tag.hpp new file mode 100644 index 0000000..99eb900 --- /dev/null +++ b/Utility/Inc/utility_tag.hpp @@ -0,0 +1,12 @@ +// +// Created by erki on 26.06.22. +// + +#ifndef SKULLC_UTILITY_TAG_HPP_ +#define SKULLC_UTILITY_TAG_HPP_ + +#define SKULLC_CONCAT_IMPL(x, y) x##y +#define SKULLC_CONCAT(x, y) SKULLC_CONCAT_IMPL(x, y) +#define SKULLC_TAG struct SKULLC_CONCAT(SkullCTag_, __COUNTER__) + +#endif// SKULLC_UTILITY_TAG_HPP_ diff --git a/Utility/Src/utility_assert.cpp b/Utility/Src/utility_assert.cpp new file mode 100644 index 0000000..4f6eb6f --- /dev/null +++ b/Utility/Src/utility_assert.cpp @@ -0,0 +1,42 @@ +// +// Created by erki on 29.06.22. +// + +#include "utility_assert.hpp" + +#include + +namespace +{ + +Utility::Assert::assert_cb INSTALLED_HANDLER = nullptr; + +} + +namespace Utility::Assert +{ + +namespace Detail +{ + +void assertImpl(const char* expression, const char* file, const int line) +{ + if (INSTALLED_HANDLER) + INSTALLED_HANDLER(expression, file, line); + else + std::terminate(); +} + +}// namespace Detail + +void setHandler(assert_cb callback) +{ + INSTALLED_HANDLER = callback; +} + +assert_cb getHandler() +{ + return INSTALLED_HANDLER; +} + +}// namespace Utility::Assert