diff --git a/Buildscripts/module.cmake b/Buildscripts/module.cmake new file mode 100644 index 00000000..276ea1bd --- /dev/null +++ b/Buildscripts/module.cmake @@ -0,0 +1,29 @@ +if (COMMAND tactility_add_module) + return() +endif() + +macro(tactility_add_module NAME) + set(options) + set(oneValueArgs) + set(multiValueArgs SRCS INCLUDE_DIRS PRIV_INCLUDE_DIRS REQUIRES PRIV_REQUIRES) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (DEFINED ENV{ESP_IDF_VERSION}) + idf_component_register( + SRCS ${ARG_SRCS} + INCLUDE_DIRS ${ARG_INCLUDE_DIRS} + PRIV_INCLUDE_DIRS ${ARG_PRIV_INCLUDE_DIRS} + REQUIRES ${ARG_REQUIRES} + PRIV_REQUIRES ${ARG_PRIV_REQUIRES} + ) + else() + add_library(${NAME} OBJECT) + target_sources(${NAME} PRIVATE ${ARG_SRCS}) + target_include_directories(${NAME} + PRIVATE ${ARG_PRIV_INCLUDE_DIRS} + PUBLIC ${ARG_INCLUDE_DIRS} + ) + target_link_libraries(${NAME} PUBLIC ${ARG_REQUIRES}) + target_link_libraries(${NAME} PRIVATE ${ARG_PRIV_REQUIRES}) + endif() +endmacro() diff --git a/CMakeLists.txt b/CMakeLists.txt index 13546940..8b2e3ba4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,16 +12,14 @@ set(Cyan "${Esc}[36m") file(READ version.txt TACTILITY_VERSION) add_compile_definitions(TT_VERSION="${TACTILITY_VERSION}") +# tactility_add_module() macro +include("Buildscripts/module.cmake") + # Determine device identifier and project location -if (DEFINED ENV{ESP_IDF_VERSION}) - include("Buildscripts/device.cmake") - init_tactility_globals("sdkconfig") - get_property(TACTILITY_DEVICE_PROJECT GLOBAL PROPERTY TACTILITY_DEVICE_PROJECT) - get_property(TACTILITY_DEVICE_ID GLOBAL PROPERTY TACTILITY_DEVICE_ID) -else () - set(TACTILITY_DEVICE_PROJECT "Devices/simulator") - set(TACTILITY_DEVICE_ID "simulator") -endif () +include("Buildscripts/device.cmake") +init_tactility_globals("sdkconfig") +get_property(TACTILITY_DEVICE_PROJECT GLOBAL PROPERTY TACTILITY_DEVICE_PROJECT) +get_property(TACTILITY_DEVICE_ID GLOBAL PROPERTY TACTILITY_DEVICE_ID) if (DEFINED ENV{ESP_IDF_VERSION}) message("Using ESP-IDF ${Cyan}v$ENV{ESP_IDF_VERSION}${ColorReset}") diff --git a/Modules/hal-device-module/CMakeLists.txt b/Modules/hal-device-module/CMakeLists.txt index 0ccdb119..63ac40be 100644 --- a/Modules/hal-device-module/CMakeLists.txt +++ b/Modules/hal-device-module/CMakeLists.txt @@ -1,41 +1,21 @@ cmake_minimum_required(VERSION 3.20) +include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake") + file(GLOB_RECURSE SOURCE_FILES "Source/*.c*") -if (DEFINED ENV{ESP_IDF_VERSION}) +list(APPEND REQUIRES_LIST + TactilityKernel + TactilityCore + TactilityFreeRtos +) - list(APPEND REQUIRES_LIST - TactilityKernel - TactilityCore - TactilityFreeRtos - ) - - idf_component_register( - SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Include/" - REQUIRES ${REQUIRES_LIST} - ) - - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(${COMPONENT_LIB} PUBLIC -Wno-unused-variable) - endif () - -else () - - add_library(hal-device-module OBJECT) - - target_sources(hal-device-module PRIVATE ${SOURCE_FILES}) - - target_include_directories(hal-device-module - PUBLIC Include/ - ) - - target_link_libraries(hal-device-module PUBLIC - TactilityFreeRtos - TactilityCore - TactilityKernel - freertos_kernel - ) - +if (NOT DEFINED ENV{ESP_IDF_VERSION}) + list(APPEND REQUIRES_LIST freertos_kernel) endif () +tactility_add_module(hal-device-module + SRCS ${SOURCE_FILES} + INCLUDE_DIRS Include/ + REQUIRES ${REQUIRES_LIST} +) diff --git a/Modules/hal-device-module/Source/drivers/hal_device.cpp b/Modules/hal-device-module/Source/drivers/hal_device.cpp index d20e6256..ff717486 100644 --- a/Modules/hal-device-module/Source/drivers/hal_device.cpp +++ b/Modules/hal-device-module/Source/drivers/hal_device.cpp @@ -8,7 +8,7 @@ #include #include -#define TAG LOG_TAG(HalDevice) +#define TAG "HalDevice" struct HalDevicePrivate { std::shared_ptr halDevice; diff --git a/Modules/lvgl-module/CMakeLists.txt b/Modules/lvgl-module/CMakeLists.txt index 2f299fe6..d259d127 100644 --- a/Modules/lvgl-module/CMakeLists.txt +++ b/Modules/lvgl-module/CMakeLists.txt @@ -1,30 +1,22 @@ cmake_minimum_required(VERSION 3.20) -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +file(GLOB_RECURSE SOURCE_FILES "Source/*.c*") + +list(APPEND REQUIRES_LIST + TactilityKernel + lvgl +) if (DEFINED ENV{ESP_IDF_VERSION}) - - idf_component_register( - SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Include/" - REQUIRES TactilityKernel lvgl esp_lvgl_port - ) - + list(APPEND REQUIRES_LIST esp_lvgl_port) else () - - add_library(lvgl-module OBJECT) - - target_sources(lvgl-module PRIVATE ${SOURCE_FILES}) - - target_include_directories(lvgl-module - PUBLIC Include/ - ) - - target_link_libraries(lvgl-module PUBLIC - TactilityKernel - freertos_kernel - lvgl - ) - + list(APPEND REQUIRES_LIST freertos_kernel) endif () +include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake") + +tactility_add_module(lvgl-module + SRCS ${SOURCE_FILES} + INCLUDE_DIRS Include/ + REQUIRES ${REQUIRES_LIST} +) diff --git a/Platforms/PlatformEsp32/CMakeLists.txt b/Platforms/PlatformEsp32/CMakeLists.txt index d8114435..b57f6271 100644 --- a/Platforms/PlatformEsp32/CMakeLists.txt +++ b/Platforms/PlatformEsp32/CMakeLists.txt @@ -2,19 +2,8 @@ cmake_minimum_required(VERSION 3.20) file(GLOB_RECURSE SOURCES "Source/*.c**") -if (DEFINED ENV{ESP_IDF_VERSION}) - - idf_component_register( - SRCS ${SOURCES} - INCLUDE_DIRS "Include/" - REQUIRES TactilityKernel driver - ) - -else () - - add_library(PlatformEsp32 OBJECT) - target_sources(PlatformEsp32 PRIVATE ${SOURCES}) - target_include_directories(PlatformEsp32 PUBLIC Include/) - target_link_libraries(PlatformEsp32 PUBLIC TactilityKernel) - -endif () \ No newline at end of file +idf_component_register( + SRCS ${SOURCES} + INCLUDE_DIRS "Include/" + REQUIRES TactilityKernel driver +) \ No newline at end of file diff --git a/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp b/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp index a71d0631..bfe37836 100644 --- a/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp +++ b/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp @@ -9,7 +9,7 @@ #include #include -#define TAG LOG_TAG(esp32_gpio) +#define TAG "esp32_gpio" #define GET_CONFIG(device) ((struct Esp32GpioConfig*)device->config) diff --git a/Platforms/PlatformEsp32/Source/drivers/esp32_i2c.cpp b/Platforms/PlatformEsp32/Source/drivers/esp32_i2c.cpp index 969b382e..5f444739 100644 --- a/Platforms/PlatformEsp32/Source/drivers/esp32_i2c.cpp +++ b/Platforms/PlatformEsp32/Source/drivers/esp32_i2c.cpp @@ -9,7 +9,7 @@ #include #include -#define TAG LOG_TAG(esp32_i2c) +#define TAG "esp32_i2c" #define ACK_CHECK_EN 1 struct InternalData { diff --git a/Platforms/PlatformPosix/CMakeLists.txt b/Platforms/PlatformPosix/CMakeLists.txt index 0f794775..48b7127b 100644 --- a/Platforms/PlatformPosix/CMakeLists.txt +++ b/Platforms/PlatformPosix/CMakeLists.txt @@ -2,19 +2,7 @@ cmake_minimum_required(VERSION 3.20) file(GLOB_RECURSE SOURCES "Source/*.c**") -if (DEFINED ENV{ESP_IDF_VERSION}) - - idf_component_register( - SRCS ${SOURCES} -# INCLUDE_DIRS "Include/" - REQUIRES TactilityKernel driver - ) - -else () - - add_library(PlatformPosix OBJECT) - target_sources(PlatformPosix PRIVATE ${SOURCES}) -# target_include_directories(PlatformPosix PUBLIC Include/) - target_link_libraries(PlatformPosix PUBLIC TactilityKernel) - -endif () \ No newline at end of file +add_library(PlatformPosix OBJECT) +target_sources(PlatformPosix PRIVATE ${SOURCES}) +#target_include_directories(PlatformPosix PUBLIC Include/) +target_link_libraries(PlatformPosix PUBLIC TactilityKernel) diff --git a/Platforms/PlatformPosix/Source/freertos.c b/Platforms/PlatformPosix/Source/freertos.c index b99b1c7b..e4a149ed 100644 --- a/Platforms/PlatformPosix/Source/freertos.c +++ b/Platforms/PlatformPosix/Source/freertos.c @@ -5,7 +5,7 @@ #include #include -#define TAG LOG_TAG(freertos) +#define TAG "freertos" /** * Assert implementation as defined in the FreeRTOSConfig.h diff --git a/Tactility/CMakeLists.txt b/Tactility/CMakeLists.txt index 647eae2e..1c66150c 100644 --- a/Tactility/CMakeLists.txt +++ b/Tactility/CMakeLists.txt @@ -1,26 +1,32 @@ cmake_minimum_required(VERSION 3.20) +include("${CMAKE_CURRENT_LIST_DIR}/../Buildscripts/module.cmake") + +file(GLOB_RECURSE SOURCE_FILES Source/*.c*) + +list(APPEND REQUIRES_LIST + TactilityKernel + TactilityCore + TactilityFreeRtos + hal-device-module + lvgl-module + lv_screenshot + minitar + minmea +) + if (DEFINED ENV{ESP_IDF_VERSION}) - file(GLOB_RECURSE SOURCE_FILES Source/*.c*) list(APPEND REQUIRES_LIST - TactilityKernel PlatformEsp32 - TactilityCore - TactilityFreeRtos - hal-device-module - lvgl-module driver elf_loader - lv_screenshot QRCode esp_http_server esp_http_client esp-tls esp_wifi - json - minitar - minmea + json # Effectively cJSON nvs_flash spiffs vfs @@ -33,13 +39,25 @@ if (DEFINED ENV{ESP_IDF_VERSION}) list(APPEND REQUIRES_LIST esp_tinyusb) endif () - idf_component_register( - SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Include/" - PRIV_INCLUDE_DIRS "Private/" - REQUIRES ${REQUIRES_LIST} +else () + + list(APPEND REQUIRES_LIST + PlatformPosix + freertos_kernel + cJSON + lvgl ) +endif () + +tactility_add_module(Tactility + SRCS ${SOURCE_FILES} + INCLUDE_DIRS Include/ + PRIV_INCLUDE_DIRS Private/ + REQUIRES ${REQUIRES_LIST} +) + +if (DEFINED ENV{ESP_IDF_VERSION}) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(${COMPONENT_LIB} PUBLIC -Wno-unused-variable) endif () @@ -50,31 +68,6 @@ if (DEFINED ENV{ESP_IDF_VERSION}) # Read-write fatfs_create_spiflash_image(data "${CMAKE_CURRENT_SOURCE_DIR}/../Data/data" FLASH_IN_PROJECT PRESERVE_TIME) endif () -else() - file(GLOB_RECURSE SOURCES "Source/*.c*") - add_library(Tactility OBJECT) - - target_sources(Tactility PRIVATE ${SOURCES}) - - target_include_directories(Tactility - PRIVATE Private/ - PUBLIC Include/ - ) - - target_link_libraries(Tactility PUBLIC - cJSON - TactilityFreeRtos - TactilityCore - TactilityKernel - PlatformPosix - hal-device-module - lvgl-module - freertos_kernel - lvgl - lv_screenshot - minmea - minitar - ) -endif() +endif () diff --git a/Tactility/Include/Tactility/Tactility.h b/Tactility/Include/Tactility/Tactility.h index f48f48c3..4e2bc337 100644 --- a/Tactility/Include/Tactility/Tactility.h +++ b/Tactility/Include/Tactility/Tactility.h @@ -38,8 +38,6 @@ const Configuration* getConfiguration(); */ Dispatcher& getMainDispatcher(); -ModuleParent& getModuleParent(); - namespace hal { /** While technically this configuration is nullable, it's never null after initHeadless() is called. */ diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index 27cf9f77..e748d68b 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -41,15 +41,6 @@ static auto LOGGER = Logger("Tactility"); static const Configuration* config_instance = nullptr; static Dispatcher mainDispatcher; -static struct ModuleParent tactility_module_parent { - "tactility", - nullptr -}; - -ModuleParent& getModuleParent() { - return tactility_module_parent; -} - // region Default services namespace service { // Primary @@ -342,10 +333,9 @@ void run(const Configuration& config, Module* platformModule, Module* deviceModu return; } - // Module parent - check(module_parent_construct(&tactility_module_parent) == ERROR_NONE); // hal-device-module - check(module_set_parent(&hal_device_module, &tactility_module_parent) == ERROR_NONE); + check(module_construct(&hal_device_module) == ERROR_NONE); + check(module_add(&hal_device_module) == ERROR_NONE); check(module_start(&hal_device_module) == ERROR_NONE); const hal::Configuration& hardware = *config.hardware; @@ -375,7 +365,8 @@ void run(const Configuration& config, Module* platformModule, Module* deviceModu .task_affinity = getCpuAffinityConfiguration().graphics #endif }); - check(module_set_parent(&lvgl_module, &tactility_module_parent) == ERROR_NONE); + check(module_construct(&lvgl_module) == ERROR_NONE); + check(module_add(&lvgl_module) == ERROR_NONE); lvgl::start(); registerAndStartSecondaryServices(); diff --git a/TactilityC/CMakeLists.txt b/TactilityC/CMakeLists.txt index d34e383e..468bd52d 100644 --- a/TactilityC/CMakeLists.txt +++ b/TactilityC/CMakeLists.txt @@ -1,32 +1,27 @@ cmake_minimum_required(VERSION 3.20) +include("${CMAKE_CURRENT_LIST_DIR}/../Buildscripts/module.cmake") + +list(APPEND REQUIRES_LIST + lvgl +) + +list(APPEND PRIV_REQUIRES_LIST + Tactility + TactilityCore + TactilityKernel +) + if (DEFINED ENV{ESP_IDF_VERSION}) - file(GLOB_RECURSE SOURCE_FILES Source/*.c*) + list(APPEND PRIV_REQUIRES_LIST elf_loader) +endif () - idf_component_register( - SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Include/" - PRIV_INCLUDE_DIRS "Private/" - REQUIRES lvgl - PRIV_REQUIRES Tactility TactilityCore elf_loader TactilityKernel - ) - - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(${COMPONENT_LIB} PUBLIC -Wno-unused-variable) - endif() -else() - file(GLOB_RECURSE SOURCES "Source/*.c**") - - add_library(TactilityC OBJECT) - - target_sources(TactilityC PRIVATE ${SOURCES}) - include_directories(TactilityC PRIVATE Private/) - target_include_directories(TactilityC PUBLIC Include/) - target_link_libraries(TactilityC - PRIVATE Tactility - PRIVATE TactilityCore - PRIVATE TactilityKernel - PUBLIC lvgl - ) -endif() +file(GLOB_RECURSE SOURCE_FILES Source/*.c*) +tactility_add_module(TactilityC + SRCS ${SOURCE_FILES} + INCLUDE_DIRS Include/ + PRIV_INCLUDE_DIRS Private/ + REQUIRES ${REQUIRES_LIST} + PRIV_REQUIRES ${PRIV_REQUIRES_LIST} +) diff --git a/TactilityC/Source/tt_init.cpp b/TactilityC/Source/tt_init.cpp index 0e27a84c..29cd2092 100644 --- a/TactilityC/Source/tt_init.cpp +++ b/TactilityC/Source/tt_init.cpp @@ -51,7 +51,6 @@ #include -bool module_parent_resolve_symbol(ModuleParent* pParent, const char* name, uintptr_t* pInt); extern "C" { extern double __floatsidf(int x); @@ -375,9 +374,8 @@ uintptr_t tt_symbol_resolver(const char* symbolName) { } } - auto& module_parent = tt::getModuleParent(); uintptr_t symbol_address; - if (module_parent_resolve_symbol(&module_parent, symbolName, &symbol_address)) { + if (module_resolve_symbol_global(symbolName, &symbol_address)) { return symbol_address; } diff --git a/TactilityCore/CMakeLists.txt b/TactilityCore/CMakeLists.txt index 47f47aa3..f7b5b44b 100644 --- a/TactilityCore/CMakeLists.txt +++ b/TactilityCore/CMakeLists.txt @@ -1,31 +1,23 @@ cmake_minimum_required(VERSION 3.20) +include("${CMAKE_CURRENT_LIST_DIR}/../Buildscripts/module.cmake") + +file(GLOB_RECURSE SOURCE_FILES Source/*.c*) + +list(APPEND REQUIRES_LIST + TactilityFreeRtos + TactilityKernel + mbedtls +) + if (DEFINED ENV{ESP_IDF_VERSION}) - file(GLOB_RECURSE SOURCE_FILES Source/*.c*) - - idf_component_register( - SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Include/" - REQUIRES TactilityFreeRtos TactilityKernel mbedtls nvs_flash esp_rom + list(APPEND REQUIRES_LIST + nvs_flash esp_rom ) +endif () - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(${COMPONENT_LIB} PUBLIC -Wno-unused-variable) - endif() -else() - file(GLOB_RECURSE SOURCES "Source/*.c*") - - add_library(TactilityCore OBJECT) - - target_sources(TactilityCore - PRIVATE ${SOURCES} - ) - - target_include_directories(TactilityCore PUBLIC Include/) - - target_link_libraries(TactilityCore PUBLIC - TactilityFreeRtos - TactilityKernel - mbedtls - ) -endif() \ No newline at end of file +tactility_add_module(TactilityCore + SRCS ${SOURCE_FILES} + INCLUDE_DIRS "Include/" + REQUIRES ${REQUIRES_LIST} +) diff --git a/TactilityCore/Include/Tactility/Logger.h b/TactilityCore/Include/Tactility/Logger.h index 6155a06b..ac5f882e 100644 --- a/TactilityCore/Include/Tactility/Logger.h +++ b/TactilityCore/Include/Tactility/Logger.h @@ -1,72 +1,70 @@ #pragma once -#include "LoggerAdapter.h" -#include "LoggerSettings.h" - -#ifdef ESP_PLATFORM -#include "LoggerAdapterEsp.h" -#else -#include "LoggerAdapterGeneric.h" -#endif +#include #include namespace tt { -#ifdef ESP_PLATFORM -static LoggerAdapter defaultLoggerAdapter = espLoggerAdapter; -#else -static LoggerAdapter defaultLoggerAdapter = genericLoggerAdapter; -#endif - class Logger { const char* tag; + LogLevel level = LOG_LEVEL_INFO; + public: explicit Logger(const char* tag) : tag(tag) {} - template - void log(LogLevel level, std::format_string format, Args&&... args) const { - std::string message = std::format(format, std::forward(args)...); - defaultLoggerAdapter(level, tag, message.c_str()); - } - template void verbose(std::format_string format, Args&&... args) const { - log(LogLevel::Verbose, format, std::forward(args)...); + std::string message = std::format(format, std::forward(args)...); + LOG_V(tag, "%s", message.c_str()); } template void debug(std::format_string format, Args&&... args) const { - log(LogLevel::Debug, format, std::forward(args)...); + std::string message = std::format(format, std::forward(args)...); + LOG_D(tag, "%s", message.c_str()); } template void info(std::format_string format, Args&&... args) const { - log(LogLevel::Info, format, std::forward(args)...); + std::string message = std::format(format, std::forward(args)...); + LOG_I(tag, "%s", message.c_str()); } template void warn(std::format_string format, Args&&... args) const { - log(LogLevel::Warning, format, std::forward(args)...); + std::string message = std::format(format, std::forward(args)...); + LOG_W(tag, "%s", message.c_str()); } template void error(std::format_string format, Args&&... args) const { - log(LogLevel::Error, format, std::forward(args)...); + std::string message = std::format(format, std::forward(args)...); + LOG_E(tag, "%s", message.c_str()); } - bool isLoggingVerbose() const { return LogLevel::Verbose <= LOG_LEVEL; } + bool isLoggingVerbose() const { + return LOG_LEVEL_VERBOSE <= level; + } - bool isLoggingDebug() const { return LogLevel::Debug <= LOG_LEVEL; } + bool isLoggingDebug() const { + return LOG_LEVEL_DEBUG <= level; + } - bool isLoggingInfo() const { return LogLevel::Info <= LOG_LEVEL; } + bool isLoggingInfo() const { + return LOG_LEVEL_INFO <= level; + } - bool isLoggingWarning() const { return LogLevel::Warning <= LOG_LEVEL; } + bool isLoggingWarning() const { + return LOG_LEVEL_WARNING <= level; + } - bool isLoggingError() const { return LogLevel::Error <= LOG_LEVEL; } + bool isLoggingError() const { + return LOG_LEVEL_ERROR <= level; + } }; } diff --git a/TactilityCore/Include/Tactility/LoggerAdapter.h b/TactilityCore/Include/Tactility/LoggerAdapter.h deleted file mode 100644 index 2288bca5..00000000 --- a/TactilityCore/Include/Tactility/LoggerAdapter.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "LoggerCommon.h" -#include - -namespace tt { - -typedef std::function LoggerAdapter; - -} diff --git a/TactilityCore/Include/Tactility/LoggerAdapterEsp.h b/TactilityCore/Include/Tactility/LoggerAdapterEsp.h deleted file mode 100644 index f9861034..00000000 --- a/TactilityCore/Include/Tactility/LoggerAdapterEsp.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "LoggerAdapter.h" -#include "LoggerAdapterShared.h" - -#include -#include - -namespace tt { - -inline esp_log_level_t toEspLogLevel(LogLevel level) { - switch (level) { - case LogLevel::Error: - return ESP_LOG_ERROR; - case LogLevel::Warning: - return ESP_LOG_WARN; - case LogLevel::Info: - return ESP_LOG_INFO; - case LogLevel::Debug: - return ESP_LOG_DEBUG; - case LogLevel::Verbose: - default: - return ESP_LOG_VERBOSE; - } -} - -static const LoggerAdapter espLoggerAdapter = [](LogLevel level, const char* tag, const char* message) { - constexpr auto COLOR_RESET = "\033[0m"; - constexpr auto COLOR_GREY = "\033[37m"; - std::stringstream buffer; - buffer << COLOR_GREY << esp_log_timestamp() << ' ' << toTagColour(level) << toPrefix(level) << COLOR_GREY << " [" << COLOR_RESET << tag << COLOR_GREY << "] " << toMessageColour(level) << message << COLOR_RESET << std::endl; - esp_log_write(toEspLogLevel(level), tag, "%s", buffer.str().c_str()); -}; - -} diff --git a/TactilityCore/Include/Tactility/LoggerAdapterGeneric.h b/TactilityCore/Include/Tactility/LoggerAdapterGeneric.h deleted file mode 100644 index 72b2aa5f..00000000 --- a/TactilityCore/Include/Tactility/LoggerAdapterGeneric.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "LoggerAdapter.h" -#include "LoggerAdapterShared.h" - -#include -#include -#include -#include - -namespace tt { - -static uint64_t getLogTimestamp() { - static uint64_t base = 0U; - static std::once_flag init_flag; - std::call_once(init_flag, []() { - timeval time {}; - gettimeofday(&time, nullptr); - base = ((uint64_t)time.tv_sec * 1000U) + (time.tv_usec / 1000U); - }); - timeval time {}; - gettimeofday(&time, nullptr); - uint64_t now = ((uint64_t)time.tv_sec * 1000U) + (time.tv_usec / 1000U); - return now - base; -} - -static const LoggerAdapter genericLoggerAdapter = [](LogLevel level, const char* tag, const char* message) { - constexpr auto COLOR_RESET = "\033[0m"; - constexpr auto COLOR_GREY = "\033[37m"; - std::stringstream buffer; - buffer << COLOR_GREY << getLogTimestamp() << ' ' << toTagColour(level) << toPrefix(level) << COLOR_GREY << " [" << COLOR_RESET << tag << COLOR_GREY << "] " << toMessageColour(level) << message << COLOR_RESET << std::endl; - printf("%s", buffer.str().c_str()); -}; - -} \ No newline at end of file diff --git a/TactilityCore/Include/Tactility/LoggerAdapterShared.h b/TactilityCore/Include/Tactility/LoggerAdapterShared.h deleted file mode 100644 index af4527cc..00000000 --- a/TactilityCore/Include/Tactility/LoggerAdapterShared.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "LoggerCommon.h" - -namespace tt { - -inline const char* toTagColour(LogLevel level) { - using enum LogLevel; - switch (level) { - case Error: - return "\033[1;31m"; - case Warning: - return "\033[1;33m"; - case Info: - return "\033[32m"; - case Debug: - return "\033[36m"; - case Verbose: - return "\033[37m"; - default: - return ""; - } -} - -inline const char* toMessageColour(LogLevel level) { - using enum LogLevel; - switch (level) { - case Error: - return "\033[1;31m"; - case Warning: - return "\033[1;33m"; - case Info: - case Debug: - case Verbose: - return "\033[0m"; - default: - return ""; - } -} - -inline char toPrefix(LogLevel level) { - using enum LogLevel; - switch (level) { - case Error: - return 'E'; - case Warning: - return 'W'; - case Info: - return 'I'; - case Debug: - return 'D'; - case Verbose: - default: - return 'V'; - } -} - -} \ No newline at end of file diff --git a/TactilityCore/Include/Tactility/LoggerCommon.h b/TactilityCore/Include/Tactility/LoggerCommon.h deleted file mode 100644 index fdbac48d..00000000 --- a/TactilityCore/Include/Tactility/LoggerCommon.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -namespace tt { - -/** Used for log output filtering */ -enum class LogLevel : int { - Error, /*!< Critical errors, software module can not recover on its own */ - Warning, /*!< Error conditions from which recovery measures have been taken */ - Info, /*!< Information messages which describe normal flow of events */ - Debug, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */ - Verbose /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */ -}; - -} \ No newline at end of file diff --git a/TactilityCore/Include/Tactility/LoggerSettings.h b/TactilityCore/Include/Tactility/LoggerSettings.h deleted file mode 100644 index 3bb5105a..00000000 --- a/TactilityCore/Include/Tactility/LoggerSettings.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "LoggerCommon.h" - -namespace tt { - -constexpr auto LOG_LEVEL = LogLevel::Info; - -} \ No newline at end of file diff --git a/TactilityFreeRtos/CMakeLists.txt b/TactilityFreeRtos/CMakeLists.txt index f23dce53..1ae8bef9 100644 --- a/TactilityFreeRtos/CMakeLists.txt +++ b/TactilityFreeRtos/CMakeLists.txt @@ -18,4 +18,4 @@ else() target_link_libraries(TactilityFreeRtos INTERFACE freertos_kernel ) -endif() \ No newline at end of file +endif() diff --git a/TactilityKernel/CMakeLists.txt b/TactilityKernel/CMakeLists.txt index 780a9782..d451fdb0 100644 --- a/TactilityKernel/CMakeLists.txt +++ b/TactilityKernel/CMakeLists.txt @@ -1,20 +1,20 @@ cmake_minimum_required(VERSION 3.20) -file(GLOB_RECURSE SOURCES "Source/*.c**") +include("${CMAKE_CURRENT_LIST_DIR}/../Buildscripts/module.cmake") + +file(GLOB_RECURSE SOURCE_FILES "Source/*.c**") + +list(APPEND REQUIRES_LIST) if (DEFINED ENV{ESP_IDF_VERSION}) - - idf_component_register( - SRCS ${SOURCES} - INCLUDE_DIRS "Include/" - # TODO move the related logic for esp_time in Tactility/time.h into the Platform/ subproject - REQUIRES esp_timer - ) - + # TODO move the related logic for esp_time in Tactility/time.h into the Platform/ subproject + list(APPEND REQUIRES_LIST esp_timer) else () - - add_library(TactilityKernel OBJECT ${SOURCES}) - target_include_directories(TactilityKernel PUBLIC Include/) - target_link_libraries(TactilityKernel PUBLIC freertos_kernel) - + list(APPEND REQUIRES_LIST freertos_kernel) endif () + +tactility_add_module(TactilityKernel + SRCS ${SOURCE_FILES} + INCLUDE_DIRS Include/ + REQUIRES ${REQUIRES_LIST} +) diff --git a/TactilityKernel/Include/tactility/log.h b/TactilityKernel/Include/tactility/log.h index 452a1412..1a702cc0 100644 --- a/TactilityKernel/Include/tactility/log.h +++ b/TactilityKernel/Include/tactility/log.h @@ -10,25 +10,32 @@ extern "C" { #endif -#define LOG_TAG(x) "\033[37m"#x"\033[0m" +/** Used for log output filtering */ +enum LogLevel { + LOG_LEVEL_ERROR, /*!< Critical errors, software module can not recover on its own */ + LOG_LEVEL_WARNING, /*!< Error conditions from which recovery measures have been taken */ + LOG_LEVEL_INFO, /*!< Information messages which describe normal flow of events */ + LOG_LEVEL_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */ + LOG_LEVEL_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */ +}; #ifndef ESP_PLATFORM -void log_generic(const char* tag, const char* format, ...); +void log_generic(enum LogLevel level, const char* tag, const char* format, ...); -#define LOG_E(x, ...) log_generic(x, ##__VA_ARGS__) -#define LOG_W(x, ...) log_generic(x, ##__VA_ARGS__) -#define LOG_I(x, ...) log_generic(x, ##__VA_ARGS__) -#define LOG_D(x, ...) log_generic(x, ##__VA_ARGS__) -#define LOG_V(x, ...) log_generic(x, ##__VA_ARGS__) +#define LOG_E(tag, ...) log_generic(LOG_LEVEL_ERROR, tag, ##__VA_ARGS__) +#define LOG_W(tag, ...) log_generic(LOG_LEVEL_WARNING, tag, ##__VA_ARGS__) +#define LOG_I(tag, ...) log_generic(LOG_LEVEL_INFO, tag, ##__VA_ARGS__) +#define LOG_D(tag, ...) log_generic(LOG_LEVEL_DEBUG, tag, ##__VA_ARGS__) +#define LOG_V(tag, ...) log_generic(LOG_LEVEL_VERBOSE, tag, ##__VA_ARGS__) #else -#define LOG_E(x, ...) ESP_LOGE(x, ##__VA_ARGS__) -#define LOG_W(x, ...) ESP_LOGW(x, ##__VA_ARGS__) -#define LOG_I(x, ...) ESP_LOGI(x, ##__VA_ARGS__) -#define LOG_D(x, ...) ESP_LOGD(x, ##__VA_ARGS__) -#define LOG_V(x, ...) ESP_LOGV(x, ##__VA_ARGS__) +#define LOG_E(tag, ...) ESP_LOGE(tag, ##__VA_ARGS__) +#define LOG_W(tag, ...) ESP_LOGW(tag, ##__VA_ARGS__) +#define LOG_I(tag, ...) ESP_LOGI(tag, ##__VA_ARGS__) +#define LOG_D(tag, ...) ESP_LOGD(tag, ##__VA_ARGS__) +#define LOG_V(tag, ...) ESP_LOGV(tag, ##__VA_ARGS__) #endif diff --git a/TactilityKernel/Include/tactility/module.h b/TactilityKernel/Include/tactility/module.h index 7895705d..0348d773 100644 --- a/TactilityKernel/Include/tactility/module.h +++ b/TactilityKernel/Include/tactility/module.h @@ -6,15 +6,17 @@ #include #ifdef __cplusplus -extern "C" { +#define MODULE_SYMBOL_TERMINATOR { nullptr, nullptr } +#else +#define MODULE_SYMBOL_TERMINATOR { NULL, NULL } #endif -struct ModuleParent; -struct ModuleParentPrivate; - -#define MODULE_SYMBOL_TERMINATOR { NULL, NULL } #define DEFINE_MODULE_SYMBOL(symbol) { #symbol, (void*)&symbol } +#ifdef __cplusplus +extern "C" { +#endif + /** A binary symbol like a function or a variable. */ struct ModuleSymbol { /** The name of the symbol. */ @@ -57,60 +59,44 @@ struct Module { */ const struct ModuleSymbol* symbols; + struct { bool started; - struct ModuleParent* parent; } internal; }; /** - * A module parent is a collection of modules that can be loaded and unloaded at runtime. + * @brief Construct a module instance. + * @param module module instance to construct + * @return ERROR_NONE if successful */ -struct ModuleParent { - /** The name of the parent module, for logging/debugging purposes */ - const char* name; - struct ModuleParentPrivate* module_parent_private; -}; +error_t module_construct(struct Module* module); /** - * @brief Initialize the module parent. - * @warn This function does no validation on input or state. - * @param parent parent module - * @return ERROR_NONE if successful, ERROR_OUT_OF_MEMORY if allocation fails + * @brief Destruct a module instance. + * @param module module instance to destruct + * @return ERROR_NONE if successful */ -error_t module_parent_construct(struct ModuleParent* parent); +error_t module_destruct(struct Module* module); /** - * @brief Deinitialize the module parent. Must have no children when calling this. - * @warn This function does no validation on input. - * @param parent parent module - * @return ERROR_NONE if successful or ERROR_INVALID_STATE if the parent has children + * @brief Add a module to the system. + * @param module module to add + * @return ERROR_NONE if successful */ -error_t module_parent_destruct(struct ModuleParent* parent); +error_t module_add(struct Module* module); /** - * @brief Resolve a symbol from the module parent. - * @details This function iterates through all started modules in the parent and attempts to resolve the symbol. - * @param parent parent module - * @param symbol_name name of the symbol to resolve - * @param symbol_address pointer to store the address of the resolved symbol - * @return true if the symbol was found, false otherwise + * @brief Remove a module from the system. + * @param module module to remove + * @return ERROR_NONE if successful */ -bool module_parent_resolve_symbol(struct ModuleParent* parent, const char* symbol_name, uintptr_t* symbol_address); - -/** - * @brief Set the parent of the module. - * @warning must call before module_start() - * @param module module - * @param parent nullable parent module - * @return ERROR_NONE if successful, ERROR_INVALID_STATE if the module is already started - */ -error_t module_set_parent(struct Module* module, struct ModuleParent* parent); +error_t module_remove(struct Module* module); /** * @brief Start the module. * @param module module - * @return ERROR_NONE if already started, ERROR_INVALID_STATE if the module doesn't have a parent, or otherwise it returns the result of the module's start function + * @return ERROR_NONE if already started, or otherwise it returns the result of the module's start function */ error_t module_start(struct Module* module); @@ -138,6 +124,16 @@ error_t module_stop(struct Module* module); */ bool module_resolve_symbol(struct Module* module, const char* symbol_name, uintptr_t* symbol_address); +/** + * @brief Resolve a symbol from any module + * @details This function iterates through all started modules in the parent and attempts to resolve the symbol. + * @param parent parent module + * @param symbol_name name of the symbol to resolve + * @param symbol_address pointer to store the address of the resolved symbol + * @return true if the symbol was found, false otherwise + */ +bool module_resolve_symbol_global(const char* symbol_name, uintptr_t* symbol_address); + #ifdef __cplusplus } #endif diff --git a/TactilityKernel/Source/concurrent/dispatcher.cpp b/TactilityKernel/Source/concurrent/dispatcher.cpp index 41873c05..2574104b 100644 --- a/TactilityKernel/Source/concurrent/dispatcher.cpp +++ b/TactilityKernel/Source/concurrent/dispatcher.cpp @@ -11,7 +11,7 @@ #include #include -#define TAG LOG_TAG(Dispatcher) +#define TAG "Dispatcher" static constexpr EventBits_t BACKPRESSURE_WARNING_COUNT = 100U; static constexpr EventBits_t WAIT_FLAG = 1U; diff --git a/TactilityKernel/Source/concurrent/thread.cpp b/TactilityKernel/Source/concurrent/thread.cpp index b57735e6..5bed3109 100644 --- a/TactilityKernel/Source/concurrent/thread.cpp +++ b/TactilityKernel/Source/concurrent/thread.cpp @@ -11,7 +11,7 @@ #include static const size_t LOCAL_STORAGE_SELF_POINTER_INDEX = 0; -static const char* TAG = LOG_TAG(Thread); +static const char* TAG = "Thread"; struct Thread { TaskHandle_t taskHandle = nullptr; diff --git a/TactilityKernel/Source/crash.cpp b/TactilityKernel/Source/crash.cpp index dbeeb8a4..99481ab7 100644 --- a/TactilityKernel/Source/crash.cpp +++ b/TactilityKernel/Source/crash.cpp @@ -2,7 +2,7 @@ #include #include -static const auto* TAG = LOG_TAG(Kernel); +static const auto* TAG = "Kernel"; static void log_memory_info() { #ifdef ESP_PLATFORM diff --git a/TactilityKernel/Source/device.cpp b/TactilityKernel/Source/device.cpp index 2e5452dd..d25d78ea 100644 --- a/TactilityKernel/Source/device.cpp +++ b/TactilityKernel/Source/device.cpp @@ -11,7 +11,7 @@ #include #include -#define TAG LOG_TAG(device) +#define TAG "device" struct DevicePrivate { std::vector children; diff --git a/TactilityKernel/Source/driver.cpp b/TactilityKernel/Source/driver.cpp index bd93f7a7..02746811 100644 --- a/TactilityKernel/Source/driver.cpp +++ b/TactilityKernel/Source/driver.cpp @@ -10,7 +10,7 @@ #include #include -#define TAG LOG_TAG(driver) +#define TAG "driver" struct DriverPrivate { Mutex mutex { 0 }; @@ -30,21 +30,11 @@ struct DriverLedger { std::vector drivers; Mutex mutex { 0 }; - DriverLedger() { - mutex_construct(&mutex); - } + DriverLedger() { mutex_construct(&mutex); } + ~DriverLedger() { mutex_destruct(&mutex); } - ~DriverLedger() { - mutex_destruct(&mutex); - } - - void lock() { - mutex_lock(&mutex); - } - - void unlock() { - mutex_unlock(&mutex); - } + void lock() { mutex_lock(&mutex); } + void unlock() { mutex_unlock(&mutex); } }; static DriverLedger& get_ledger() { @@ -99,6 +89,8 @@ error_t driver_add(Driver* driver) { error_t driver_remove(Driver* driver) { LOG_I(TAG, "remove %s", driver->name); + if (driver->owner == nullptr) return ERROR_NOT_ALLOWED; + ledger.lock(); const auto iterator = std::ranges::find(ledger.drivers, driver); if (iterator == ledger.drivers.end()) { diff --git a/TactilityKernel/Source/drivers/root.cpp b/TactilityKernel/Source/drivers/root.cpp index f52ffdd2..0288e4c1 100644 --- a/TactilityKernel/Source/drivers/root.cpp +++ b/TactilityKernel/Source/drivers/root.cpp @@ -12,8 +12,7 @@ Driver root_driver = { .stop_device = nullptr, .api = nullptr, .device_type = nullptr, - .owner = nullptr, - .driver_private = nullptr + .owner = nullptr }; } diff --git a/TactilityKernel/Source/kernel_init.cpp b/TactilityKernel/Source/kernel_init.cpp index 1877d7fb..419d857b 100644 --- a/TactilityKernel/Source/kernel_init.cpp +++ b/TactilityKernel/Source/kernel_init.cpp @@ -5,12 +5,7 @@ extern "C" { #endif -#define TAG LOG_TAG(kernel) - -struct ModuleParent kernel_module_parent = { - "kernel", - nullptr -}; +#define TAG "kernel" static error_t init_kernel_drivers() { extern Driver root_driver; @@ -21,24 +16,37 @@ static error_t init_kernel_drivers() { error_t kernel_init(struct Module* platform_module, struct Module* device_module, struct CompatibleDevice devicetree_devices[]) { LOG_I(TAG, "init"); - if (module_parent_construct(&kernel_module_parent) != ERROR_NONE) { - LOG_E(TAG, "init failed to create kernel module parent"); - return ERROR_RESOURCE; - } - if (init_kernel_drivers() != ERROR_NONE) { LOG_E(TAG, "init failed to init kernel drivers"); return ERROR_RESOURCE; } - module_set_parent(platform_module, &kernel_module_parent); + if (module_construct(platform_module) != ERROR_NONE) { + LOG_E(TAG, "init failed to construct platform module"); + return ERROR_RESOURCE; + } + + if (module_add(platform_module) != ERROR_NONE) { + LOG_E(TAG, "init failed to add platform module"); + return ERROR_RESOURCE; + } + if (module_start(platform_module) != ERROR_NONE) { LOG_E(TAG, "init failed to start platform module"); return ERROR_RESOURCE; } if (device_module != nullptr) { - module_set_parent(device_module, &kernel_module_parent); + if (module_construct(device_module) != ERROR_NONE) { + LOG_E(TAG, "init failed to construct device module"); + return ERROR_RESOURCE; + } + + if (module_add(device_module) != ERROR_NONE) { + LOG_E(TAG, "init failed to add device module"); + return ERROR_RESOURCE; + } + if (module_start(device_module) != ERROR_NONE) { LOG_E(TAG, "init failed to start device module"); return ERROR_RESOURCE; diff --git a/TactilityKernel/Source/log.cpp b/TactilityKernel/Source/log.cpp index cb404dfb..1ad0b5b6 100644 --- a/TactilityKernel/Source/log.cpp +++ b/TactilityKernel/Source/log.cpp @@ -4,15 +4,69 @@ #include +#include +#include #include +#include #include +#include + +static const char* get_log_color(LogLevel level) { + using enum LogLevel; + switch (level) { + case LOG_LEVEL_ERROR: + return "\033[1;31m"; + case LOG_LEVEL_WARNING: + return "\033[1;33m"; + case LOG_LEVEL_INFO: + return "\033[32m"; + case LOG_LEVEL_DEBUG: + return "\033[36m"; + case LOG_LEVEL_VERBOSE: + return "\033[37m"; + default: + return ""; + } +} + +static inline char get_log_prefix(LogLevel level) { + using enum LogLevel; + switch (level) { + case LOG_LEVEL_ERROR: + return 'E'; + case LOG_LEVEL_WARNING: + return 'W'; + case LOG_LEVEL_INFO: + return 'I'; + case LOG_LEVEL_DEBUG: + return 'D'; + case LOG_LEVEL_VERBOSE: + return 'V'; + default: + return '?'; + } +} + +static uint64_t get_log_timestamp() { + static uint64_t base = 0U; + static std::once_flag init_flag; + std::call_once(init_flag, []() { + timeval time {}; + gettimeofday(&time, nullptr); + base = ((uint64_t)time.tv_sec * 1000U) + (time.tv_usec / 1000U); + }); + timeval time {}; + gettimeofday(&time, nullptr); + uint64_t now = ((uint64_t)time.tv_sec * 1000U) + (time.tv_usec / 1000U); + return now - base; +} extern "C" { -void log_generic(const char* tag, const char* format, ...) { +void log_generic(enum LogLevel level, const char* tag, const char* format, ...) { va_list args; va_start(args, format); - printf("%s ", tag); + printf("%s %c (%" PRIu64 ") \033[37m%s\033[0m ", get_log_color(level), get_log_prefix(level), get_log_timestamp(), tag); vprintf(format, args); printf("\n"); va_end(args); diff --git a/TactilityKernel/Source/module.cpp b/TactilityKernel/Source/module.cpp index 9a43becd..9c129f0d 100644 --- a/TactilityKernel/Source/module.cpp +++ b/TactilityKernel/Source/module.cpp @@ -4,88 +4,40 @@ #include #include -#define TAG LOG_TAG(module) +#define TAG "module" -struct ModuleParentPrivate { +struct ModuleLedger { std::vector modules; struct Mutex mutex = { 0 }; + + ModuleLedger() { mutex_construct(&mutex); } + ~ModuleLedger() { mutex_destruct(&mutex); } }; +static ModuleLedger ledger; + extern "C" { -#pragma region module_parent - -error_t module_parent_construct(struct ModuleParent* parent) { - parent->module_parent_private = new (std::nothrow) ModuleParentPrivate(); - if (!parent->module_parent_private) return ERROR_OUT_OF_MEMORY; - - auto* data = static_cast(parent->module_parent_private); - mutex_construct(&data->mutex); - +error_t module_construct(struct Module* module) { + module->internal.started = false; return ERROR_NONE; } -error_t module_parent_destruct(struct ModuleParent* parent) { - auto* data = static_cast(parent->module_parent_private); - if (data == nullptr) return ERROR_NONE; - - mutex_lock(&data->mutex); - if (!data->modules.empty()) { - mutex_unlock(&data->mutex); - return ERROR_INVALID_STATE; - } - mutex_unlock(&data->mutex); - - mutex_destruct(&data->mutex); - delete data; - parent->module_parent_private = nullptr; +error_t module_destruct(struct Module* module) { return ERROR_NONE; } -bool module_parent_resolve_symbol(ModuleParent* parent, const char* symbol_name, uintptr_t* symbol_address) { - auto* data = static_cast(parent->module_parent_private); - mutex_lock(&data->mutex); - for (auto* module : data->modules) { - if (!module_is_started(module)) - continue; - if (module_resolve_symbol(module, symbol_name, symbol_address)) { - mutex_unlock(&data->mutex); - return true; - } - } - mutex_unlock(&data->mutex); - return false; +error_t module_add(struct Module* module) { + mutex_lock(&ledger.mutex); + ledger.modules.push_back(module); + mutex_unlock(&ledger.mutex); + return ERROR_NONE; } -#pragma endregion - -#pragma region module - -error_t module_set_parent(struct Module* module, struct ModuleParent* parent) { - if (module->internal.started) return ERROR_INVALID_STATE; - if (module->internal.parent == parent) return ERROR_NONE; - - // Remove from old parent - if (module->internal.parent && module->internal.parent->module_parent_private) { - auto* old_data = static_cast(module->internal.parent->module_parent_private); - mutex_lock(&old_data->mutex); - auto it = std::find(old_data->modules.begin(), old_data->modules.end(), module); - if (it != old_data->modules.end()) { - old_data->modules.erase(it); - } - mutex_unlock(&old_data->mutex); - } - - module->internal.parent = parent; - - // Add to new parent - if (parent && parent->module_parent_private) { - auto* new_data = static_cast(parent->module_parent_private); - mutex_lock(&new_data->mutex); - new_data->modules.push_back(module); - mutex_unlock(&new_data->mutex); - } - +error_t module_remove(struct Module* module) { + mutex_lock(&ledger.mutex); + ledger.modules.erase(std::remove(ledger.modules.begin(), ledger.modules.end(), module), ledger.modules.end()); + mutex_unlock(&ledger.mutex); return ERROR_NONE; } @@ -93,7 +45,6 @@ error_t module_start(struct Module* module) { LOG_I(TAG, "start %s", module->name); if (module->internal.started) return ERROR_NONE; - if (!module->internal.parent) return ERROR_INVALID_STATE; error_t error = module->start(); module->internal.started = (error == ERROR_NONE); @@ -132,7 +83,19 @@ bool module_resolve_symbol(Module* module, const char* symbol_name, uintptr_t* s return false; } -#pragma endregion +bool module_resolve_symbol_global(const char* symbol_name, uintptr_t* symbol_address) { + mutex_lock(&ledger.mutex); + for (auto* module : ledger.modules) { + if (!module_is_started(module)) + continue; + if (module_resolve_symbol(module, symbol_name, symbol_address)) { + mutex_unlock(&ledger.mutex); + return true; + } + } + mutex_unlock(&ledger.mutex); + return false; +} } diff --git a/Tests/Tactility/Main.cpp b/Tests/Tactility/Main.cpp index e613b156..661e44ef 100644 --- a/Tests/Tactility/Main.cpp +++ b/Tests/Tactility/Main.cpp @@ -34,9 +34,7 @@ void test_task(void* parameter) { context.setOption("no-breaks", true); // don't break in the debugger when assertions fail check(kernel_init(&platform_module, nullptr, nullptr) == ERROR_NONE); - // HAL compatibility module: it creates kernel driver wrappers for tt::hal::Device - check(module_parent_construct(&tactility_tests_module_parent) == ERROR_NONE); - check(module_set_parent(&hal_device_module, &tactility_tests_module_parent) == ERROR_NONE); + check(module_construct(&hal_device_module) == ERROR_NONE); check(module_start(&hal_device_module) == ERROR_NONE); data->result = context.run(); diff --git a/Tests/TactilityKernel/ModuleTest.cpp b/Tests/TactilityKernel/ModuleTest.cpp index 9d42168d..d4f00f8e 100644 --- a/Tests/TactilityKernel/ModuleTest.cpp +++ b/Tests/TactilityKernel/ModuleTest.cpp @@ -1,6 +1,8 @@ #include "doctest.h" #include +static void symbol_test_function() { /* NO-OP */ } + static error_t test_start_result = ERROR_NONE; static bool start_called = false; static error_t test_start() { @@ -15,84 +17,40 @@ static error_t test_stop() { return test_stop_result; } -TEST_CASE("ModuleParent construction and destruction") { - struct ModuleParent parent = { "test_parent", nullptr }; +TEST_CASE("Module construction and destruction") { + struct Module module = { + .name = "test", + .start = test_start, + .stop = test_stop, + .symbols = nullptr, + .internal = {.started = false} + }; // Test successful construction - CHECK_EQ(module_parent_construct(&parent), ERROR_NONE); - CHECK_NE(parent.module_parent_private, nullptr); + CHECK_EQ(module_construct(&module), ERROR_NONE); + CHECK_EQ(module.internal.started, false); // Test successful destruction - CHECK_EQ(module_parent_destruct(&parent), ERROR_NONE); - CHECK_EQ(parent.module_parent_private, nullptr); + CHECK_EQ(module_destruct(&module), ERROR_NONE); } -TEST_CASE("ModuleParent destruction with children") { - struct ModuleParent parent = { "parent", nullptr }; - REQUIRE_EQ(module_parent_construct(&parent), ERROR_NONE); - +TEST_CASE("Module registration") { struct Module module = { .name = "test", .start = test_start, .stop = test_stop, .symbols = nullptr, - .internal = {.started = false, .parent = nullptr} + .internal = {.started = false} }; - REQUIRE_EQ(module_set_parent(&module, &parent), ERROR_NONE); + // module_add should succeed + CHECK_EQ(module_add(&module), ERROR_NONE); - // Should fail to destruct because it has a child - CHECK_EQ(module_parent_destruct(&parent), ERROR_INVALID_STATE); - CHECK_NE(parent.module_parent_private, nullptr); - - // Remove child - REQUIRE_EQ(module_set_parent(&module, nullptr), ERROR_NONE); - - // Now it should succeed - CHECK_EQ(module_parent_destruct(&parent), ERROR_NONE); - CHECK_EQ(parent.module_parent_private, nullptr); -} - -TEST_CASE("Module parent management") { - struct ModuleParent parent1 = { "parent1", nullptr }; - struct ModuleParent parent2 = { "parent2", nullptr }; - REQUIRE_EQ(module_parent_construct(&parent1), ERROR_NONE); - REQUIRE_EQ(module_parent_construct(&parent2), ERROR_NONE); - - struct Module module = { - .name = "test", - .start = test_start, - .stop = test_stop, - .symbols = nullptr, - .internal = {.started = false, .parent = nullptr} - }; - - // Set parent - CHECK_EQ(module_set_parent(&module, &parent1), ERROR_NONE); - CHECK_EQ(module.internal.parent, &parent1); - - // Change parent - CHECK_EQ(module_set_parent(&module, &parent2), ERROR_NONE); - CHECK_EQ(module.internal.parent, &parent2); - - // Clear parent - CHECK_EQ(module_set_parent(&module, nullptr), ERROR_NONE); - CHECK_EQ(module.internal.parent, nullptr); - - // Set same parent (should be NOOP and return ERROR_NONE) - CHECK_EQ(module_set_parent(&module, &parent1), ERROR_NONE); - CHECK_EQ(module_set_parent(&module, &parent1), ERROR_NONE); - CHECK_EQ(module.internal.parent, &parent1); - - CHECK_EQ(module_set_parent(&module, nullptr), ERROR_NONE); - CHECK_EQ(module_parent_destruct(&parent1), ERROR_NONE); - CHECK_EQ(module_parent_destruct(&parent2), ERROR_NONE); + // module_remove should succeed + CHECK_EQ(module_remove(&module), ERROR_NONE); } TEST_CASE("Module lifecycle") { - struct ModuleParent parent = { "parent", nullptr }; - REQUIRE_EQ(module_parent_construct(&parent), ERROR_NONE); - start_called = false; stop_called = false; test_start_result = ERROR_NONE; @@ -103,48 +61,37 @@ TEST_CASE("Module lifecycle") { .start = test_start, .stop = test_stop, .symbols = nullptr, - .internal = {.started = false, .parent = nullptr} + .internal = {.started = false} }; - // 1. Cannot start without parent - CHECK_EQ(module_start(&module), ERROR_INVALID_STATE); - CHECK_EQ(module_is_started(&module), false); - CHECK_EQ(start_called, false); - - CHECK_EQ(module_set_parent(&module, &parent), ERROR_NONE); - - // 2. Successful start + // 1. Successful start (no parent required anymore) CHECK_EQ(module_start(&module), ERROR_NONE); CHECK_EQ(module_is_started(&module), true); CHECK_EQ(start_called, true); - // 3. Start when already started (should return ERROR_NONE) + // Start when already started (should return ERROR_NONE) start_called = false; CHECK_EQ(module_start(&module), ERROR_NONE); CHECK_EQ(start_called, false); // start() function should NOT be called again - // 4. Cannot change parent while started - CHECK_EQ(module_set_parent(&module, nullptr), ERROR_INVALID_STATE); - - // 5. Successful stop + // Stop successful CHECK_EQ(module_stop(&module), ERROR_NONE); CHECK_EQ(module_is_started(&module), false); CHECK_EQ(stop_called, true); - // 6. Stop when already stopped (should return ERROR_NONE) + // Stop when already stopped (should return ERROR_NONE) stop_called = false; CHECK_EQ(module_stop(&module), ERROR_NONE); CHECK_EQ(stop_called, false); // stop() function should NOT be called again - // 7. Test failed start + // Test failed start test_start_result = ERROR_NOT_FOUND; start_called = false; CHECK_EQ(module_start(&module), ERROR_NOT_FOUND); CHECK_EQ(module_is_started(&module), false); CHECK_EQ(start_called, true); - // 8. Test failed stop - CHECK_EQ(module_set_parent(&module, &parent), ERROR_NONE); + // Test failed stop test_start_result = ERROR_NONE; CHECK_EQ(module_start(&module), ERROR_NONE); @@ -157,7 +104,32 @@ TEST_CASE("Module lifecycle") { // Clean up: fix stop result so we can stop it test_stop_result = ERROR_NONE; CHECK_EQ(module_stop(&module), ERROR_NONE); - - CHECK_EQ(module_set_parent(&module, nullptr), ERROR_NONE); - CHECK_EQ(module_parent_destruct(&parent), ERROR_NONE); +} + +TEST_CASE("Global symbol resolution") { + static const struct ModuleSymbol test_symbols[] = { + DEFINE_MODULE_SYMBOL(symbol_test_function), + MODULE_SYMBOL_TERMINATOR + }; + + struct Module module = { + .name = "test_sym", + .start = test_start, + .stop = test_stop, + .symbols = test_symbols, + .internal = {.started = false} + }; + + uintptr_t addr; + // Should fail as it is not added or started + CHECK_EQ(module_resolve_symbol_global("symbol_test_function", &addr), false); + REQUIRE_EQ(module_add(&module), ERROR_NONE); + CHECK_EQ(module_resolve_symbol_global("symbol_test_function", &addr), false); + REQUIRE_EQ(module_start(&module), ERROR_NONE); + // Still fails as symbols are null + CHECK_EQ(module_resolve_symbol_global("symbol_test_function", &addr), true); + + // Cleanup + CHECK_EQ(module_remove(&module), ERROR_NONE); + CHECK_EQ(module_destruct(&module), ERROR_NONE); }