From 415096c3b28b2db9daf186a66b0a722faae7c3bf Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Tue, 7 Jan 2025 20:45:23 +0100 Subject: [PATCH] Update docs and fix bugs (#149) Improved the docs for the 3 main Tactility projects. I also fixed some inaccuracies and bugs in certain APIs as I went through the code. --- App/Source/Main.cpp | 4 +- Boards/Simulator/Source/LvglTask.cpp | 4 +- Documentation/ideas.md | 13 +- Tactility/Source/Tactility.h | 20 ++- Tactility/Source/app/AppContext.h | 4 +- Tactility/Source/app/AppManifest.h | 42 ++---- Tactility/Source/app/ElfApp.cpp | 2 +- Tactility/Source/app/ManifestRegistry.h | 8 ++ .../Source/app/crashdiagnostics/QrUrl.cpp | 10 +- Tactility/Source/lvgl/LvglSync.cpp | 12 +- Tactility/Source/lvgl/LvglSync.h | 17 ++- Tactility/Source/service/gui/Gui.h | 13 +- Tactility/Source/service/gui/ViewPort.h | 20 ++- Tactility/Source/service/loader/Loader.h | 5 +- .../Source/service/screenshot/Screenshot.cpp | 4 +- .../Source/service/screenshot/Screenshot.h | 20 ++- .../service/screenshot/ScreenshotTask.h | 16 +-- TactilityC/Source/tt_message_queue.cpp | 4 +- TactilityC/Source/tt_message_queue.h | 6 +- TactilityC/Source/tt_mutex.cpp | 4 +- TactilityC/Source/tt_mutex.h | 4 +- TactilityC/Source/tt_semaphore.cpp | 4 +- TactilityC/Source/tt_semaphore.h | 6 +- TactilityC/Source/tt_timer.cpp | 9 +- TactilityC/Source/tt_timer.h | 8 +- TactilityCore/Source/Bundle.h | 3 + TactilityCore/Source/Check.h | 16 +-- TactilityCore/Source/CoreDefines.h | 2 - TactilityCore/Source/CoreExtraDefines.h | 59 +++------ TactilityCore/Source/Dispatcher.cpp | 12 +- TactilityCore/Source/Dispatcher.h | 31 ++++- TactilityCore/Source/DispatcherThread.cpp | 4 +- TactilityCore/Source/DispatcherThread.h | 2 +- TactilityCore/Source/Lockable.h | 14 +- TactilityCore/Source/Log.h | 5 + TactilityCore/Source/MessageQueue.cpp | 14 +- TactilityCore/Source/MessageQueue.h | 5 +- TactilityCore/Source/Mutex.cpp | 4 +- TactilityCore/Source/Mutex.h | 54 ++++---- TactilityCore/Source/Pubsub.cpp | 4 +- TactilityCore/Source/Pubsub.h | 31 ++--- TactilityCore/Source/StreamBuffer.h | 18 +-- TactilityCore/Source/Thread.h | 122 +++++------------- TactilityCore/Source/Timer.cpp | 25 ++-- TactilityCore/Source/Timer.h | 36 ++---- TactilityCore/Source/crypt/Crypt.cpp | 28 ++-- TactilityCore/Source/crypt/Crypt.h | 28 ++-- TactilityCore/Source/crypt/Hash.h | 1 + TactilityCore/Source/file/File.cpp | 27 ++-- TactilityCore/Source/file/File.h | 10 ++ TactilityCore/Source/kernel/Kernel.cpp | 16 +-- TactilityCore/Source/kernel/Kernel.h | 77 +++-------- TactilityCore/Source/kernel/PanicHandler.cpp | 7 +- TactilityCore/Source/kernel/PanicHandler.h | 5 +- .../Source/kernel/critical/Critical.h | 7 + TactilityHeadless/Source/Preferences.h | 4 + TactilityHeadless/Source/TactilityHeadless.h | 6 + .../Source/service/ServiceContext.h | 10 +- .../Source/service/ServiceManifest.h | 14 +- .../Source/service/ServiceRegistry.h | 27 +++- TactilityHeadless/Source/service/wifi/Wifi.h | 31 ++--- .../Source/service/wifi/WifiEsp.cpp | 2 +- 62 files changed, 503 insertions(+), 517 deletions(-) diff --git a/App/Source/Main.cpp b/App/Source/Main.cpp index 2ff4dbce..5f3b8f1b 100644 --- a/App/Source/Main.cpp +++ b/App/Source/Main.cpp @@ -18,9 +18,7 @@ void app_main() { .hardware = TT_BOARD_HARDWARE, .apps = { &hello_world_app, - }, - .services = {}, - .autoStartAppId = nullptr + } }; #ifdef ESP_PLATFORM diff --git a/Boards/Simulator/Source/LvglTask.cpp b/Boards/Simulator/Source/LvglTask.cpp index ce347f78..e137b75b 100644 --- a/Boards/Simulator/Source/LvglTask.cpp +++ b/Boards/Simulator/Source/LvglTask.cpp @@ -41,8 +41,8 @@ bool lvgl_task_is_running() { return result; } -static bool lvgl_lock(uint32_t timeout_ticks) { - return lvgl_mutex.acquire(timeout_ticks) == tt::TtStatusOk; +static bool lvgl_lock(uint32_t timeoutMillis) { + return lvgl_mutex.acquire(pdMS_TO_TICKS(timeoutMillis)) == tt::TtStatusOk; } static void lvgl_unlock() { diff --git a/Documentation/ideas.md b/Documentation/ideas.md index ab48ed76..578a8ae5 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -1,4 +1,4 @@ -# Bugs +# Issues - WiFi bug: when pressing disconnect while between `WIFI_EVENT_STA_START` and `IP_EVENT_STA_GOT_IP`, then auto-connect becomes active again. - ESP32 (CYD) memory issues (or any device without PSRAM): - Boot app doesn't show logo @@ -11,8 +11,17 @@ - Clean up static_cast when casting to base class. - M5Stack CoreS3 SD card mounts, but cannot be read. There is currently a notice about it [here](https://github.com/espressif/esp-bsp/blob/master/bsp/m5stack_core_s3/README.md). - SD card statusbar icon shows error when there's a read timeout on the SD card status. Don't show the error icon in this scenario. +- EventFlag: Fix return value of set/get/wait (the errors are weirdly mixed in) +- getConfiguration() in TT headless is a reference, while in TT main project it's a pointer. Make it a pointer for headless too. # TODOs +- Tactility.h config: List of apps and services can be a std::vector (get rid of TT_CONFIG_SERVICES_LIMIT and TT_CONFIG_APPS_LIMIT) +- Boot hooks instead of a single boot method in config. Define different boot phases/levels in enum. +- Rename "Desktop" to "Launcher" because it more clearly communicates its purpose +- Add toggle to Display app for sysmon overlay: https://docs.lvgl.io/master/API/others/sysmon/index.html +- Mutex: Cleanup deprecated methods +- CrashHandler: use "corrupted" flag +- CrashHandler: process other types of crashes (WDT?) - Call tt::lvgl::isSyncSet after HAL init and show error (and crash?) when it is not set. - Create different partitions files for different ESP flash size targets (N4, N8, N16, N32) - Attach ELF data to wrapper app (as app data) (check that app state is "running"!) so you can run more than 1 external apps at a time. @@ -37,6 +46,8 @@ - Support hot-plugging SD card # Nice-to-haves +- OTA updates +- Web flasher - T-Deck Plus: Create separate board config? - Support for displays with different DPI. Consider the layer-based system like on Android. - Make firmwares available via web serial website diff --git a/Tactility/Source/Tactility.h b/Tactility/Source/Tactility.h index d97f1e07..12759aff 100644 --- a/Tactility/Source/Tactility.h +++ b/Tactility/Source/Tactility.h @@ -7,17 +7,23 @@ namespace tt { -typedef struct { +/** @brief The configuration for the operating system + * It contains the hardware configuration, apps and services + */ +struct Configuration { + /** HAL configuration (drivers) */ const hal::Configuration* hardware; - // List of user applications - const app::AppManifest* const apps[TT_CONFIG_APPS_LIMIT]; - const service::ServiceManifest* const services[TT_CONFIG_SERVICES_LIMIT]; - const char* autoStartAppId; -} Configuration; + /** List of user applications */ + const app::AppManifest* const apps[TT_CONFIG_APPS_LIMIT] = {}; + /** List of user services */ + const service::ServiceManifest* const services[TT_CONFIG_SERVICES_LIMIT] = {}; + /** Optional app to start automatically after the splash screen. */ + const char* _Nullable autoStartAppId = nullptr; +}; /** * Attempts to initialize Tactility and all configured hardware. - * @param config + * @param[in] config */ void run(const Configuration& config); diff --git a/Tactility/Source/app/AppContext.h b/Tactility/Source/app/AppContext.h index 238017ad..7477e051 100644 --- a/Tactility/Source/app/AppContext.h +++ b/Tactility/Source/app/AppContext.h @@ -16,8 +16,8 @@ typedef union { } Flags; /** - * A limited representation of the application instance. - * Do not store references or pointers to these! + * The public representation of an application instance. + * @warning Do not store references or pointers to these! You can retrieve them via the service registry. */ class AppContext { diff --git a/Tactility/Source/app/AppManifest.h b/Tactility/Source/app/AppManifest.h index 87ba2046..4c5e10ae 100644 --- a/Tactility/Source/app/AppManifest.h +++ b/Tactility/Source/app/AppManifest.h @@ -11,7 +11,8 @@ namespace tt::app { class AppContext; -typedef enum { +/** Application types */ +enum Type { /** Boot screen, shown before desktop is launched. */ TypeBoot, /** A desktop app sits at the root of the app stack managed by the Loader service */ @@ -24,8 +25,9 @@ typedef enum { TypeSettings, /** User-provided apps. */ TypeUser -} Type; +}; +/** Result status code for application result callback. */ typedef enum { ResultOk, ResultCancelled, @@ -39,49 +41,31 @@ typedef void (*AppOnHide)(AppContext& app); typedef void (*AppOnResult)(AppContext& app, Result result, const Bundle& resultData); struct AppManifest { - /** - * The identifier by which the app is launched by the system and other apps. - */ + /** The identifier by which the app is launched by the system and other apps. */ std::string id; - /** - * The user-readable name of the app. Used in UI. - */ + /** The user-readable name of the app. Used in UI. */ std::string name; - /** - * Optional icon. - */ + /** Optional icon. */ std::string icon = {}; - /** - * App type affects launch behaviour. - */ + /** App type affects launch behaviour. */ Type type = TypeUser; - /** - * Non-blocking method to call when app is started. - */ + /** Non-blocking method to call when app is started. */ AppOnStart onStart = nullptr; - /** - * Non-blocking method to call when app is stopped. - */ + /** Non-blocking method to call when app is stopped. */ AppOnStop _Nullable onStop = nullptr; - /** - * Non-blocking method to create the GUI - */ + /** Non-blocking method to create the GUI. */ AppOnShow _Nullable onShow = nullptr; - /** - * Non-blocking method, called before gui is destroyed - */ + /** Non-blocking method, called before gui is destroyed. */ AppOnHide _Nullable onHide = nullptr; - /** - * Handle the result for apps that are launched - */ + /** Handle the result for apps that are launched. */ AppOnResult _Nullable onResult = nullptr; }; diff --git a/Tactility/Source/app/ElfApp.cpp b/Tactility/Source/app/ElfApp.cpp index 26bec482..7447ada2 100644 --- a/Tactility/Source/app/ElfApp.cpp +++ b/Tactility/Source/app/ElfApp.cpp @@ -22,7 +22,7 @@ bool startElfApp(const std::string& filePath) { assert(elfFileData == nullptr); size_t size = 0; - elfFileData = file::readBinary(filePath.c_str(), size); + elfFileData = file::readBinary(filePath, size); if (elfFileData == nullptr) { return false; } diff --git a/Tactility/Source/app/ManifestRegistry.h b/Tactility/Source/app/ManifestRegistry.h index 72bcd3c5..86cef60d 100644 --- a/Tactility/Source/app/ManifestRegistry.h +++ b/Tactility/Source/app/ManifestRegistry.h @@ -6,8 +6,16 @@ namespace tt::app { +/** Register an application with its manifest */ void addApp(const AppManifest* manifest); + +/** Find an application manifest by its id + * @param[in] id the manifest id + * @return the application manifest if it was found + */ const AppManifest _Nullable* findAppById(const std::string& id); + +/** @return a list of all registered apps. This includes user and system apps. */ std::vector getApps(); } // namespace diff --git a/Tactility/Source/app/crashdiagnostics/QrUrl.cpp b/Tactility/Source/app/crashdiagnostics/QrUrl.cpp index b2137928..baa3eca2 100644 --- a/Tactility/Source/app/crashdiagnostics/QrUrl.cpp +++ b/Tactility/Source/app/crashdiagnostics/QrUrl.cpp @@ -9,10 +9,10 @@ #include std::string getUrlFromCrashData() { - auto* crash_data = getRtcCrashData(); - auto* stack_buffer = (uint32_t*) malloc(crash_data->callstackLength * 2 * sizeof(uint32_t)); - for (int i = 0; i < crash_data->callstackLength; ++i) { - const CallstackFrame&frame = crash_data->callstack[i]; + auto crash_data = getRtcCrashData(); + auto* stack_buffer = (uint32_t*) malloc(crash_data.callstackLength * 2 * sizeof(uint32_t)); + for (int i = 0; i < crash_data.callstackLength; ++i) { + const CallstackFrame&frame = crash_data.callstack[i]; uint32_t pc = esp_cpu_process_stack_pc(frame.pc); #if CRASH_DATA_INCLUDES_SP uint32_t sp = frame.sp; @@ -30,7 +30,7 @@ std::string getUrlFromCrashData() { stream << "&a=" << CONFIG_IDF_TARGET; // Architecture stream << "&s="; // Stacktrace - for (int i = crash_data->callstackLength - 1; i >= 0; --i) { + for (int i = crash_data.callstackLength - 1; i >= 0; --i) { uint32_t pc = stack_buffer[(i * 2)]; stream << std::hex << pc; #if CRASH_DATA_INCLUDES_SP diff --git a/Tactility/Source/lvgl/LvglSync.cpp b/Tactility/Source/lvgl/LvglSync.cpp index d09cfc1d..55dc197a 100644 --- a/Tactility/Source/lvgl/LvglSync.cpp +++ b/Tactility/Source/lvgl/LvglSync.cpp @@ -3,10 +3,10 @@ namespace tt::lvgl { -Mutex lockMutex; +static Mutex lockMutex; -static bool defaultLock(uint32_t timeoutTicks) { - return lockMutex.acquire(timeoutTicks) == TtStatusOk; +static bool defaultLock(uint32_t timeoutMillis) { + return lockMutex.acquire(timeoutMillis) == TtStatusOk; } static void defaultUnlock() { @@ -21,8 +21,8 @@ void syncSet(LvglLock lock, LvglUnlock unlock) { unlock_singleton = unlock; } -bool lock(uint32_t timeout_ticks) { - return lock_singleton(timeout_ticks); +bool lock(TickType_t timeout) { + return lock_singleton(pdMS_TO_TICKS(timeout == 0 ? portMAX_DELAY : timeout)); } void unlock() { @@ -33,7 +33,7 @@ class LvglSync : public Lockable { public: ~LvglSync() override = default; - bool lock(uint32_t timeoutTicks) const override { + bool lock(TickType_t timeoutTicks) const override { return tt::lvgl::lock(timeoutTicks); } diff --git a/Tactility/Source/lvgl/LvglSync.h b/Tactility/Source/lvgl/LvglSync.h index 5aadfa3f..bb3b144c 100644 --- a/Tactility/Source/lvgl/LvglSync.h +++ b/Tactility/Source/lvgl/LvglSync.h @@ -6,12 +6,23 @@ namespace tt::lvgl { -typedef bool (*LvglLock)(uint32_t timeout_ticks); +/** + * LVGL locking function + * @param[in] timeoutMillis timeout in milliseconds. waits forever when 0 is passed. + * @warning this works with milliseconds, as opposed to every other FreeRTOS function that works in ticks! + * @warning when passing zero, we wait forever, as this is the default behaviour for esp_lvgl_port, and we want it to remain consistent + */ +typedef bool (*LvglLock)(uint32_t timeoutMillis); typedef void (*LvglUnlock)(); void syncSet(LvglLock lock, LvglUnlock unlock); -bool isSyncSet(); -bool lock(uint32_t timeout_ticks); + +/** + * LVGL locking function + * @param[in] timeout as ticks + * @warning when passing zero, we wait forever, as this is the default behaviour for esp_lvgl_port, and we want it to remain consistent + */ +bool lock(TickType_t timeout); void unlock(); std::shared_ptr getLvglSyncLockable(); diff --git a/Tactility/Source/service/gui/Gui.h b/Tactility/Source/service/gui/Gui.h index a7dffe24..54b38fb3 100644 --- a/Tactility/Source/service/gui/Gui.h +++ b/Tactility/Source/service/gui/Gui.h @@ -9,12 +9,11 @@ typedef struct Gui Gui; /** * Set the app viewport in the gui state and request the gui to draw it. - * - * @param app - * @param on_show - * @param on_hide + * @param[in] app + * @param[in] onShow + * @param[in] onHide */ -void showApp(app::AppContext& app, ViewPortShowCallback on_show, ViewPortHideCallback on_hide); +void showApp(app::AppContext& app, ViewPortShowCallback onShow, ViewPortHideCallback onHide); /** * Hide the current app's viewport. @@ -25,7 +24,7 @@ void hideApp(); /** * Show the on-screen keyboard. - * @param textarea the textarea to focus the input for + * @param[in] textarea the textarea to focus the input for */ void keyboardShow(lv_obj_t* textarea); @@ -47,7 +46,7 @@ bool keyboardIsEnabled(); * Glue code for the on-screen keyboard and the hardware keyboard: * - Attach automatic hide/show parameters for the on-screen keyboard. * - Registers the textarea to the default lv_group_t for hardware keyboards. - * @param textarea + * @param[in] textarea */ void keyboardAddTextArea(lv_obj_t* textarea); diff --git a/Tactility/Source/service/gui/ViewPort.h b/Tactility/Source/service/gui/ViewPort.h index 4c1d22b5..7721e0ea 100644 --- a/Tactility/Source/service/gui/ViewPort.h +++ b/Tactility/Source/service/gui/ViewPort.h @@ -26,26 +26,22 @@ typedef struct ViewPort { } ViewPort; /** ViewPort allocator - * * always returns view_port or stops system if not enough memory. * @param app - * @param on_show Called to create LVGL widgets - * @param on_hide Called before clearing the LVGL widget parent - * - * @return ViewPort instance + * @param onShow Called to create LVGL widgets + * @param onHide Called before clearing the LVGL widget parent + * @return ViewPort instance */ ViewPort* view_port_alloc( app::AppContext& app, - ViewPortShowCallback on_show, - ViewPortHideCallback on_hide + ViewPortShowCallback onShow, + ViewPortHideCallback onHide ); -/** ViewPort deallocator - * +/** ViewPort destruction * Ensure that view_port was unregistered in GUI system before use. - * - * @param view_port ViewPort instance + * @param viewPort ViewPort instance */ -void view_port_free(ViewPort* view_port); +void view_port_free(ViewPort* viewPort); } // namespace diff --git a/Tactility/Source/service/loader/Loader.h b/Tactility/Source/service/loader/Loader.h index 1a75311e..02866449 100644 --- a/Tactility/Source/service/loader/Loader.h +++ b/Tactility/Source/service/loader/Loader.h @@ -26,11 +26,10 @@ typedef enum { */ void startApp(const std::string& id, bool blocking = false, std::shared_ptr _Nullable parameters = nullptr); -/** - * @brief Stop the currently showing app. Show the previous app if any app was still running. - */ +/** @brief Stop the currently showing app. Show the previous app if any app was still running. */ void stopApp(); +/** @return the currently running app (it is only ever null before the splash screen is shown) */ app::AppContext* _Nullable getCurrentApp(); /** diff --git a/Tactility/Source/service/screenshot/Screenshot.cpp b/Tactility/Source/service/screenshot/Screenshot.cpp index 8d1ef97f..17af25b5 100644 --- a/Tactility/Source/service/screenshot/Screenshot.cpp +++ b/Tactility/Source/service/screenshot/Screenshot.cpp @@ -39,7 +39,7 @@ void ScreenshotService::startApps(const char* path) { } } -void ScreenshotService::startTimed(const char* path, uint8_t delay_in_seconds, uint8_t amount) { +void ScreenshotService::startTimed(const char* path, uint8_t delayInSeconds, uint8_t amount) { auto scoped_lockable = mutex.scoped(); if (!scoped_lockable->lock(50 / portTICK_PERIOD_MS)) { TT_LOG_W(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED); @@ -49,7 +49,7 @@ void ScreenshotService::startTimed(const char* path, uint8_t delay_in_seconds, u if (task == nullptr || task->isFinished()) { task = std::make_unique(); mode = ScreenshotModeTimed; - task->startTimed(path, delay_in_seconds, amount); + task->startTimed(path, delayInSeconds, amount); } else { TT_LOG_W(TAG, "Screenshot task already running"); } diff --git a/Tactility/Source/service/screenshot/Screenshot.h b/Tactility/Source/service/screenshot/Screenshot.h index b1ca5a8c..c3418f88 100644 --- a/Tactility/Source/service/screenshot/Screenshot.h +++ b/Tactility/Source/service/screenshot/Screenshot.h @@ -16,8 +16,10 @@ typedef enum { ScreenshotModeApps } Mode; - class ScreenshotService { + +private: + Mutex mutex; std::unique_ptr task; Mode mode = ScreenshotModeNone; @@ -25,9 +27,23 @@ class ScreenshotService { public: bool isTaskStarted(); + + /** The state of the service. */ Mode getMode(); + + /** @brief Start taking screenshot whenever an app is started + * @param[in] path the path to store the screenshots at + */ void startApps(const char* path); - void startTimed(const char* path, uint8_t delay_in_seconds, uint8_t amount); + + /** @brief Start taking screenshots after a certain delay + * @param[in] path the path to store the screenshots at + * @param[in] delayInSeconds the delay before starting (and between successive screenshots) + * @param[in] amount 0 = indefinite, >0 for a specific + */ + void startTimed(const char* path, uint8_t delayInSeconds, uint8_t amount); + + /** @brief Stop taking screenshots */ void stop(); }; diff --git a/Tactility/Source/service/screenshot/ScreenshotTask.h b/Tactility/Source/service/screenshot/ScreenshotTask.h index 5fbd2d12..3683a008 100644 --- a/Tactility/Source/service/screenshot/ScreenshotTask.h +++ b/Tactility/Source/service/screenshot/ScreenshotTask.h @@ -35,22 +35,18 @@ public: ~ScreenshotTask(); /** @brief Start taking screenshots after a certain delay - * @param task the screenshot task - * @param path the path to store the screenshots at - * @param delay_in_seconds the delay before starting (and between successive screenshots) - * @param amount 0 = indefinite, >0 for a specific + * @param[in] path the path to store the screenshots at + * @param[in] delayInSeconds the delay before starting (and between successive screenshots) + * @param[in] amount 0 = indefinite, >0 for a specific */ - void startTimed(const char* path, uint8_t delay_in_seconds, uint8_t amount); + void startTimed(const char* path, uint8_t delayInSeconds, uint8_t amount); /** @brief Start taking screenshot whenever an app is started - * @param task the screenshot task - * @param path the path to store the screenshots at + * @param[in] path the path to store the screenshots at */ void startApps(const char* path); - /** @brief Stop taking screenshots - * @param task the screenshot task - */ + /** @brief Stop taking screenshots */ void stop(); void taskMain(); diff --git a/TactilityC/Source/tt_message_queue.cpp b/TactilityC/Source/tt_message_queue.cpp index 814cbd2f..80d2867f 100644 --- a/TactilityC/Source/tt_message_queue.cpp +++ b/TactilityC/Source/tt_message_queue.cpp @@ -13,11 +13,11 @@ void tt_message_queue_free(MessageQueueHandle handle) { delete HANDLE_TO_MESSAGE_QUEUE(handle); } -bool tt_message_queue_put(MessageQueueHandle handle, const void* message, uint32_t timeout) { +bool tt_message_queue_put(MessageQueueHandle handle, const void* message, TickType_t timeout) { return HANDLE_TO_MESSAGE_QUEUE(handle)->put(message, timeout); } -bool tt_message_queue_get(MessageQueueHandle handle, void* message, uint32_t timeout) { +bool tt_message_queue_get(MessageQueueHandle handle, void* message, TickType_t timeout) { return HANDLE_TO_MESSAGE_QUEUE(handle)->get(message, timeout); } diff --git a/TactilityC/Source/tt_message_queue.h b/TactilityC/Source/tt_message_queue.h index c0aac3cf..53f92841 100644 --- a/TactilityC/Source/tt_message_queue.h +++ b/TactilityC/Source/tt_message_queue.h @@ -1,5 +1,7 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif @@ -11,8 +13,8 @@ typedef void* MessageQueueHandle; MessageQueueHandle tt_message_queue_alloc(uint32_t capacity, uint32_t messageSize); void tt_message_queue_free(MessageQueueHandle handle); -bool tt_message_queue_put(MessageQueueHandle handle, const void* message, uint32_t timeout); -bool tt_message_queue_get(MessageQueueHandle handle, void* message, uint32_t timeout); +bool tt_message_queue_put(MessageQueueHandle handle, const void* message, TickType_t timeout); +bool tt_message_queue_get(MessageQueueHandle handle, void* message, TickType_t timeout); uint32_t tt_message_queue_get_capacity(MessageQueueHandle handle); uint32_t tt_message_queue_get_message_size(MessageQueueHandle handle); uint32_t tt_message_queue_get_count(MessageQueueHandle handle); diff --git a/TactilityC/Source/tt_mutex.cpp b/TactilityC/Source/tt_mutex.cpp index 82a00450..119412e7 100644 --- a/TactilityC/Source/tt_mutex.cpp +++ b/TactilityC/Source/tt_mutex.cpp @@ -20,8 +20,8 @@ void tt_mutex_free(MutexHandle handle) { delete HANDLE_AS_MUTEX(handle); } -bool tt_mutex_lock(MutexHandle handle, uint32_t timeoutTicks) { - return HANDLE_AS_MUTEX(handle)->lock(timeoutTicks); +bool tt_mutex_lock(MutexHandle handle, TickType_t timeout) { + return HANDLE_AS_MUTEX(handle)->lock((TickType_t)timeout); } bool tt_mutex_unlock(MutexHandle handle) { diff --git a/TactilityC/Source/tt_mutex.h b/TactilityC/Source/tt_mutex.h index b4c69c22..8f4b8e4e 100644 --- a/TactilityC/Source/tt_mutex.h +++ b/TactilityC/Source/tt_mutex.h @@ -1,5 +1,7 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif @@ -16,7 +18,7 @@ enum TtMutexType { MutexHandle tt_mutex_alloc(enum TtMutexType); void tt_mutex_free(MutexHandle handle); -bool tt_mutex_lock(MutexHandle handle, uint32_t timeoutTicks); +bool tt_mutex_lock(MutexHandle handle, TickType_t timeoutTicks); bool tt_mutex_unlock(MutexHandle handle); #ifdef __cplusplus diff --git a/TactilityC/Source/tt_semaphore.cpp b/TactilityC/Source/tt_semaphore.cpp index 8921267a..405bf712 100644 --- a/TactilityC/Source/tt_semaphore.cpp +++ b/TactilityC/Source/tt_semaphore.cpp @@ -5,7 +5,7 @@ extern "C" { #define HANDLE_AS_SEMAPHORE(handle) ((tt::Semaphore*)(handle)) -SemaphoreHandle tt_semaphore_alloc(uint32_t maxCount, uint32_t initialCount) { +SemaphoreHandle tt_semaphore_alloc(uint32_t maxCount, TickType_t initialCount) { return new tt::Semaphore(maxCount, initialCount); } @@ -13,7 +13,7 @@ void tt_semaphore_free(SemaphoreHandle handle) { delete HANDLE_AS_SEMAPHORE(handle); } -bool tt_semaphore_acquire(SemaphoreHandle handle, uint32_t timeoutTicks) { +bool tt_semaphore_acquire(SemaphoreHandle handle, TickType_t timeoutTicks) { return HANDLE_AS_SEMAPHORE(handle)->acquire(timeoutTicks); } diff --git a/TactilityC/Source/tt_semaphore.h b/TactilityC/Source/tt_semaphore.h index 1958a0aa..0f3dd607 100644 --- a/TactilityC/Source/tt_semaphore.h +++ b/TactilityC/Source/tt_semaphore.h @@ -1,5 +1,7 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif @@ -9,9 +11,9 @@ extern "C" { typedef void* SemaphoreHandle; -SemaphoreHandle tt_semaphore_alloc(uint32_t maxCount, uint32_t initialCount); +SemaphoreHandle tt_semaphore_alloc(uint32_t maxCount, TickType_t initialCount); void tt_semaphore_free(SemaphoreHandle handle); -bool tt_semaphore_acquire(SemaphoreHandle handle, uint32_t timeoutTicks); +bool tt_semaphore_acquire(SemaphoreHandle handle, TickType_t timeoutTicks); bool tt_semaphore_release(SemaphoreHandle handle); uint32_t tt_semaphore_get_count(SemaphoreHandle handle); diff --git a/TactilityC/Source/tt_timer.cpp b/TactilityC/Source/tt_timer.cpp index a593c570..533eb585 100644 --- a/TactilityC/Source/tt_timer.cpp +++ b/TactilityC/Source/tt_timer.cpp @@ -29,11 +29,11 @@ void tt_timer_free(TimerHandle handle) { delete wrapper; } -bool tt_timer_start(TimerHandle handle, uint32_t intervalTicks) { +bool tt_timer_start(TimerHandle handle, TickType_t intervalTicks) { return ((TimerWrapper*)handle)->timer->start(intervalTicks); } -bool tt_timer_restart(TimerHandle handle, uint32_t intervalTicks) { +bool tt_timer_restart(TimerHandle handle, TickType_t intervalTicks) { return ((TimerWrapper*)handle)->timer->restart(intervalTicks); } @@ -49,11 +49,12 @@ uint32_t tt_timer_get_expire_time(TimerHandle handle) { return ((TimerWrapper*)handle)->timer->getExpireTime(); } -bool tt_timer_set_pending_callback(TimerHandle handle, TimerPendingCallback callback, void* callbackContext, uint32_t arg) { +bool tt_timer_set_pending_callback(TimerHandle handle, TimerPendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeoutTicks) { return ((TimerWrapper*)handle)->timer->setPendingCallback( callback, callbackContext, - arg + callbackArg, + (TickType_t)timeoutTicks ); } diff --git a/TactilityC/Source/tt_timer.h b/TactilityC/Source/tt_timer.h index eba26d30..15b79047 100644 --- a/TactilityC/Source/tt_timer.h +++ b/TactilityC/Source/tt_timer.h @@ -1,5 +1,7 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif @@ -24,12 +26,12 @@ typedef void (*TimerPendingCallback)(void* context, uint32_t arg); TimerHandle tt_timer_alloc(TimerType type, TimerCallback callback, void* callbackContext); void tt_timer_free(TimerHandle handle); -bool tt_timer_start(TimerHandle handle, uint32_t intervalTicks); -bool tt_timer_restart(TimerHandle handle, uint32_t intervalTicks); +bool tt_timer_start(TimerHandle handle, TickType_t intervalTicks); +bool tt_timer_restart(TimerHandle handle, TickType_t intervalTicks); bool tt_timer_stop(TimerHandle handle); bool tt_timer_is_running(TimerHandle handle); uint32_t tt_timer_get_expire_time(TimerHandle handle); -bool tt_timer_set_pending_callback(TimerHandle handle, TimerPendingCallback callback, void* callbackContext, uint32_t arg); +bool tt_timer_set_pending_callback(TimerHandle handle, TimerPendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeoutTicks); void tt_timer_set_thread_priority(TimerHandle handle, TimerThreadPriority priority); #ifdef __cplusplus diff --git a/TactilityCore/Source/Bundle.h b/TactilityCore/Source/Bundle.h index 7fc6ddb1..d0789dc9 100644 --- a/TactilityCore/Source/Bundle.h +++ b/TactilityCore/Source/Bundle.h @@ -10,6 +10,9 @@ namespace tt { +/** + * A dictionary that maps keys (strings) onto several atomary types. + */ class Bundle { private: diff --git a/TactilityCore/Source/Check.h b/TactilityCore/Source/Check.h index 1354b372..e347f0a7 100644 --- a/TactilityCore/Source/Check.h +++ b/TactilityCore/Source/Check.h @@ -40,9 +40,8 @@ namespace tt { tt::_crash(); \ } while (0) -/** Halt system - * - * @param optional message (const char*) +/** Halt the system + * @param[in] optional message (const char*) */ #define tt_halt(...) M_APPLY(__tt_halt, M_IF_EMPTY(__VA_ARGS__)((NULL), (__VA_ARGS__))) @@ -61,8 +60,8 @@ namespace tt { /** Check condition and crash if failed * - * @param condition to check - * @param optional message (const char*) + * @param[in] condition to check + * @param[in] optional message (const char*) */ #define tt_check(x, ...) if (!(x)) { TT_LOG_E("check", "Failed: %s", #x); tt::_crash(); } @@ -89,10 +88,7 @@ namespace tt { #endif /** Assert condition and crash if failed - * - * @warning only will do check if firmware compiled in debug mode - * - * @param condition to check - * @param optional message (const char*) + * @warning only will do check if firmware compiled in debug mode + * @param[in] condition to check */ #define tt_assert(expression) assert(expression) diff --git a/TactilityCore/Source/CoreDefines.h b/TactilityCore/Source/CoreDefines.h index eefd6b63..f8313cf2 100644 --- a/TactilityCore/Source/CoreDefines.h +++ b/TactilityCore/Source/CoreDefines.h @@ -45,5 +45,3 @@ #define _TT_ARGCOUNT4(X,...) _TT_ARGCOUNT ## __VA_OPT__(5(__VA_ARGS__) TT_ARG_IGNORE) (4) #define _TT_ARGCOUNT5(X,...) 5 #define _TT_ARGCOUNT(X) X - -// endregion \ No newline at end of file diff --git a/TactilityCore/Source/CoreExtraDefines.h b/TactilityCore/Source/CoreExtraDefines.h index 2132b4e4..eb0759ca 100644 --- a/TactilityCore/Source/CoreExtraDefines.h +++ b/TactilityCore/Source/CoreExtraDefines.h @@ -1,5 +1,10 @@ #pragma once +/** Find the largest value + * @param[in] a first value to compare + * @param[in] b second value to compare + * @return the largest value of a and b + */ #define TT_MAX(a, b) \ ({ \ __typeof__(a) _a = (a); \ @@ -7,6 +12,11 @@ _a > _b ? _a : _b; \ }) +/** Find the smallest value + * @param[in] a first value to compare + * @param[in] b second value to compare + * @return the smallest value of a and b + */ #define TT_MIN(a, b) \ ({ \ __typeof__(a) _a = (a); \ @@ -14,49 +24,12 @@ _a < _b ? _a : _b; \ }) +/** @return the absolute value of the input */ #define TT_ABS(a) ({ (a) < 0 ? -(a) : (a); }) -#define TT_ROUND_UP_TO(a, b) \ - ({ \ - __typeof__(a) _a = (a); \ - __typeof__(b) _b = (b); \ - _a / _b + !!(_a % _b); \ - }) - +/** Clamp a value between a min and a max. + * @param[in] x value to clamp + * @param[in] upper upper bounds for x + * @param[in] lower lower bounds for x + */ #define TT_CLAMP(x, upper, lower) (TT_MIN(upper, TT_MAX(x, lower))) - -#define TT_COUNT_OF(x) (sizeof(x) / sizeof(x[0])) - -#define TT_SWAP(x, y) \ - do { \ - typeof(x) SWAP = x; \ - x = y; \ - y = SWAP; \ - } while (0) - -#define TT_STRINGIFY(x) #x - -#define TT_TOSTRING(x) TT_STRINGIFY(x) - -#define TT_CONCATENATE(a, b) CONCATENATE_(a, b) -#define TT_CONCATENATE_(a, b) a##b - -#define TT_REVERSE_BYTES_U32(x) \ - ((((x) & 0x000000FF) << 24) | (((x) & 0x0000FF00) << 8) | (((x) & 0x00FF0000) >> 8) | \ - (((x) & 0xFF000000) >> 24)) - -#define TT_BIT(x, n) (((x) >> (n)) & 1) - -#define TT_BIT_SET(x, n) \ - ({ \ - __typeof__(x) _x = (1); \ - (x) |= (_x << (n)); \ - }) - -#define TT_BIT_CLEAR(x, n) \ - ({ \ - __typeof__(x) _x = (1); \ - (x) &= ~(_x << (n)); \ - }) - -#define TT_SW_MEMBARRIER() asm volatile("" : : : "memory") diff --git a/TactilityCore/Source/Dispatcher.cpp b/TactilityCore/Source/Dispatcher.cpp index eb1295bb..34e3d36d 100644 --- a/TactilityCore/Source/Dispatcher.cpp +++ b/TactilityCore/Source/Dispatcher.cpp @@ -18,8 +18,8 @@ Dispatcher::~Dispatcher() { mutex.release(); } -void Dispatcher::dispatch(Callback callback, std::shared_ptr context) { - auto message = std::make_shared(callback, std::move(context)); +void Dispatcher::dispatch(Function function, std::shared_ptr context) { + auto message = std::make_shared(function, std::move(context)); // Mutate if (mutex.lock(1000 / portTICK_PERIOD_MS)) { queue.push(std::move(message)); @@ -34,16 +34,16 @@ void Dispatcher::dispatch(Callback callback, std::shared_ptr context) { } } -uint32_t Dispatcher::consume(uint32_t timeout_ticks) { +uint32_t Dispatcher::consume(TickType_t timeout) { // Wait for signal and clear TickType_t start_ticks = kernel::getTicks(); - if (eventFlag.wait(WAIT_FLAG, TtFlagWaitAny, timeout_ticks) == WAIT_FLAG) { + if (eventFlag.wait(WAIT_FLAG, TtFlagWaitAny, timeout) == WAIT_FLAG) { eventFlag.clear(WAIT_FLAG); } else { return 0; } - TickType_t ticks_remaining = TT_MAX(timeout_ticks - (kernel::getTicks() - start_ticks), 0); + TickType_t ticks_remaining = TT_MAX(timeout - (kernel::getTicks() - start_ticks), 0); TT_LOG_I(TAG, "Dispatcher continuing (%d ticks)", (int)ticks_remaining); @@ -59,7 +59,7 @@ uint32_t Dispatcher::consume(uint32_t timeout_ticks) { processing = !queue.empty(); // Don't keep lock as callback might be slow tt_check(mutex.unlock()); - item->callback(item->context); + item->function(item->context); } else { processing = false; tt_check(mutex.unlock()); diff --git a/TactilityCore/Source/Dispatcher.h b/TactilityCore/Source/Dispatcher.h index 522674f4..b83920b6 100644 --- a/TactilityCore/Source/Dispatcher.h +++ b/TactilityCore/Source/Dispatcher.h @@ -13,16 +13,24 @@ namespace tt { -typedef void (*Callback)(std::shared_ptr data); +/** + * A thread-safe way to defer code execution. + * Generally, one task would dispatch the execution, + * while the other thread consumes and executes the work. + */ class Dispatcher { +public: + + typedef void (*Function)(std::shared_ptr data); + private: struct DispatcherMessage { - Callback callback; + Function function; std::shared_ptr context; // Can't use unique_ptr with void, so we use shared_ptr - DispatcherMessage(Callback callback, std::shared_ptr context) : - callback(callback), + DispatcherMessage(Function function, std::shared_ptr context) : + function(function), context(std::move(context)) {} @@ -38,8 +46,19 @@ public: explicit Dispatcher(); ~Dispatcher(); - void dispatch(Callback callback, std::shared_ptr context); - uint32_t consume(uint32_t timeout_ticks); + /** + * Queue a function to be consumed elsewhere. + * @param[in] function the function to execute elsewhere + * @param[in] context the data to pass onto the function + */ + void dispatch(Function function, std::shared_ptr context); + + /** + * Consume a dispatched function (if any) + * @param[in] timeout the ticks to wait for a message + * @return the amount of messages that were consumed + */ + uint32_t consume(TickType_t timeout); }; } // namespace diff --git a/TactilityCore/Source/DispatcherThread.cpp b/TactilityCore/Source/DispatcherThread.cpp index ed59f93e..09f92f5a 100644 --- a/TactilityCore/Source/DispatcherThread.cpp +++ b/TactilityCore/Source/DispatcherThread.cpp @@ -29,8 +29,8 @@ void DispatcherThread::_threadMain() { } while (!interruptThread); } -void DispatcherThread::dispatch(Callback callback, std::shared_ptr context) { - dispatcher.dispatch(callback, std::move(context)); +void DispatcherThread::dispatch(Dispatcher::Function function, std::shared_ptr context) { + dispatcher.dispatch(function, std::move(context)); } void DispatcherThread::start() { diff --git a/TactilityCore/Source/DispatcherThread.h b/TactilityCore/Source/DispatcherThread.h index 76499b96..e653b8e4 100644 --- a/TactilityCore/Source/DispatcherThread.h +++ b/TactilityCore/Source/DispatcherThread.h @@ -19,7 +19,7 @@ public: /** * Dispatch a message. */ - void dispatch(Callback callback, std::shared_ptr context); + void dispatch(Dispatcher::Function function, std::shared_ptr context); /** Start the thread (blocking). */ void start(); diff --git a/TactilityCore/Source/Lockable.h b/TactilityCore/Source/Lockable.h index 07b7c53c..f5d73f6e 100644 --- a/TactilityCore/Source/Lockable.h +++ b/TactilityCore/Source/Lockable.h @@ -1,22 +1,32 @@ #pragma once #include "Check.h" +#include "RtosCompat.h" #include namespace tt { class ScopedLockableUsage; +/** Represents a lock/mutex */ class Lockable { public: virtual ~Lockable() = default; - virtual bool lock(uint32_t timeoutTicks) const = 0; + virtual bool lock(TickType_t timeoutTicks) const = 0; + virtual bool unlock() const = 0; std::unique_ptr scoped() const; }; +/** + * Represents a lockable instance that is scoped to a specific lifecycle. + * Once the ScopedLockableUsage is destroyed, unlock() is called automatically. + * + * In other words: + * You have to lock() this object manually, but unlock() happens automatically on destruction. + */ class ScopedLockableUsage final : public Lockable { const Lockable& lockable; @@ -29,7 +39,7 @@ public: lockable.unlock(); // We don't care whether it succeeded or not } - bool lock(uint32_t timeout) const override { + bool lock(TickType_t timeout) const override { return lockable.lock(timeout); } diff --git a/TactilityCore/Source/Log.h b/TactilityCore/Source/Log.h index be5b5650..d87ee2bf 100644 --- a/TactilityCore/Source/Log.h +++ b/TactilityCore/Source/Log.h @@ -12,6 +12,7 @@ namespace tt { +/** Used for log output filtering */ enum LogLevel { LogLevelNone, /*!< No log output */ LogLevelError, /*!< Critical errors, software module can not recover on its own */ @@ -26,6 +27,10 @@ struct LogEntry { char message[TT_LOG_MESSAGE_SIZE] = { 0 }; }; +/** Make a copy of the currently stored entries. + * The array size is TT_LOG_ENTRY_COUNT + * @param[out] outIndex the write index for the next log entry. + */ LogEntry* copyLogEntries(unsigned int& outIndex); } // namespace tt diff --git a/TactilityCore/Source/MessageQueue.cpp b/TactilityCore/Source/MessageQueue.cpp index 1cb8767e..505bef12 100644 --- a/TactilityCore/Source/MessageQueue.cpp +++ b/TactilityCore/Source/MessageQueue.cpp @@ -5,13 +5,13 @@ namespace tt { MessageQueue::MessageQueue(uint32_t capacity, uint32_t msg_size) { - tt_assert((kernel::isIrq() == 0U) && (capacity > 0U) && (msg_size > 0U)); + tt_assert(!TT_IS_ISR() && (capacity > 0U) && (msg_size > 0U)); queue_handle = xQueueCreate(capacity, msg_size); tt_check(queue_handle); } MessageQueue::~MessageQueue() { - tt_assert(kernel::isIrq() == 0U); + tt_assert(!TT_IS_ISR()); vQueueDelete(queue_handle); } @@ -19,7 +19,7 @@ bool MessageQueue::put(const void* message, uint32_t timeout) { bool result = true; BaseType_t yield; - if (kernel::isIrq() != 0U) { + if (TT_IS_ISR()) { if ((queue_handle == nullptr) || (message == nullptr) || (timeout != 0U)) { result = false; } else { @@ -45,7 +45,7 @@ bool MessageQueue::get(void* msg_ptr, uint32_t timeout_ticks) { BaseType_t yield; - if (kernel::isIrq()) { + if (TT_IS_ISR()) { if ((queue_handle == nullptr) || (msg_ptr == nullptr) || (timeout_ticks != 0U)) { result = false; } else { @@ -91,7 +91,7 @@ uint32_t MessageQueue::getCount() const { if (queue_handle == nullptr) { count = 0U; - } else if (kernel::isIrq() != 0U) { + } else if (TT_IS_ISR()) { count = uxQueueMessagesWaitingFromISR(queue_handle); } else { count = uxQueueMessagesWaiting(queue_handle); @@ -108,7 +108,7 @@ uint32_t MessageQueue::getSpace() const { if (mq == nullptr) { space = 0U; - } else if (kernel::isIrq() != 0U) { + } else if (TT_IS_ISR()) { isrm = taskENTER_CRITICAL_FROM_ISR(); /* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */ @@ -123,7 +123,7 @@ uint32_t MessageQueue::getSpace() const { } bool MessageQueue::reset() { - tt_check(!kernel::isIrq()); + tt_check(!TT_IS_ISR()); if (queue_handle == nullptr) { return false; } else { diff --git a/TactilityCore/Source/MessageQueue.h b/TactilityCore/Source/MessageQueue.h index 8bbe7a32..2018f1c7 100644 --- a/TactilityCore/Source/MessageQueue.h +++ b/TactilityCore/Source/MessageQueue.h @@ -36,7 +36,8 @@ public: ~MessageQueue(); - /** Put message into queue + /** Post a message to the queue. + * The message is queued by copy, not by reference. * @param[in] message A pointer to a message. The message will be copied into a buffer. * @param[in] timeoutTicks * @return success result @@ -44,7 +45,7 @@ public: bool put(const void* message, uint32_t timeoutTicks); /** Get message from queue - * @param message A pointer to an already allocated message object + * @param[out] message A pointer to an already allocated message object * @param[in] timeoutTicks * @return success result */ diff --git a/TactilityCore/Source/Mutex.cpp b/TactilityCore/Source/Mutex.cpp index 392f736c..031ecabc 100644 --- a/TactilityCore/Source/Mutex.cpp +++ b/TactilityCore/Source/Mutex.cpp @@ -44,7 +44,7 @@ Mutex::~Mutex() { semaphore = nullptr; // If the mutex is used after release, this might help debugging } -TtStatus Mutex::acquire(uint32_t timeout) const { +TtStatus Mutex::acquire(TickType_t timeout) const { tt_assert(!TT_IS_IRQ_MODE()); tt_assert(semaphore); @@ -114,7 +114,7 @@ void tt_mutex_free(Mutex* mutex) { delete mutex; } -TtStatus tt_mutex_acquire(Mutex* mutex, uint32_t timeout) { +TtStatus tt_mutex_acquire(Mutex* mutex, TickType_t timeout) { return mutex-> acquire(timeout); } diff --git a/TactilityCore/Source/Mutex.h b/TactilityCore/Source/Mutex.h index 030650fc..a7410637 100644 --- a/TactilityCore/Source/Mutex.h +++ b/TactilityCore/Source/Mutex.h @@ -13,8 +13,6 @@ namespace tt { -class ScopedMutexUsage; - /** * Wrapper for FreeRTOS xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex * Can be used in IRQ mode (within ISR context) @@ -38,56 +36,64 @@ public: explicit Mutex(Type type = TypeNormal); ~Mutex() override; - TtStatus acquire(uint32_t timeoutTicks) const; + /** Attempt to lock the mutex. Blocks until timeout passes or lock is acquired. + * @param[in] timeout + * @return status result + */ + TtStatus acquire(TickType_t timeout) const; + + /** Attempt to unlock the mutex. + * @return status result + */ TtStatus release() const; - bool lock(uint32_t timeoutTicks) const override { return acquire(timeoutTicks) == TtStatusOk; } + /** Attempt to lock the mutex. Blocks until timeout passes or lock is acquired. + * @param[in] timeout + * @return success result + */ + bool lock(TickType_t timeout) const override { return acquire(timeout) == TtStatusOk; } + + /** Attempt to unlock the mutex. + * @return success result + */ bool unlock() const override { return release() == TtStatusOk; } + /** @return the owner of the thread */ ThreadId getOwner() const; }; /** Allocate Mutex - * - * @param[in] type The mutex type - * - * @return pointer to Mutex instance + * @param[in] type The mutex type + * @return pointer to Mutex instance */ [[deprecated("use class")]] Mutex* tt_mutex_alloc(Mutex::Type type); /** Free Mutex - * - * @param mutex The Mutex instance + * @param[in] mutex The Mutex instance */ [[deprecated("use class")]] void tt_mutex_free(Mutex* mutex); /** Acquire mutex - * - * @param mutex The Mutex instance - * @param[in] timeout The timeout - * - * @return The status. + * @param[in] mutex + * @param[in] timeout + * @return the status result */ [[deprecated("use class")]] -TtStatus tt_mutex_acquire(Mutex* mutex, uint32_t timeout); +TtStatus tt_mutex_acquire(Mutex* mutex, TickType_t timeout); /** Release mutex - * - * @param mutex The Mutex instance - * - * @return The status. + * @param[in] mutex The Mutex instance + * @return the status result */ [[deprecated("use class")]] TtStatus tt_mutex_release(Mutex* mutex); /** Get mutex owner thread id - * - * @param mutex The Mutex instance - * - * @return The thread identifier. + * @param[in] mutex The Mutex instance + * @return The thread identifier. */ [[deprecated("use class")]] ThreadId tt_mutex_get_owner(Mutex* mutex); diff --git a/TactilityCore/Source/Pubsub.cpp b/TactilityCore/Source/Pubsub.cpp index 49ecd68b..62f83072 100644 --- a/TactilityCore/Source/Pubsub.cpp +++ b/TactilityCore/Source/Pubsub.cpp @@ -3,12 +3,12 @@ namespace tt { -PubSubSubscription* tt_pubsub_subscribe(std::shared_ptr pubsub, PubSubCallback callback, void* callback_context) { +PubSubSubscription* tt_pubsub_subscribe(std::shared_ptr pubsub, PubSubCallback callback, void* callbackContext) { tt_check(pubsub->mutex.acquire(TtWaitForever) == TtStatusOk); PubSubSubscription subscription = { .id = (++pubsub->last_id), .callback = callback, - .callback_context = callback_context + .callback_context = callbackContext }; pubsub->items.push_back( subscription diff --git a/TactilityCore/Source/Pubsub.h b/TactilityCore/Source/Pubsub.h index 134e892c..80314beb 100644 --- a/TactilityCore/Source/Pubsub.h +++ b/TactilityCore/Source/Pubsub.h @@ -30,34 +30,27 @@ struct PubSub { }; /** Subscribe to PubSub - * * Threadsafe, Reentrable - * - * @param pubsub pointer to PubSub instance - * @param[in] callback The callback - * @param callback_context The callback context - * - * @return pointer to PubSubSubscription instance + * @param[in] pubsub pointer to PubSub instance + * @param[in] callback + * @param[in] callbackContext the data to pass to the callback + * @return subscription instance */ PubSubSubscription* -tt_pubsub_subscribe(std::shared_ptr pubsub, PubSubCallback callback, void* callback_context); +tt_pubsub_subscribe(std::shared_ptr pubsub, PubSubCallback callback, void* callbackContext); /** Unsubscribe from PubSub - * - * No use of `pubsub_subscription` allowed after call of this method - * Threadsafe, Reentrable. - * - * @param pubsub pointer to PubSub instance - * @param pubsub_subscription pointer to PubSubSubscription instance + * No use of `tt_pubsub_subscription` allowed after call of this method + * Threadsafe, Re-entrable. + * @param[in] pubsub + * @param[in] subscription */ -void tt_pubsub_unsubscribe(std::shared_ptr pubsub, PubSubSubscription* pubsub_subscription); +void tt_pubsub_unsubscribe(std::shared_ptr pubsub, PubSubSubscription* subscription); /** Publish message to PubSub - * * Threadsafe, Reentrable. - * - * @param pubsub pointer to PubSub instance - * @param message message pointer to publish + * @param[in] pubsub + * @param[in] message message pointer to publish - it is passed as-is to the callback */ void tt_pubsub_publish(std::shared_ptr pubsub, void* message); diff --git a/TactilityCore/Source/StreamBuffer.h b/TactilityCore/Source/StreamBuffer.h index 94caf2eb..3d2db7ae 100644 --- a/TactilityCore/Source/StreamBuffer.h +++ b/TactilityCore/Source/StreamBuffer.h @@ -35,8 +35,8 @@ public: * interrupt that will write to the buffer (the writer), and only one task or * interrupt that will read from the buffer (the reader). * - * @param size The total number of bytes the stream buffer will be able to hold at any one time. - * @param triggerLevel The number of bytes that must be in the stream buffer + * @param[in] size The total number of bytes the stream buffer will be able to hold at any one time. + * @param[in] triggerLevel The number of bytes that must be in the stream buffer * before a task that is blocked on the stream buffer to wait for data is moved out of the blocked state. * @return The stream buffer instance. */ @@ -50,7 +50,7 @@ public: * stream buffer before a task that is blocked on the stream buffer to * wait for data is moved out of the blocked state. * - * @param triggerLevel The new trigger level for the stream buffer. + * @param[in] triggerLevel The new trigger level for the stream buffer. * @return true if trigger level can be be updated (new trigger level was less than or equal to the stream buffer's length). * @return false if trigger level can't be be updated (new trigger level was greater than the stream buffer's length). */ @@ -60,9 +60,9 @@ public: * @brief Sends bytes to a stream buffer. The bytes are copied into the stream buffer. * Wakes up task waiting for data to become available if called from ISR. * - * @param data A pointer to the data that is to be copied into the stream buffer. - * @param length The maximum number of bytes to copy from data into the stream buffer. - * @param timeout The maximum amount of time the task should remain in the + * @param[in] data A pointer to the data that is to be copied into the stream buffer. + * @param[in] length The maximum number of bytes to copy from data into the stream buffer. + * @param[in] timeout The maximum amount of time the task should remain in the * Blocked state to wait for space to become available if the stream buffer is full. * Will return immediately if timeout is zero. * Setting timeout to TtWaitForever will cause the task to wait indefinitely. @@ -79,10 +79,10 @@ public: * @brief Receives bytes from a stream buffer. * Wakes up task waiting for space to become available if called from ISR. * - * @param data A pointer to the buffer into which the received bytes will be + * @param[in] data A pointer to the buffer into which the received bytes will be * copied. - * @param length The length of the buffer pointed to by the data parameter. - * @param timeout The maximum amount of time the task should remain in the + * @param[in] length The length of the buffer pointed to by the data parameter. + * @param[in] timeout The maximum amount of time the task should remain in the * Blocked state to wait for data to become available if the stream buffer is empty. * Will return immediately if timeout is zero. * Setting timeout to TtWaitForever will cause the task to wait indefinitely. diff --git a/TactilityCore/Source/Thread.h b/TactilityCore/Source/Thread.h index 639c3528..b8538b8d 100644 --- a/TactilityCore/Source/Thread.h +++ b/TactilityCore/Source/Thread.h @@ -7,13 +7,7 @@ #include #include -#ifdef ESP_PLATFORM -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#else -#include "FreeRTOS.h" -#include "task.h" -#endif +#include "RtosCompatTask.h" namespace tt { @@ -47,14 +41,14 @@ public: typedef int32_t (*Callback)(void* context); /** Write to stdout callback - * @param data pointer to data - * @param size data size @warning your handler must consume everything + * @param[in] data pointer to data + * @param[in] size data size @warning your handler must consume everything */ typedef void (*StdoutWriteCallback)(const char* data, size_t size); /** Thread state change callback called upon thread state change - * @param state new thread state - * @param context callback context + * @param[in] state new thread state + * @param[in] context callback context */ typedef void (*StateCallback)(State state, void* context); @@ -85,11 +79,10 @@ public: Thread(); /** Allocate Thread, shortcut version - - * @param name - * @param stack_size - * @param callback - * @param context + * @param[in] name + * @param[in] stack_size + * @param[in] callback + * @param[in] callbackContext * @return Thread* */ Thread( @@ -102,8 +95,7 @@ public: ~Thread(); /** Set Thread name - * - * @param name string + * @param[in] name string */ void setName(const std::string& name); @@ -118,75 +110,49 @@ public: bool isMarkedAsStatic() const; /** Set Thread stack size - * - * @param thread Thread instance - * @param stackSize stack size in bytes + * @param[in] stackSize stack size in bytes */ void setStackSize(size_t stackSize); /** Set Thread callback - * - * @param thread Thread instance - * @param callback ThreadCallback, called upon thread run - * @param callbackContext what to pass to the callback + * @param[in] callback ThreadCallback, called upon thread run + * @param[in] callbackContext what to pass to the callback */ void setCallback(Callback callback, _Nullable void* callbackContext = nullptr); /** Set Thread priority - * - * @param thread Thread instance - * @param priority ThreadPriority value + * @param[in] priority ThreadPriority value */ void setPriority(Priority priority); /** Set Thread state change callback - * - * @param thread Thread instance - * @param callback state change callback - * @param context pointer to context + * @param[in] callback state change callback + * @param[in] callbackContext pointer to context */ void setStateCallback(StateCallback callback, _Nullable void* callbackContext = nullptr); /** Get Thread state - * - * @param thread Thread instance - * * @return thread state from ThreadState */ State getState() const; /** Start Thread - * - * @param thread Thread instance */ void start(); /** Join Thread - * - * @warning Use this method only when CPU is not busy(Idle task receives - * control), otherwise it will wait forever. - * - * @param thread Thread instance - * + * @warning Use this method only when CPU is not busy (Idle task receives control), otherwise it will wait forever. * @return success result */ bool join(); /** Get FreeRTOS ThreadId for Thread instance - * - * @param thread Thread instance - * * @return ThreadId or nullptr */ ThreadId getId(); - /** Get thread return code - * - * @param thread Thread instance - * - * @return return code - */ + /** @return thread return code */ int32_t getReturnCode(); private: @@ -200,31 +166,17 @@ private: #define THREAD_PRIORITY_ISR (TT_CONFIG_THREAD_MAX_PRIORITIES - 1) /** Set current thread priority - * - * @param priority ThreadPriority value + * @param[in] priority ThreadPriority value */ void thread_set_current_priority(Thread::Priority priority); -/** Get current thread priority - * - * @return ThreadPriority value - */ +/** @return ThreadPriority value */ Thread::Priority thread_get_current_priority(); -/** Thread related methods that doesn't involve Thread directly */ - -/** Get FreeRTOS ThreadId for current thread - * - * @param thread Thread instance - * - * @return ThreadId or NULL - */ +/** @return FreeRTOS ThreadId or NULL */ ThreadId thread_get_current_id(); -/** Get Thread instance for current thread - * - * @return pointer to Thread or NULL if this thread doesn't belongs to Tactility - */ +/** @return pointer to Thread instance or NULL if this thread doesn't belongs to Tactility */ Thread* thread_get_current(); /** Return control to scheduler */ @@ -240,44 +192,38 @@ uint32_t thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout); /** * @brief Get thread name - * - * @param thread_id + * @param[in] threadId * @return const char* name or NULL */ -const char* thread_get_name(ThreadId thread_id); +const char* thread_get_name(ThreadId threadId); /** * @brief Get thread stack watermark - * - * @param thread_id + * @param[in] threadId * @return uint32_t */ -uint32_t thread_get_stack_space(ThreadId thread_id); +uint32_t thread_get_stack_space(ThreadId threadId); /** Suspend thread - * - * @param thread_id thread id + * @param[in] threadId thread id */ -void thread_suspend(ThreadId thread_id); +void thread_suspend(ThreadId threadId); /** Resume thread - * - * @param thread_id thread id + * @param[in] threadId thread id */ -void thread_resume(ThreadId thread_id); +void thread_resume(ThreadId threadId); /** Get thread suspended state - * - * @param thread_id thread id + * @param[in] threadId thread id * @return true if thread is suspended */ -bool thread_is_suspended(ThreadId thread_id); +bool thread_is_suspended(ThreadId threadId); /** Check if the thread was created with static memory - * - * @param thread_id thread id + * @param[in] threadId thread id * @return true if thread memory is static */ -bool thread_mark_is_static(ThreadId thread_id); +bool thread_mark_is_static(ThreadId threadId); } // namespace diff --git a/TactilityCore/Source/Timer.cpp b/TactilityCore/Source/Timer.cpp index 4146ba91..a9a7f66a 100644 --- a/TactilityCore/Source/Timer.cpp +++ b/TactilityCore/Source/Timer.cpp @@ -16,7 +16,7 @@ static void timer_callback(TimerHandle_t hTimer) { } Timer::Timer(Type type, Callback callback, std::shared_ptr callbackContext) { - tt_assert((kernel::isIrq() == 0U) && (callback != nullptr)); + tt_assert((!TT_IS_ISR()) && (callback != nullptr)); this->callback = callback; this->callbackContext = std::move(callbackContext); @@ -33,48 +33,49 @@ Timer::Timer(Type type, Callback callback, std::shared_ptr callbackContext } Timer::~Timer() { - tt_assert(!kernel::isIrq()); + tt_assert(!TT_IS_ISR()); tt_check(xTimerDelete(timerHandle, portMAX_DELAY) == pdPASS); } bool Timer::start(uint32_t intervalTicks) { - tt_assert(!kernel::isIrq()); + tt_assert(!TT_IS_ISR()); tt_assert(intervalTicks < portMAX_DELAY); return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS; } bool Timer::restart(uint32_t intervalTicks) { - tt_assert(!kernel::isIrq()); + tt_assert(!TT_IS_ISR()); tt_assert(intervalTicks < portMAX_DELAY); return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS && xTimerReset(timerHandle, portMAX_DELAY) == pdPASS; } bool Timer::stop() { - tt_assert(!kernel::isIrq()); + tt_assert(!TT_IS_ISR()); return xTimerStop(timerHandle, portMAX_DELAY) == pdPASS; } bool Timer::isRunning() { - tt_assert(!kernel::isIrq()); + tt_assert(!TT_IS_ISR()); return xTimerIsTimerActive(timerHandle) == pdTRUE; } uint32_t Timer::getExpireTime() { - tt_assert(!kernel::isIrq()); + tt_assert(!TT_IS_ISR()); return (uint32_t)xTimerGetExpiryTime(timerHandle); } -bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg) { - if (kernel::isIrq()) { - return xTimerPendFunctionCallFromISR(callback, callbackContext, arg, nullptr) == pdPASS; +bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout) { + if (TT_IS_ISR()) { + assert(timeout == 0); + return xTimerPendFunctionCallFromISR(callback, callbackContext, callbackArg, nullptr) == pdPASS; } else { - return xTimerPendFunctionCall(callback, callbackContext, arg, TtWaitForever) == pdPASS; + return xTimerPendFunctionCall(callback, callbackContext, callbackArg, timeout) == pdPASS; } } void Timer::setThreadPriority(ThreadPriority priority) { - tt_assert(!kernel::isIrq()); + tt_assert(!TT_IS_ISR()); TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle(); tt_assert(task_handle); // Don't call this method before timer task start diff --git a/TactilityCore/Source/Timer.h b/TactilityCore/Source/Timer.h index 54fe6f4a..803bd6ec 100644 --- a/TactilityCore/Source/Timer.h +++ b/TactilityCore/Source/Timer.h @@ -33,55 +33,44 @@ public: ~Timer(); /** Start timer - * - * @warning This is asynchronous call, real operation will happen as soon as - * timer service process this request. - * + * @warning This is asynchronous call, real operation will happen as soon as timer service process this request. * @param[in] ticks The interval in ticks * @return success result */ bool start(uint32_t intervalTicks); /** Restart timer with previous timeout value - * - * @warning This is asynchronous call, real operation will happen as soon as - * timer service process this request. - * + * @warning This is asynchronous call, real operation will happen as soon as timer service process this request. * @param[in] ticks The interval in ticks - * * @return success result */ bool restart(uint32_t intervalTicks); - /** Stop timer - * - * @warning This is asynchronous call, real operation will happen as soon as - * timer service process this request. - * + * @warning This is asynchronous call, real operation will happen as soon as timer service process this request. * @return success result */ bool stop(); /** Is timer running - * - * @warning This cal may and will return obsolete timer state if timer - * commands are still in the queue. Please read FreeRTOS timer - * documentation first. - * + * @warning This cal may and will return obsolete timer state if timer commands are still in the queue. Please read FreeRTOS timer documentation first. * @return true when running */ bool isRunning(); /** Get timer expire time - * - * @param instance The Timer instance - * * @return expire tick */ uint32_t getExpireTime(); - bool setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg); + /** + * Calls xTimerPendFunctionCall internally. + * @param[in] callback the function to call + * @param[in] callbackContext the first function argument + * @param[in] callbackArg the second function argument + * @param[in] timeout the function timeout (must set to 0 in ISR mode) + */ + bool setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout); typedef enum { TimerThreadPriorityNormal, /**< Lower then other threads */ @@ -89,7 +78,6 @@ public: } ThreadPriority; /** Set Timer thread priority - * * @param[in] priority The priority */ void setThreadPriority(ThreadPriority priority); diff --git a/TactilityCore/Source/crypt/Crypt.cpp b/TactilityCore/Source/crypt/Crypt.cpp index c0d64d21..7faec8cd 100644 --- a/TactilityCore/Source/crypt/Crypt.cpp +++ b/TactilityCore/Source/crypt/Crypt.cpp @@ -91,14 +91,14 @@ static void get_nvs_key(uint8_t key[32]) { /** * Performs XOR on 2 memory regions and stores it in a third - * @param[in] in_left input buffer for XOR - * @param[in] in_right second input buffer for XOR + * @param[in] inLeft input buffer for XOR + * @param[in] inRight second input buffer for XOR * @param[out] out output buffer for result of XOR * @param[in] length data length (all buffers must be at least this size) */ -static void xorKey(const uint8_t* in_left, const uint8_t* in_right, uint8_t* out, size_t length) { +static void xorKey(const uint8_t* inLeft, const uint8_t* inRight, uint8_t* out, size_t length) { for (int i = 0; i < length; ++i) { - out[i] = in_left[i] ^ in_right[i]; + out[i] = inLeft[i] ^ inRight[i]; } } @@ -112,10 +112,10 @@ static void getKey(uint8_t key[32]) { TT_LOG_W(TAG, "An attacker with physical access to your ESP32 can decrypt your secure data."); #endif +#ifdef ESP_PLATFORM uint8_t hardware_key[32]; uint8_t nvs_key[32]; -#ifdef ESP_PLATFORM get_hardware_key(hardware_key); get_nvs_key(nvs_key); xorKey(hardware_key, nvs_key, key, 32); @@ -125,10 +125,10 @@ static void getKey(uint8_t key[32]) { #endif } -void getIv(const void* data, size_t data_length, uint8_t iv[16]) { +void getIv(const void* data, size_t dataLength, uint8_t iv[16]) { memset((void*)iv, 0, 16); - uint8_t* data_bytes = (uint8_t*)data; - for (int i = 0; i < data_length; ++i) { + auto* data_bytes = (uint8_t*)data; + for (int i = 0; i < dataLength; ++i) { size_t safe_index = i % 16; iv[safe_index] %= data_bytes[i]; } @@ -160,8 +160,8 @@ static int aes256CryptCbc( return result; } -int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length) { - tt_check(length % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256"); +int encrypt(const uint8_t iv[16], uint8_t* inData, uint8_t* outData, size_t dataLength) { + tt_check(dataLength % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256"); uint8_t key[32]; getKey(key); @@ -169,11 +169,11 @@ int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t le uint8_t iv_copy[16]; memcpy(iv_copy, iv, sizeof(iv_copy)); - return aes256CryptCbc(key, MBEDTLS_AES_ENCRYPT, length, iv_copy, in_data, out_data); + return aes256CryptCbc(key, MBEDTLS_AES_ENCRYPT, dataLength, iv_copy, inData, outData); } -int decrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length) { - tt_check(length % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256"); +int decrypt(const uint8_t iv[16], uint8_t* inData, uint8_t* outData, size_t dataLength) { + tt_check(dataLength % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256"); uint8_t key[32]; getKey(key); @@ -181,7 +181,7 @@ int decrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t le uint8_t iv_copy[16]; memcpy(iv_copy, iv, sizeof(iv_copy)); - return aes256CryptCbc(key, MBEDTLS_AES_DECRYPT, length, iv_copy, in_data, out_data); + return aes256CryptCbc(key, MBEDTLS_AES_DECRYPT, dataLength, iv_copy, inData, outData); } } // namespace diff --git a/TactilityCore/Source/crypt/Crypt.h b/TactilityCore/Source/crypt/Crypt.h index 6ced0483..2b08cf54 100644 --- a/TactilityCore/Source/crypt/Crypt.h +++ b/TactilityCore/Source/crypt/Crypt.h @@ -26,11 +26,11 @@ namespace tt::crypt { /** * @brief Fills the IV with zeros and then creates an IV based on the input data. - * @param data input data - * @param data_length input data length - * @param iv output IV + * @param[in] data input data + * @param[in] dataLength input data length + * @param[out] iv output IV */ -void getIv(const void* data, size_t data_length, uint8_t iv[16]); +void getIv(const void* data, size_t dataLength, uint8_t iv[16]); /** * @brief Encrypt data. @@ -38,13 +38,13 @@ void getIv(const void* data, size_t data_length, uint8_t iv[16]); * Important: Use flash encryption to increase security. * Important: input and output data must be aligned to 16 bytes. * - * @param iv the AES IV - * @param data_in input data - * @param data_out output data - * @param length data length, a multiple of 16 + * @param[in] iv the AES IV + * @param[in] inData input data + * @param[out] outData output data + * @param[in] dataLength data length, a multiple of 16 (for both inData and outData) * @return the result of esp_aes_crypt_cbc() (MBEDTLS_ERR_*) */ -int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length); +int encrypt(const uint8_t iv[16], uint8_t* inData, uint8_t* outData, size_t dataLength); /** * @brief Decrypt data. @@ -52,12 +52,12 @@ int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t le * Important: Use flash encryption to increase security. * Important: input and output data must be aligned to 16 bytes. * - * @param iv AES IV - * @param data_in input data - * @param data_out output data - * @param length data length, a multiple of 16 + * @param[in] iv AES IV + * @param[in] inData input data + * @param[out] outData output data + * @param[in] dataLength data length, a multiple of 16 (for both inData and outData) * @return the result of esp_aes_crypt_cbc() (MBEDTLS_ERR_*) */ -int decrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length); +int decrypt(const uint8_t iv[16], uint8_t* inData, uint8_t* outData, size_t dataLength); } // namespace diff --git a/TactilityCore/Source/crypt/Hash.h b/TactilityCore/Source/crypt/Hash.h index 407afc8f..e670b9c1 100644 --- a/TactilityCore/Source/crypt/Hash.h +++ b/TactilityCore/Source/crypt/Hash.h @@ -15,6 +15,7 @@ uint32_t djb2(const char* str); /** * Implementation of DJB2 hashing algorithm. * @param[in] data the bytes to calculate the hash for + * @param[in] length the size of data * @return the hash */ uint32_t djb2(const void* data, size_t length); diff --git a/TactilityCore/Source/file/File.cpp b/TactilityCore/Source/file/File.cpp index 2759398f..53140701 100644 --- a/TactilityCore/Source/file/File.cpp +++ b/TactilityCore/Source/file/File.cpp @@ -26,6 +26,11 @@ long getSize(FILE* file) { return file_size; } +/** Read a file. + * @param[in] filepath + * @param[out] outSize the amount of bytes that were read, excluding the sizePadding + * @param[in] sizePadding optional padding to add at the end of the output data (the values are not set) + */ static std::unique_ptr readBinaryInternal(const std::string& filepath, size_t& outSize, size_t sizePadding = 0) { FILE* file = fopen(filepath.c_str(), "rb"); @@ -53,15 +58,19 @@ static std::unique_ptr readBinaryInternal(const std::string& filepath if (bytes_read > 0) { buffer_offset += bytes_read; } else { // Something went wrong? - data = nullptr; break; } } - outSize = buffer_offset; - fclose(file); - return data; + + if (buffer_offset == content_length) { + outSize = buffer_offset; + return data; + } else { + outSize = 0; + return nullptr; + } } std::unique_ptr readBinary(const std::string& filepath, size_t& outSize) { @@ -71,15 +80,11 @@ std::unique_ptr readBinary(const std::string& filepath, size_t& outSi std::unique_ptr readString(const std::string& filepath) { size_t size = 0; auto data = readBinaryInternal(filepath, size, 1); - if (data == nullptr) { - return nullptr; - } else if (size > 0) { + if (data != nullptr) { data.get()[size] = 0; // Append null terminator return data; - } else { // Empty file: return empty string - auto value = std::make_unique(1); - value[0] = 0; - return value; + } else { + return nullptr; } } diff --git a/TactilityCore/Source/file/File.h b/TactilityCore/Source/file/File.h index ee835794..e95a016c 100644 --- a/TactilityCore/Source/file/File.h +++ b/TactilityCore/Source/file/File.h @@ -7,7 +7,17 @@ namespace tt::file { long getSize(FILE* file); +/** Read a file and return its data. + * @param[in] filepath the path of the file + * @param[out] size the amount of bytes that were read + * @return null on error, or an array of bytes in case of success + */ std::unique_ptr readBinary(const std::string& filepath, size_t& outSize); + +/** Read a file and return a null-terminated string that represents its content. + * @param[in] filepath the path of the file + * @return null on error, or an array of bytes in case of success. Empty string returns as a single 0 character. + */ std::unique_ptr readString(const std::string& filepath); } diff --git a/TactilityCore/Source/kernel/Kernel.cpp b/TactilityCore/Source/kernel/Kernel.cpp index 26f97cfa..e5180be1 100644 --- a/TactilityCore/Source/kernel/Kernel.cpp +++ b/TactilityCore/Source/kernel/Kernel.cpp @@ -12,16 +12,12 @@ namespace tt::kernel { -bool isIrq() { - return TT_IS_IRQ_MODE(); -} - bool isRunning() { return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING; } int32_t lock() { - tt_assert(!isIrq()); + tt_assert(!TT_IS_ISR()); int32_t lock; @@ -46,7 +42,7 @@ int32_t lock() { } int32_t unlock() { - tt_assert(!isIrq()); + tt_assert(!TT_IS_ISR()); int32_t lock; @@ -76,7 +72,7 @@ int32_t unlock() { } int32_t restoreLock(int32_t lock) { - tt_assert(!isIrq()); + tt_assert(!TT_IS_ISR()); switch (xTaskGetSchedulerState()) { case taskSCHEDULER_SUSPENDED: @@ -112,7 +108,7 @@ uint32_t getTickFrequency() { } void delayTicks(TickType_t ticks) { - tt_assert(!isIrq()); + tt_assert(!TT_IS_ISR()); if (ticks == 0U) { taskYIELD(); } else { @@ -121,7 +117,7 @@ void delayTicks(TickType_t ticks) { } TtStatus delayUntilTick(TickType_t tick) { - tt_assert(!isIrq()); + tt_assert(!TT_IS_ISR()); TickType_t tcnt, delay; TtStatus stat; @@ -150,7 +146,7 @@ TtStatus delayUntilTick(TickType_t tick) { TickType_t getTicks() { TickType_t ticks; - if (isIrq() != 0U) { + if (TT_IS_ISR() != 0U) { ticks = xTaskGetTickCountFromISR(); } else { ticks = xTaskGetTickCount(); diff --git a/TactilityCore/Source/kernel/Kernel.h b/TactilityCore/Source/kernel/Kernel.h index 19b29d92..016435e6 100644 --- a/TactilityCore/Source/kernel/Kernel.h +++ b/TactilityCore/Source/kernel/Kernel.h @@ -10,87 +10,56 @@ namespace tt::kernel { +/** Recognized platform types */ typedef enum { PlatformEsp, PlatformSimulator } Platform; -/** Check if CPU is in IRQ or kernel running and IRQ is masked - * - * Originally this primitive was born as a workaround for FreeRTOS kernel primitives shenanigans with PRIMASK. - * - * Meaningful use cases are: - * - * - When kernel is started and you want to ensure that you are not in IRQ or IRQ is not masked(like in critical section) - * - When kernel is not started and you want to make sure that you are not in IRQ mode, ignoring PRIMASK. - * - * As you can see there will be edge case when kernel is not started and PRIMASK is not 0 that may cause some funky behavior. - * Most likely it will happen after kernel primitives being used, but control not yet passed to kernel. - * It's up to you to figure out if it is safe for your code or not. - * - * @return true if CPU is in IRQ or kernel running and IRQ is masked - */ -bool isIrq(); - /** Check if kernel is running - * - * @return true if running, false otherwise + * @return true if the FreeRTOS kernel is running, false otherwise */ bool isRunning(); /** Lock kernel, pause process scheduling - * - * @warning This should never be called in interrupt request context. - * - * @return previous lock state(0 - unlocked, 1 - locked) + * @warning don't call from ISR context + * @return previous lock state(0 - unlocked, 1 - locked) */ int32_t lock(); /** Unlock kernel, resume process scheduling - * - * @warning This should never be called in interrupt request context. - * - * @return previous lock state(0 - unlocked, 1 - locked) + * @warning don't call from ISR context + * @return previous lock state(0 - unlocked, 1 - locked) */ int32_t unlock(); /** Restore kernel lock state - * - * @warning This should never be called in interrupt request context. - * - * @param[in] lock The lock state - * - * @return new lock state or error + * @warning don't call from ISR context + * @param[in] lock The lock state + * @return new lock state or error */ int32_t restoreLock(int32_t lock); /** Get kernel systick frequency - * - * @return systick counts per second + * @return systick counts per second */ uint32_t getTickFrequency(); TickType_t getTicks(); /** Delay execution - * - * @warning This should never be called in interrupt request context. - * + * @warning don't call from ISR context * Also keep in mind delay is aliased to scheduler timer intervals. - * - * @param[in] ticks The ticks count to pause + * @param[in] ticks The ticks count to pause */ void delayTicks(TickType_t ticks); /** Delay until tick - * - * @warning This should never be called in interrupt request context. - * - * @param[in] ticks The tick until which kerel should delay task execution - * - * @return The status. + * @warning don't call from ISR context + * @param[in] ticks The tick until which kerel should delay task execution + * @return the status */ -TtStatus delayUntilTick(uint32_t tick); +TtStatus delayUntilTick(TickType_t tick); /** Convert milliseconds to ticks * @@ -100,26 +69,22 @@ TtStatus delayUntilTick(uint32_t tick); TickType_t millisToTicks(uint32_t milliSeconds); /** Delay in milliseconds - * * This method uses kernel ticks on the inside, which causes delay to be aliased to scheduler timer intervals. * Real wait time will be between X+ milliseconds. * Special value: 0, will cause task yield. - * Also if used when kernel is not running will fall back to `tt_delay_us`. - * - * @warning Cannot be used from ISR - * - * @param[in] milliSeconds milliseconds to wait + * Also if used when kernel is not running will fall back to delayMicros() + * @warning don't call from ISR context + * @param[in] milliSeconds milliseconds to wait */ void delayMillis(uint32_t milliSeconds); /** Delay in microseconds - * * Implemented using Cortex DWT counter. Blocking and non aliased. - * - * @param[in] microSeconds microseconds to wait + * @param[in] microSeconds microseconds to wait */ void delayMicros(uint32_t microSeconds); +/** @return the platform that Tactility currently is running on. */ Platform getPlatform(); } // namespace diff --git a/TactilityCore/Source/kernel/PanicHandler.cpp b/TactilityCore/Source/kernel/PanicHandler.cpp index ab519675..aaa7913f 100644 --- a/TactilityCore/Source/kernel/PanicHandler.cpp +++ b/TactilityCore/Source/kernel/PanicHandler.cpp @@ -2,7 +2,6 @@ #include "PanicHandler.h" -#include #include #include #include @@ -10,6 +9,10 @@ extern "C" { +/** + * This static variable survives a crash reboot. + * It is reset by the Boot app. + */ static RTC_NOINIT_ATTR CrashData crashData; void __real_esp_panic_handler(void* info); @@ -61,6 +64,6 @@ void __wrap_esp_panic_handler(void* info) { } -const CrashData* getRtcCrashData() { return &crashData; } +const CrashData& getRtcCrashData() { return crashData; } #endif \ No newline at end of file diff --git a/TactilityCore/Source/kernel/PanicHandler.h b/TactilityCore/Source/kernel/PanicHandler.h index 21a54458..9b143f7e 100644 --- a/TactilityCore/Source/kernel/PanicHandler.h +++ b/TactilityCore/Source/kernel/PanicHandler.h @@ -7,6 +7,7 @@ #define CRASH_DATA_CALLSTACK_LIMIT 64 #define CRASH_DATA_INCLUDES_SP false +/** Represents a single frame on the callstack. */ struct CallstackFrame { uint32_t pc = 0; #if CRASH_DATA_INCLUDES_SP @@ -14,12 +15,14 @@ struct CallstackFrame { #endif }; +/** Callstack-related crash data. */ struct CrashData { bool callstackCorrupted = false; uint8_t callstackLength = 0; CallstackFrame callstack[CRASH_DATA_CALLSTACK_LIMIT]; }; -const CrashData* getRtcCrashData(); +/** @return the crash data */ +const CrashData& getRtcCrashData(); #endif \ No newline at end of file diff --git a/TactilityCore/Source/kernel/critical/Critical.h b/TactilityCore/Source/kernel/critical/Critical.h index 162ab1e8..890be92c 100644 --- a/TactilityCore/Source/kernel/critical/Critical.h +++ b/TactilityCore/Source/kernel/critical/Critical.h @@ -10,8 +10,15 @@ typedef struct { bool kernelRunning; } TtCriticalInfo; +/** Enter a critical section + * @return info on the status + */ TtCriticalInfo enter(); +/** + * Exit a critical section + * @param[in] info the info from when the critical section was started + */ void exit(TtCriticalInfo info); } // namespace diff --git a/TactilityHeadless/Source/Preferences.h b/TactilityHeadless/Source/Preferences.h index 332a9c0c..d2a34812 100644 --- a/TactilityHeadless/Source/Preferences.h +++ b/TactilityHeadless/Source/Preferences.h @@ -5,6 +5,10 @@ namespace tt { +/** + * Settings that persist on NVS flash for ESP32. + * On simulator, the settings are only in-memory. + */ class Preferences { private: const char* namespace_; diff --git a/TactilityHeadless/Source/TactilityHeadless.h b/TactilityHeadless/Source/TactilityHeadless.h index b714f409..b4528b50 100644 --- a/TactilityHeadless/Source/TactilityHeadless.h +++ b/TactilityHeadless/Source/TactilityHeadless.h @@ -7,14 +7,20 @@ namespace tt { +/** Initialize the hardware and started the internal services. */ void initHeadless(const hal::Configuration& config); +/** Provides access to the dispatcher that runs on the main task. + * @warning This dispatcher is used for WiFi and might block for some time during WiFi connection. + * @return the dispatcher + */ Dispatcher& getMainDispatcher(); } // namespace namespace tt::hal { +/** Can be called after initHeadless() is called. Will crash otherwise. */ const Configuration& getConfiguration(); } // namespace diff --git a/TactilityHeadless/Source/service/ServiceContext.h b/TactilityHeadless/Source/service/ServiceContext.h index 8c27af7a..23b9a419 100644 --- a/TactilityHeadless/Source/service/ServiceContext.h +++ b/TactilityHeadless/Source/service/ServiceContext.h @@ -8,6 +8,10 @@ namespace tt::service { class Paths; +/** + * The public representation of a service instance. + * @warning Do not store references or pointers to these! You can retrieve them via the Loader service. + */ class ServiceContext { protected: @@ -16,9 +20,13 @@ protected: public: + /** @return a reference ot the service's manifest */ virtual const service::ServiceManifest& getManifest() const = 0; - virtual std::shared_ptr getData() const = 0; + /** @return a shared pointer to the data that is attached to the service */ + virtual std::shared_ptr _Nullable getData() const = 0; + /** Set the data for a service. */ virtual void setData(std::shared_ptr newData) = 0; + /** Retrieve the paths that are relevant to this service */ virtual std::unique_ptr getPaths() const = 0; }; diff --git a/TactilityHeadless/Source/service/ServiceManifest.h b/TactilityHeadless/Source/service/ServiceManifest.h index 3ce32465..50da638a 100644 --- a/TactilityHeadless/Source/service/ServiceManifest.h +++ b/TactilityHeadless/Source/service/ServiceManifest.h @@ -9,22 +9,16 @@ class ServiceContext; typedef void (*ServiceOnStart)(ServiceContext& service); typedef void (*ServiceOnStop)(ServiceContext& service); +/** A ledger that describes the main parts of a service. */ struct ServiceManifest { - /** - * The identifier by which the app is launched by the system and other apps. - */ + /** The identifier by which the app is launched by the system and other apps. */ std::string id {}; - /** - * Non-blocking method to call when service is started. - */ + /** Non-blocking method to call when service is started. */ const ServiceOnStart onStart = nullptr; - /** - * Non-blocking method to call when service is stopped. - */ + /** Non-blocking method to call when service is stopped. */ const ServiceOnStop onStop = nullptr; - }; } // namespace diff --git a/TactilityHeadless/Source/service/ServiceRegistry.h b/TactilityHeadless/Source/service/ServiceRegistry.h index 366f13db..6d9e1e9e 100644 --- a/TactilityHeadless/Source/service/ServiceRegistry.h +++ b/TactilityHeadless/Source/service/ServiceRegistry.h @@ -4,17 +4,40 @@ namespace tt::service { -typedef void (*ManifestCallback)(const ServiceManifest*, void* context); - void initRegistry(); +/** Register a service. + * @param[in] the service manifest + */ void addService(const ServiceManifest* manifest); + +/** Unregister a service. + * @param[in] the service manifest + */ void removeService(const ServiceManifest* manifest); +/** Start a service. + * @param[in] the service id as defined in its manifest + * @return true on success + */ bool startService(const std::string& id); + +/** Stop a service. + * @param[in] the service id as defined in its manifest + * @return true on success or false when service wasn't running. + */ bool stopService(const std::string& id); +/** Find a service manifest by its id. + * @param[in] id the id as defined in the manifest + * @return the matching manifest or nullptr when it wasn't found + */ const ServiceManifest* _Nullable findManifestId(const std::string& id); + +/** Find a service by its manifest id. + * @param[in] id the id as defined in the manifest + * @return the service context or nullptr when it wasn't found + */ ServiceContext* _Nullable findServiceById(const std::string& id); } // namespace diff --git a/TactilityHeadless/Source/service/wifi/Wifi.h b/TactilityHeadless/Source/service/wifi/Wifi.h index ddc7ca34..c49765f0 100644 --- a/TactilityHeadless/Source/service/wifi/Wifi.h +++ b/TactilityHeadless/Source/service/wifi/Wifi.h @@ -84,53 +84,42 @@ WifiRadioState getRadioState(); */ void scan(); -/** - * @return true if wifi is actively scanning - */ +/** @return true if wifi is actively scanning */ bool isScanning(); -/** - * @return true the ssid name or empty string - */ +/** @return true the ssid name or empty string */ std::string getConnectionTarget(); -/** - * @brief Returns the access points from the last scan (if any). It only contains public APs. - */ +/** @return the access points from the last scan (if any). It only contains public APs. */ std::vector getScanResults(); /** * @brief Overrides the default scan result size of 16. - * @param records the record limit for the scan result (84 bytes per record!) + * @param[in] records the record limit for the scan result (84 bytes per record!) */ void setScanRecords(uint16_t records); /** * @brief Enable/disable the radio. Ignores input if desired state matches current state. - * @param enabled + * @param[in] enabled */ void setEnabled(bool enabled); /** * @brief Connect to a network. Disconnects any existing connection. * Returns immediately but runs in the background. Results are through pubsub. - * @param ap + * @param[in] ap + * @param[in] remember whether to save the ap data to the settings upon successful connection */ void connect(const settings::WifiApSettings* ap, bool remember); -/** - * @brief Disconnect from the access point. Doesn't have any effect when not connected. - */ +/** @brief Disconnect from the access point. Doesn't have any effect when not connected. */ void disconnect(); -/** - * Return true if the connection isn't unencrypted. - */ +/** @return true if the connection isn't unencrypted. */ bool isConnectionSecure(); -/** - * Returns the RSSI value (negative number) or return 1 when not connected - */ +/** @return the RSSI value (negative number) or return 1 when not connected. */ int getRssi(); } // namespace diff --git a/TactilityHeadless/Source/service/wifi/WifiEsp.cpp b/TactilityHeadless/Source/service/wifi/WifiEsp.cpp index 622d2dcc..2efd7782 100644 --- a/TactilityHeadless/Source/service/wifi/WifiEsp.cpp +++ b/TactilityHeadless/Source/service/wifi/WifiEsp.cpp @@ -780,7 +780,7 @@ static void dispatchConnect(std::shared_ptr context) { TT_LOG_I(TAG, "Waiting for EventFlag by event_handler()"); if (bits & WIFI_CONNECTED_BIT) { - wifi->setSecureConnection(wifi_config.sta.password[0] != 0x00); + wifi->setSecureConnection(wifi_config.sta.password[0] != 0x00U); wifi->setRadioState(WIFI_RADIO_CONNECTION_ACTIVE); publish_event_simple(wifi, WifiEventTypeConnectionSuccess); TT_LOG_I(TAG, "Connected to %s", wifi->connection_target.ssid);