From 01807f47ab4a578d5a44aaef9bd9fe4a87eb71a0 Mon Sep 17 00:00:00 2001 From: Attila Body Date: Thu, 12 Jun 2025 18:19:03 +0200 Subject: [PATCH] Add thread-safe (-ish) console output --- Core/Src/main.c | 2 +- components/app/CMakeLists.txt | 1 + components/app/inc/app.h | 24 ++++++-- .../app/inc/thread_safe_console_output.h | 23 ++++++++ components/app/src/app.cpp | 56 +++++++++++++++++-- .../app/src/thread_safe_console_output.cpp | 34 +++++++++++ 6 files changed, 129 insertions(+), 11 deletions(-) create mode 100644 components/app/inc/thread_safe_console_output.h create mode 100644 components/app/src/thread_safe_console_output.cpp diff --git a/Core/Src/main.c b/Core/Src/main.c index 434c6b8..7011fb7 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -94,7 +94,7 @@ int main(void) MX_DMA_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ - // app_main(); + /* USER CODE END 2 */ /* Call init function for freertos objects (in cmsis_os2.c) */ diff --git a/components/app/CMakeLists.txt b/components/app/CMakeLists.txt index 7c92004..2703ea9 100644 --- a/components/app/CMakeLists.txt +++ b/components/app/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(app STATIC src/app.cpp src/irq_bridge.cpp + src/thread_safe_console_output.cpp ) target_include_directories(app PUBLIC diff --git a/components/app/inc/app.h b/components/app/inc/app.h index c5a3298..7b517fb 100644 --- a/components/app/inc/app.h +++ b/components/app/inc/app.h @@ -7,34 +7,50 @@ #pragma once +#include #include +#include #ifdef __cplusplus #include +#include +#include -class app : public f4ll::initialized_singleton +class app : public f4ll::initialized_singleton, f4ll::console_handler::iconsole_input { friend class f4ll::initialized_singleton; private: - app(); + app(void const *param); public: __attribute__((noreturn)) void main(); + void input_available(f4ll::console_handler::size_type len) override; private: + static void cli_task_dispatch(void *param) { static_cast(param)->cli_task(); } + __attribute__((noreturn)) void cli_task(); + static constexpr size_t const CLI_TASK_STACK_LEN = 128; + StackType_t m_cli_task_stack[CLI_TASK_STACK_LEN]; + StaticTask_t m_cli_task_buffer; + TaskHandle_t m_cli_task_handle; + f4ll::console_handler &m_con; static constexpr size_t const TXBUF_LEN = 128; static constexpr size_t const RXBUF_LEN = 32; uint8_t m_tx_buf_mem[TXBUF_LEN]; uint8_t m_rx_buf_mem[RXBUF_LEN]; + + thread_safe_console_output m_safe_conout; + + void queue_ts(); }; extern "C" { -#endif +#endif // __cplusplus void app_main(void const *param) __attribute__((noreturn)); #ifdef __cplusplus } // extern "C" { -#endif // __cplusplus +#endif // __cplusplus diff --git a/components/app/inc/thread_safe_console_output.h b/components/app/inc/thread_safe_console_output.h new file mode 100644 index 0000000..61cc35c --- /dev/null +++ b/components/app/inc/thread_safe_console_output.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include +#include + +class thread_safe_console_output +{ +public: + using size_type = f4ll::console_handler::size_type; + thread_safe_console_output(f4ll::console_handler &console); + + void print(char const *s); + void flush(); + size_type append(char const *s); + +private: + f4ll::console_handler &m_con; + + SemaphoreHandle_t m_sem; + StaticSemaphore_t m_sem_buf; +}; \ No newline at end of file diff --git a/components/app/src/app.cpp b/components/app/src/app.cpp index d30dab8..5d4b338 100644 --- a/components/app/src/app.cpp +++ b/components/app/src/app.cpp @@ -5,11 +5,15 @@ * Author: abody */ #include +#include + +#include #include #include #include +#include #include #include @@ -18,24 +22,64 @@ void app_main(void const *param) { - (void)param; - app::init().main(); + + app::init(param).main(); } -app::app() +app::app(void const *param) : m_con( f4ll::console_handler::init( USART2, DMA1, LL_DMA_STREAM_5, LL_DMA_STREAM_6, m_rx_buf_mem, sizeof(m_rx_buf_mem), m_tx_buf_mem, sizeof(m_tx_buf_mem), - nullptr)) + nullptr)), + m_safe_conout(m_con) + { + (void)param; } void app::main() { - m_con.print("-------------------------------------------\n"); + m_cli_task_handle = xTaskCreateStatic( + cli_task_dispatch, "CLI_task", CLI_TASK_STACK_LEN, this, osPriorityAboveNormal, m_cli_task_stack, &m_cli_task_buffer); + + queue_ts(); + m_safe_conout.print("-------------------------------------------\n"); while (true) { - m_con.print("Hello woooooooooooooooooooooooooooooooorld!\n"); + queue_ts(); + m_safe_conout.print("Hello woooooooooooooooooooooooooooooooorld!\n"); vTaskDelay(pdMS_TO_TICKS(500)); LL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); } +} + +void app::input_available(f4ll::console_handler::size_type len) +{ + // TODO: trigger a semaphore here and do the processing from a task. This is running in interrupt context + f4ll::iringbuffer &rb = f4ll::console_handler::instance().get_rx_buffer(); + f4ll::console_handler::size_type chunk_len = 0; + uint8_t const *chunk = nullptr; + bool more = false; + do { + more = rb.get_chunk(chunk, chunk_len); + if (chunk_len) { + rb.consumed(chunk_len); + } + } while (more); +} + +void app::cli_task() +{ + while (1) { + vTaskDelay(pdMS_TO_TICKS(10000)); + queue_ts(); + m_safe_conout.print(">>> TICK <<<\n"); + } +} + +void app::queue_ts() +{ + char ts_buf[12]; + uitodec(ts_buf, xTaskGetTickCount()); + m_safe_conout.append(ts_buf); + m_safe_conout.append(" "); } \ No newline at end of file diff --git a/components/app/src/thread_safe_console_output.cpp b/components/app/src/thread_safe_console_output.cpp new file mode 100644 index 0000000..278c5e9 --- /dev/null +++ b/components/app/src/thread_safe_console_output.cpp @@ -0,0 +1,34 @@ +#include + +#include +#include + +#include + +thread_safe_console_output::thread_safe_console_output(f4ll::console_handler &con) + : m_con(con), + m_sem(xSemaphoreCreateMutexStatic(&m_sem_buf)) +{ +} + +thread_safe_console_output::size_type thread_safe_console_output::append(char const *s) +{ + xSemaphoreTake(m_sem, portMAX_DELAY); + auto ret = m_con.append(s); + xSemaphoreGive(m_sem); + return ret; +} + +void thread_safe_console_output::flush() +{ + xSemaphoreTake(m_sem, portMAX_DELAY); + m_con.flush(); + xSemaphoreGive(m_sem); +} + +void thread_safe_console_output::print(const char *s) +{ + xSemaphoreTake(m_sem, portMAX_DELAY); + m_con.print(s); + xSemaphoreGive(m_sem); +}