Compare commits
No commits in common. "d65e0b9ad9910fe0c363492e4970b8602318ad58" and "992c55b7852439c356a20f87b1009ff8ec51368d" have entirely different histories.
d65e0b9ad9
...
992c55b785
@ -9,6 +9,7 @@ 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
|
||||
|
||||
@ -1,19 +1,22 @@
|
||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||
|
||||
set(SKULLC_VERSION 0.1.0)
|
||||
set(version 0.1.0)
|
||||
|
||||
project(skullc
|
||||
VERSION ${SKULLC_VERSION}
|
||||
VERSION ${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/)
|
||||
|
||||
option(SKULLC_WITH_TESTS "Enable unit testing." OFF)
|
||||
option(SKULLC_WITH_HAL "Enable the compiling and deployment of the HAL dependent sections." OFF)
|
||||
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)
|
||||
|
||||
include(skullc-install)
|
||||
|
||||
@ -21,7 +24,7 @@ add_subdirectory(Peripherals)
|
||||
add_subdirectory(Utility)
|
||||
add_subdirectory(Messaging)
|
||||
|
||||
if(SKULLC_WITH_TESTS)
|
||||
if(WITH_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(Tests)
|
||||
endif()
|
||||
|
||||
50
Jenkinsfile
vendored
50
Jenkinsfile
vendored
@ -1,50 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,9 +5,9 @@ add_library(messaging INTERFACE)
|
||||
add_library(skullc::messaging ALIAS messaging)
|
||||
|
||||
target_include_directories(messaging
|
||||
INTERFACE
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Inc>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
)
|
||||
|
||||
skullc_install_packages(skullc messaging ${SKULLC_VERSION})
|
||||
skullc_install_packages(skullc messaging ${version})
|
||||
|
||||
@ -11,4 +11,4 @@ target_include_directories(peripherals
|
||||
)
|
||||
|
||||
## INSTALL
|
||||
skullc_install_packages(skullc peripherals ${SKULLC_VERSION})
|
||||
skullc_install_packages(skullc peripherals ${version})
|
||||
|
||||
@ -74,12 +74,11 @@ 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,
|
||||
|
||||
@ -15,6 +15,10 @@
|
||||
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<typename T>
|
||||
constexpr const T& clamp(const T& v, const T& lo, const T& hi)
|
||||
{
|
||||
|
||||
@ -1,16 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||
|
||||
option(SKULLC_TESTS_WITH_SANITIZERS "Enable sanitizers for tests." ON)
|
||||
option(TESTS_WITH_SANITIZERS "Enable sanitizers for tests." ON)
|
||||
|
||||
include(FetchContent)
|
||||
find_package(Catch2 REQUIRED)
|
||||
|
||||
FetchContent_Declare(Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v2.13.8
|
||||
)
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
|
||||
if(SKULLC_TESTS_WITH_SANITIZERS)
|
||||
if(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()
|
||||
@ -24,12 +18,7 @@ add_executable(tests
|
||||
rand.cpp
|
||||
fixedpoint.cpp
|
||||
pixelbuffer.cpp
|
||||
pixelbuffer_effects.cpp
|
||||
function.cpp
|
||||
assert_ndebug.cpp
|
||||
assert.cpp
|
||||
enum_helpers.cpp
|
||||
)
|
||||
pixelbuffer_effects.cpp function.cpp)
|
||||
|
||||
target_link_libraries(tests
|
||||
PUBLIC
|
||||
@ -39,12 +28,6 @@ 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)
|
||||
@ -1,68 +0,0 @@
|
||||
//
|
||||
// Created by erki on 29.06.22.
|
||||
//
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#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);
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
//
|
||||
// Created by erki on 29.06.22.
|
||||
//
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#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);
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
//
|
||||
// Created by erki on 15.07.22.
|
||||
//
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#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);
|
||||
}
|
||||
@ -5,7 +5,6 @@
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <utility_function.hpp>
|
||||
#include <utility_tag.hpp>
|
||||
|
||||
TEST_CASE("Function calls function appropriately.", "[utility],[function]")
|
||||
{
|
||||
@ -39,26 +38,6 @@ 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<void(int, bool)> function(func_to_call);
|
||||
using signature = void (*)(int, bool);
|
||||
|
||||
signature func_pointer = function.toStaticFunction<SKULLC_TAG>();
|
||||
func_pointer(10, true);
|
||||
|
||||
REQUIRE(int_to_set == 10);
|
||||
REQUIRE(bool_to_set == true);
|
||||
}
|
||||
|
||||
TEST_CASE("FunctionOwned calls function appropriately.", "[utility],[function]")
|
||||
{
|
||||
struct S
|
||||
@ -103,29 +82,3 @@ 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<S, void(int, bool)> function(subject, &S::toCall);
|
||||
using signature = void (*)(int, bool);
|
||||
|
||||
signature func_pointer = function.toStaticFunction<SKULLC_TAG>();
|
||||
func_pointer(10, true);
|
||||
|
||||
REQUIRE(subject.int_to_set == 10);
|
||||
REQUIRE(subject.bool_to_set == true);
|
||||
}
|
||||
|
||||
@ -15,15 +15,15 @@
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
#include <threads_actor_thread.hpp>
|
||||
#include <threads_iactor.hpp>
|
||||
#include <threads_signal.hpp>
|
||||
#include "threads_primitivethread.hpp"
|
||||
#include "threads_signal.hpp"
|
||||
#include "threads_timer.hpp"
|
||||
|
||||
namespace Threads
|
||||
{
|
||||
|
||||
template<typename CRTP, typename... Ts>
|
||||
class Actor : public IActor
|
||||
class Actor
|
||||
{
|
||||
public:
|
||||
using value_type = std::variant<Ts...>;
|
||||
@ -31,11 +31,14 @@ public:
|
||||
static_assert(std::is_default_constructible_v<value_type>, "Ts must be default constructible.");
|
||||
static_assert(std::is_trivially_copyable_v<value_type>, "Ts must be trivially copyable.");
|
||||
|
||||
Actor() : IActor(sizeof(value_type)),
|
||||
signal_(this)
|
||||
{}
|
||||
Actor(const std::uint32_t queue_size, const char* name, const osPriority_t priority, const std::uint32_t stack_size)
|
||||
: thread_(&Actor<CRTP, Ts...>::threadHandler_, this, name, priority, stack_size),
|
||||
msg_queue_(xQueueCreate(queue_size, sizeof(value_type))), signal_(this)
|
||||
{
|
||||
assert(msg_queue_);
|
||||
}
|
||||
|
||||
~Actor() override {}
|
||||
virtual ~Actor() {}
|
||||
|
||||
template<typename T>
|
||||
struct Signal : Signallable<T>
|
||||
@ -56,13 +59,17 @@ public:
|
||||
void emit(const T& data) override
|
||||
{
|
||||
parent::value_type to_send = data;
|
||||
q_->dispatchEvent(to_send);
|
||||
xQueueSend(q_->msg_queue_, &to_send, 0);
|
||||
}
|
||||
|
||||
BaseType_t emitFromIsr(const T& data) override
|
||||
{
|
||||
parent::value_type to_send = data;
|
||||
return q_->dispatchEventFromIsr(to_send);
|
||||
BaseType_t was_awoken = pdFALSE;
|
||||
|
||||
xQueueSendFromISR(q_->msg_queue_, &to_send, &was_awoken);
|
||||
|
||||
return was_awoken;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -90,12 +97,13 @@ public:
|
||||
return &signal_;
|
||||
}
|
||||
|
||||
void dispatchSignal(const char* data) final
|
||||
{
|
||||
dispatchImpl_(data);
|
||||
}
|
||||
protected:
|
||||
virtual void init() = 0;
|
||||
|
||||
private:
|
||||
PrimitiveThread thread_;
|
||||
QueueHandle_t msg_queue_;
|
||||
|
||||
struct Visitor_
|
||||
{
|
||||
using parent = Actor<CRTP, Ts...>;
|
||||
@ -113,15 +121,113 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
void dispatchImpl_(const char* data)
|
||||
void operator()()
|
||||
{
|
||||
const value_type* signal_data = reinterpret_cast<const value_type*>(data);
|
||||
std::visit(Visitor_{this}, *signal_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<Actor<CRTP, Ts...>*>(d);
|
||||
(*dd)();
|
||||
}
|
||||
|
||||
Signal<value_type> signal_;
|
||||
};
|
||||
|
||||
template<typename CRTP>
|
||||
class Actor<CRTP, void>
|
||||
{
|
||||
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<Actor<CRTP, value_type>*>(d);
|
||||
(*dd)();
|
||||
},
|
||||
this, name, priority, stack_size),
|
||||
msg_queue_(xQueueCreate(queue_size, sizeof(int))), signal_(*this)
|
||||
{
|
||||
assert(msg_queue_);
|
||||
}
|
||||
|
||||
virtual ~Actor() {}
|
||||
|
||||
Signallable<value_type>* 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<CRTP*>(this);
|
||||
crtp->onSignal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
friend struct Signal_;
|
||||
|
||||
struct Signal_ : Signallable<value_type>
|
||||
{
|
||||
using parent = Actor<CRTP, void>;
|
||||
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
|
||||
|
||||
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* threads_actor_thread.hpp
|
||||
*
|
||||
* Created on: Nov 13, 2021
|
||||
* Author: erki
|
||||
*/
|
||||
|
||||
#ifndef SKULLC_THREADS_ACTOR_THREAD_HPP_
|
||||
#define SKULLC_THREADS_ACTOR_THREAD_HPP_
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include <freertos_os2.h>
|
||||
#include <queue.h>
|
||||
|
||||
#include <threads_thread.hpp>
|
||||
|
||||
namespace Threads
|
||||
{
|
||||
|
||||
class IActor;
|
||||
|
||||
class ActorThread : public Thread<ActorThread>
|
||||
{
|
||||
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<IActor*, 32> actors_;
|
||||
};
|
||||
|
||||
}// namespace Threads
|
||||
|
||||
|
||||
#endif /* SKULLC_THREADS_ACTOR_THREAD_HPP_ */
|
||||
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* threads_iactor.hpp
|
||||
*
|
||||
* Created on: Nov 14, 2021
|
||||
* Author: erki
|
||||
*/
|
||||
|
||||
#ifndef SKULLC_THREADS_IACTOR_HPP_
|
||||
#define SKULLC_THREADS_IACTOR_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <freertos_os2.h>
|
||||
|
||||
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<typename T>
|
||||
void dispatchEvent(const T& data)
|
||||
{
|
||||
dispatchEventImpl_(&data, sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
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_ */
|
||||
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* threads_actor_thread.cpp
|
||||
*
|
||||
* Created on: Nov 13, 2021
|
||||
* Author: erki
|
||||
*/
|
||||
|
||||
|
||||
#include "threads_actor_thread.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include <threads_iactor.hpp>
|
||||
|
||||
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<ActorThread>(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
|
||||
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* threads_iactor.cpp
|
||||
*
|
||||
* Created on: Nov 14, 2021
|
||||
* Author: erki
|
||||
*/
|
||||
|
||||
|
||||
#include "threads_iactor.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <queue.h>
|
||||
|
||||
#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
|
||||
@ -1,9 +1,13 @@
|
||||
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}
|
||||
)
|
||||
|
||||
@ -14,9 +18,5 @@ target_include_directories(utility
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Inc>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
set_target_properties(utility
|
||||
PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
)
|
||||
|
||||
skullc_install_packages(skullc utility ${SKULLC_VERSION})
|
||||
skullc_install_packages(skullc utility ${version})
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
//
|
||||
// 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_
|
||||
@ -1,22 +0,0 @@
|
||||
//
|
||||
// Created by erki on 15.07.22.
|
||||
//
|
||||
|
||||
#ifndef SKULLC_UTILITY_ENUM_HELPERS_HPP_
|
||||
#define SKULLC_UTILITY_ENUM_HELPERS_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#define SKULLC_ENUM_DECLARE_BITFLAG_OPERATORS(E) \
|
||||
inline E operator|(const E& lhs, const E& rhs) \
|
||||
{ \
|
||||
using T = std::underlying_type_t<E>; \
|
||||
return static_cast<E>(static_cast<T>(lhs) | static_cast<T>(rhs)); \
|
||||
} \
|
||||
inline E operator&(const E& lhs, const E& rhs) \
|
||||
{ \
|
||||
using T = std::underlying_type_t<E>; \
|
||||
return static_cast<E>(static_cast<T>(lhs) & static_cast<T>(rhs)); \
|
||||
}
|
||||
|
||||
#endif//SKULLC_UTILITY_ENUM_HELPERS_HPP_
|
||||
@ -8,8 +8,6 @@
|
||||
#ifndef SKULLC_UTILITY_FUNCTION_HPP_
|
||||
#define SKULLC_UTILITY_FUNCTION_HPP_
|
||||
|
||||
#include <utility_assert.hpp>
|
||||
|
||||
namespace Utility
|
||||
{
|
||||
|
||||
@ -21,19 +19,11 @@ class IFunction<R(Args...)>
|
||||
{
|
||||
public:
|
||||
using result_type = R;
|
||||
using static_signature = R (*)(Args...);
|
||||
|
||||
virtual ~IFunction()
|
||||
{}
|
||||
|
||||
virtual result_type operator()(Args... args) = 0;
|
||||
|
||||
template<typename Tag>
|
||||
static_signature toStaticFunction()
|
||||
{
|
||||
static decltype(this) h = this;
|
||||
return +[](Args... args) { (*h)(args...); };
|
||||
}
|
||||
};
|
||||
|
||||
template<class>
|
||||
@ -51,7 +41,7 @@ public:
|
||||
explicit Function(signature callable)
|
||||
: callable_(callable)
|
||||
{
|
||||
SKULLC_ASSERT_DEBUG(callable_);
|
||||
assert(callable_);
|
||||
}
|
||||
|
||||
~Function() override
|
||||
@ -83,7 +73,7 @@ public:
|
||||
explicit FunctionOwned(source& src, signature callable)
|
||||
: src_(&src), callable_(callable)
|
||||
{
|
||||
SKULLC_ASSERT_DEBUG(callable_);
|
||||
assert(callable_);
|
||||
}
|
||||
|
||||
~FunctionOwned() override
|
||||
|
||||
@ -8,11 +8,8 @@
|
||||
#ifndef SKULLC_UTILITY_STATICPOINTER_HPP_
|
||||
#define SKULLC_UTILITY_STATICPOINTER_HPP_
|
||||
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
#include <utility_assert.hpp>
|
||||
|
||||
namespace Utility
|
||||
{
|
||||
|
||||
@ -60,18 +57,6 @@ struct StaticPointer
|
||||
return initialized_;
|
||||
}
|
||||
|
||||
value_type* get()
|
||||
{
|
||||
SKULLC_ASSERT_DEBUG(initialized_);
|
||||
return reinterpret_cast<value_type*>(storage);
|
||||
}
|
||||
|
||||
const value_type* get() const
|
||||
{
|
||||
SKULLC_ASSERT_DEBUG(initialized_);
|
||||
return reinterpret_cast<const value_type*>(storage);
|
||||
}
|
||||
|
||||
private:
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
//
|
||||
// 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_
|
||||
@ -1,42 +0,0 @@
|
||||
//
|
||||
// Created by erki on 29.06.22.
|
||||
//
|
||||
|
||||
#include "utility_assert.hpp"
|
||||
|
||||
#include <exception>
|
||||
|
||||
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
|
||||
Loading…
x
Reference in New Issue
Block a user