diff --git a/CMLibStorage.cmake b/CMLibStorage.cmake index 7e7142d..36796ba 100644 --- a/CMLibStorage.cmake +++ b/CMLibStorage.cmake @@ -1,3 +1,7 @@ +FIND_PACKAGE(CMLIB REQUIRED COMPONENTS CMCONF) + +CMCONF_INIT_SYSTEM(FLEET_PROTOCOL) + SET(STORAGE_LIST DEP) SET(STORAGE_LIST_DEP "https://github.com/bacpack-system/package-tracker.git") diff --git a/CMakeLists.txt b/CMakeLists.txt index b070bc2..cdf6d0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,9 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.25 FATAL_ERROR) PROJECT(fleet-protocol C CXX) SET(CMAKE_POSITION_INDEPENDENT_CODE ON) -SET(CMAKE_CXX_STANDARD 20) +SET(CMAKE_CXX_STANDARD 23) -SET(FLEET_PROTOCOL_CXX_HELPERS_VERSION 1.1.2) +SET(FLEET_PROTOCOL_CXX_HELPERS_VERSION 1.2.0) SET(FLEET_PROTOCOL_INTERFACE_VERSION 2.0.0) FIND_PACKAGE(CMLIB @@ -40,6 +40,8 @@ IF (BRINGAUTO_PACKAGE) ENDIF () FIND_PACKAGE(fleet-protocol-interface ${FLEET_PROTOCOL_INTERFACE_VERSION} REQUIRED) +FIND_PACKAGE(aeron 1.48.6 REQUIRED) +FIND_PACKAGE(async-function-execution-shared 1.0.0 REQUIRED) FILE(GLOB_RECURSE source_files ${CMAKE_CURRENT_LIST_DIR}/source/*) @@ -47,13 +49,14 @@ CMDEF_ADD_LIBRARY( LIBRARY_GROUP ${MODULE_MAINTAINER_TARGET_NAME} TYPE STATIC SOURCES ${source_files} - INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/include/" + INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/include" INSTALL_INCLUDE_DIRECTORIES "include/" VERSION ${FLEET_PROTOCOL_CXX_HELPERS_VERSION} ) TARGET_LINK_LIBRARIES(${MODULE_MAINTAINER_TARGET_NAME}-static PUBLIC ${COMMON_HEADERS_TARGET} + async-function-execution-shared::async-function-execution-shared ) ADD_LIBRARY(${MODULE_MAINTAINER_ALIAS_NAME} ALIAS "${MODULE_MAINTAINER_TARGET_NAME}-static") @@ -77,5 +80,5 @@ ENDIF () IF (BRINGAUTO_TESTS) ENABLE_TESTING() - ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/test/) + INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt) ENDIF (BRINGAUTO_TESTS) diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index 6ec21a4..e24b0ff 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -1,5 +1,7 @@ SET(CMAKE_FIND_USE_CMAKE_SYSTEM_PATH FALSE) BA_PACKAGE_LIBRARY(fleet-protocol-interface v${FLEET_PROTOCOL_INTERFACE_VERSION} NO_DEBUG ON) +BA_PACKAGE_LIBRARY(aeron v1.48.6) +BA_PACKAGE_LIBRARY(async-function-execution v1.0.0) IF (BRINGAUTO_TESTS) BA_PACKAGE_LIBRARY(gtest v1.12.1) diff --git a/include/bringauto/fleet_protocol/cxx/AsyncModuleFunctionDefinitions.hpp b/include/bringauto/fleet_protocol/cxx/AsyncModuleFunctionDefinitions.hpp new file mode 100644 index 0000000..386732b --- /dev/null +++ b/include/bringauto/fleet_protocol/cxx/AsyncModuleFunctionDefinitions.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include +#include + +#include + + +namespace bringauto::fleet_protocol::cxx { + +inline static const async_function_execution::FunctionDefinition getModuleNumberAsync { + async_function_execution::FunctionId { 0 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments {} +}; + +inline static const async_function_execution::FunctionDefinition isDeviceTypeSupportedAsync { + async_function_execution::FunctionId { 1 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition sendStatusConditionAsync { + async_function_execution::FunctionId { 2 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition generateCommandAsync { + async_function_execution::FunctionId { 3 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition aggregateStatusAsync { + async_function_execution::FunctionId { 4 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition aggregateErrorAsync { + async_function_execution::FunctionId { 5 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition generateFirstCommandAsync { + async_function_execution::FunctionId { 6 }, + async_function_execution::Return { ConvertibleBufferReturn {} }, + async_function_execution::Arguments { uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition statusDataValidAsync { + async_function_execution::FunctionId { 7 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } +}; + +inline static const async_function_execution::FunctionDefinition commandDataValidAsync { + async_function_execution::FunctionId { 8 }, + async_function_execution::Return { int {} }, + async_function_execution::Arguments { ConvertibleBuffer {}, uint32_t {} } +}; + +/** + * @brief Type alias for an AsyncFunctionExecutor specialized with module-related functions. + */ +using ModuleFunctionExecutor = async_function_execution::AsyncFunctionExecutor< + decltype(getModuleNumberAsync), + decltype(isDeviceTypeSupportedAsync), + decltype(sendStatusConditionAsync), + decltype(generateCommandAsync), + decltype(aggregateStatusAsync), + decltype(aggregateErrorAsync), + decltype(generateFirstCommandAsync), + decltype(statusDataValidAsync), + decltype(commandDataValidAsync) +>; + +/** + * @brief FunctionList containing all module-related function definitions. + */ +inline static const async_function_execution::FunctionList< + decltype(getModuleNumberAsync), + decltype(isDeviceTypeSupportedAsync), + decltype(sendStatusConditionAsync), + decltype(generateCommandAsync), + decltype(aggregateStatusAsync), + decltype(aggregateErrorAsync), + decltype(generateFirstCommandAsync), + decltype(statusDataValidAsync), + decltype(commandDataValidAsync) + > moduleFunctionList { + getModuleNumberAsync, + isDeviceTypeSupportedAsync, + sendStatusConditionAsync, + generateCommandAsync, + aggregateStatusAsync, + aggregateErrorAsync, + generateFirstCommandAsync, + statusDataValidAsync, + commandDataValidAsync + }; + +} diff --git a/include/bringauto/fleet_protocol/cxx/ConvertibleBuffer.hpp b/include/bringauto/fleet_protocol/cxx/ConvertibleBuffer.hpp new file mode 100644 index 0000000..f6e8733 --- /dev/null +++ b/include/bringauto/fleet_protocol/cxx/ConvertibleBuffer.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include +#include + + + +namespace bringauto::fleet_protocol::cxx { + +/** + * @brief ConvertibleBuffer is a helper class to convert a fleet_protocol 'buffer' struct + * to/from a byte span for serialization/deserialization. + */ +struct ConvertibleBuffer final { + struct ::buffer buffer {}; + ConvertibleBuffer() = default; + ConvertibleBuffer(struct ::buffer buff) : buffer(buff) {} + + std::span serialize() const { + return std::span {reinterpret_cast(buffer.data), buffer.size_in_bytes}; + } + void deserialize(std::span bytes) { + auto size = bytes.size(); + buffer.data = new uint8_t[size]; + buffer.size_in_bytes = size; + std::memcpy(buffer.data, bytes.data(), size); + } +}; + +} diff --git a/include/bringauto/fleet_protocol/cxx/ConvertibleBufferReturn.hpp b/include/bringauto/fleet_protocol/cxx/ConvertibleBufferReturn.hpp new file mode 100644 index 0000000..61d31ad --- /dev/null +++ b/include/bringauto/fleet_protocol/cxx/ConvertibleBufferReturn.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include +#include +#include + + + +namespace bringauto::fleet_protocol::cxx { + +/** + * @brief ConvertibleBufferReturn is a helper class to convert a fleet_protocol 'buffer' struct + * and a return code to/from a byte span for serialization/deserialization. + * The first 4 bytes represent the return code (int), followed by the buffer data. + */ +struct ConvertibleBufferReturn final { + int returnCode {}; + struct ::buffer buffer {}; + ConvertibleBufferReturn() = default; + ConvertibleBufferReturn(int code, struct ::buffer buff) : returnCode(code), buffer(buff) {} + + std::span serialize() const { + size_t total_size = sizeof(int) + buffer.size_in_bytes; + uint8_t* data = new uint8_t[total_size]; + std::memcpy(data, &returnCode, sizeof(int)); + std::memcpy(data + sizeof(int), buffer.data, buffer.size_in_bytes); + return {data, total_size}; + } + void deserialize(std::span bytes) { + auto size = bytes.size(); + if (size < sizeof(int)) return; + std::memcpy(&returnCode, bytes.data(), sizeof(int)); + size -= sizeof(int); + buffer.data = new uint8_t[size]; + buffer.size_in_bytes = size; + std::memcpy(buffer.data, bytes.data() + sizeof(int), size); + } +}; + +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 25d4e5a..34a4330 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,7 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.25 FATAL_ERROR) PROJECT(fleet-protocol C CXX) -SET(CMAKE_CXX_STANDARD 20) +SET(CMAKE_CXX_STANDARD 23) ADD_SUBDIRECTORY(${CMAKE_CURRENT_LIST_DIR}/lib/memory_management/) diff --git a/test/lib/memory_management/CMakeLists.txt b/test/lib/memory_management/CMakeLists.txt index b43da65..2479a8f 100644 --- a/test/lib/memory_management/CMakeLists.txt +++ b/test/lib/memory_management/CMakeLists.txt @@ -1,7 +1,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.25 FATAL_ERROR) PROJECT(fleet-protocol C CXX) -SET(CMAKE_CXX_STANDARD 20) +SET(CMAKE_CXX_STANDARD 23) FIND_PACKAGE(fleet-protocol-interface 2.0.0 REQUIRED) diff --git a/test/source/AsyncModuleFunctionDefinitionsTest.cpp b/test/source/AsyncModuleFunctionDefinitionsTest.cpp new file mode 100644 index 0000000..6d55bc8 --- /dev/null +++ b/test/source/AsyncModuleFunctionDefinitionsTest.cpp @@ -0,0 +1,18 @@ +#include + +#include + +using namespace bringauto::fleet_protocol::cxx; + + +TEST(AsyncModuleFunctionDefinitions_tests, FunctionDefinitionsExist) { + EXPECT_EQ(getModuleNumberAsync.id.value, 0); + EXPECT_EQ(isDeviceTypeSupportedAsync.id.value, 1); + EXPECT_EQ(sendStatusConditionAsync.id.value, 2); + EXPECT_EQ(generateCommandAsync.id.value, 3); + EXPECT_EQ(aggregateStatusAsync.id.value, 4); + EXPECT_EQ(aggregateErrorAsync.id.value, 5); + EXPECT_EQ(generateFirstCommandAsync.id.value, 6); + EXPECT_EQ(statusDataValidAsync.id.value, 7); + EXPECT_EQ(commandDataValidAsync.id.value, 8); +}