From f1eb60b36021df376f8cf46e6d2eadedfe5fb8be Mon Sep 17 00:00:00 2001 From: Anna Antonenko Date: Thu, 7 Nov 2024 17:38:06 +0300 Subject: [PATCH] feat: stdio callback context --- .../unit_tests/tests/furi/furi_stdio_test.c | 20 +++++++++++-------- applications/services/cli/cli.c | 10 +++++----- applications/services/cli/cli_i.h | 3 ++- applications/services/cli/cli_vcp.c | 9 ++++++++- furi/core/thread.c | 12 +++++++---- furi/core/thread.h | 13 ++++++++---- targets/f18/api_symbols.csv | 6 +++--- targets/f7/api_symbols.csv | 6 +++--- 8 files changed, 50 insertions(+), 29 deletions(-) diff --git a/applications/debug/unit_tests/tests/furi/furi_stdio_test.c b/applications/debug/unit_tests/tests/furi/furi_stdio_test.c index a42973900a4..94e2f613b6a 100644 --- a/applications/debug/unit_tests/tests/furi/furi_stdio_test.c +++ b/applications/debug/unit_tests/tests/furi/furi_stdio_test.c @@ -5,6 +5,8 @@ #define TAG "StdioTest" +#define CONTEXT_MAGIC ((void*)0xDEADBEEF) + // stdin static char mock_in[256]; @@ -17,8 +19,9 @@ static void set_mock_in(const char* str) { mock_in_pos = 0; } -static size_t mock_in_cb(char* buffer, size_t size, FuriWait wait) { +static size_t mock_in_cb(char* buffer, size_t size, FuriWait wait, void* context) { UNUSED(wait); + furi_check(context == CONTEXT_MAGIC); size_t remaining = mock_in_len - mock_in_pos; size = MIN(remaining, size); memcpy(buffer, mock_in + mock_in_pos, size); @@ -28,7 +31,7 @@ static size_t mock_in_cb(char* buffer, size_t size, FuriWait wait) { void test_stdin(void) { FuriThreadStdinReadCallback in_cb = furi_thread_get_stdin_callback(); - furi_thread_set_stdin_callback(mock_in_cb); + furi_thread_set_stdin_callback(mock_in_cb, CONTEXT_MAGIC); char buf[256]; // plain in @@ -60,7 +63,7 @@ void test_stdin(void) { fgets(buf, sizeof(buf), stdin); mu_assert_string_eq(" World!\n", buf); - furi_thread_set_stdin_callback(in_cb); + furi_thread_set_stdin_callback(in_cb, CONTEXT_MAGIC); } // stdout @@ -68,7 +71,8 @@ void test_stdin(void) { static FuriString* mock_out; FuriThreadStdoutWriteCallback original_out_cb; -static void mock_out_cb(const char* data, size_t size) { +static void mock_out_cb(const char* data, size_t size, void* context) { + furi_check(context == CONTEXT_MAGIC); // there's no furi_string_cat_strn :( for(size_t i = 0; i < size; i++) { furi_string_push_back(mock_out, data[i]); @@ -79,16 +83,16 @@ static void assert_and_clear_mock_out(const char* expected) { // return the original stdout callback for the duration of the check // if the check fails, we don't want the error to end up in our buffer, // we want to be able to see it! - furi_thread_set_stdout_callback(original_out_cb); + furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC); mu_assert_string_eq(expected, furi_string_get_cstr(mock_out)); - furi_thread_set_stdout_callback(mock_out_cb); + furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC); furi_string_reset(mock_out); } void test_stdout(void) { original_out_cb = furi_thread_get_stdout_callback(); - furi_thread_set_stdout_callback(mock_out_cb); + furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC); mock_out = furi_string_alloc(); puts("Hello, World!"); @@ -100,5 +104,5 @@ void test_stdout(void) { assert_and_clear_mock_out("Hello!"); furi_string_free(mock_out); - furi_thread_set_stdout_callback(original_out_cb); + furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC); } diff --git a/applications/services/cli/cli.c b/applications/services/cli/cli.c index 0d8f52c04ec..28ba417c261 100644 --- a/applications/services/cli/cli.c +++ b/applications/services/cli/cli.c @@ -431,9 +431,9 @@ void cli_session_open(Cli* cli, void* session) { cli->session = session; if(cli->session != NULL) { cli->session->init(); - furi_thread_set_stdout_callback(cli->session->tx_stdout); + furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL); } else { - furi_thread_set_stdout_callback(NULL); + furi_thread_set_stdout_callback(NULL, NULL); } furi_semaphore_release(cli->idle_sem); furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); @@ -447,7 +447,7 @@ void cli_session_close(Cli* cli) { cli->session->deinit(); } cli->session = NULL; - furi_thread_set_stdout_callback(NULL); + furi_thread_set_stdout_callback(NULL, NULL); furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk); } @@ -461,9 +461,9 @@ int32_t cli_srv(void* p) { furi_record_create(RECORD_CLI, cli); if(cli->session != NULL) { - furi_thread_set_stdout_callback(cli->session->tx_stdout); + furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL); } else { - furi_thread_set_stdout_callback(NULL); + furi_thread_set_stdout_callback(NULL, NULL); } if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) { diff --git a/applications/services/cli/cli_i.h b/applications/services/cli/cli_i.h index d4cac6e7d92..d7351b9ffc3 100644 --- a/applications/services/cli/cli_i.h +++ b/applications/services/cli/cli_i.h @@ -28,8 +28,9 @@ struct CliSession { void (*init)(void); void (*deinit)(void); size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout); + size_t (*rx_stdin)(uint8_t* buffer, size_t size, uint32_t timeout, void* context); void (*tx)(const uint8_t* buffer, size_t size); - void (*tx_stdout)(const char* data, size_t size); + void (*tx_stdout)(const char* data, size_t size, void* context); bool (*is_connected)(void); }; diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index cdabaaa0544..aa399e78a29 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -242,6 +242,11 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) { return rx_cnt; } +static size_t cli_vcp_rx_stdin(uint8_t* data, size_t size, uint32_t timeout, void* context) { + UNUSED(context); + return cli_vcp_rx(data, size, timeout); +} + static void cli_vcp_tx(const uint8_t* buffer, size_t size) { furi_assert(vcp); furi_assert(buffer); @@ -267,7 +272,8 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) { VCP_DEBUG("tx %u end", size); } -static void cli_vcp_tx_stdout(const char* data, size_t size) { +static void cli_vcp_tx_stdout(const char* data, size_t size, void* context) { + UNUSED(context); cli_vcp_tx((const uint8_t*)data, size); } @@ -310,6 +316,7 @@ CliSession cli_vcp = { cli_vcp_init, cli_vcp_deinit, cli_vcp_rx, + cli_vcp_rx_stdin, cli_vcp_tx, cli_vcp_tx_stdout, cli_vcp_is_connected, diff --git a/furi/core/thread.c b/furi/core/thread.c index 12b9e61887c..6e515795775 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -26,11 +26,13 @@ typedef struct { FuriThreadStdoutWriteCallback write_callback; FuriString* buffer; + void* context; } FuriThreadStdout; typedef struct { FuriThreadStdinReadCallback read_callback; FuriString* unread_buffer; // output.write_callback != NULL) { - thread->output.write_callback(data, size); + thread->output.write_callback(data, size, thread->output.context); } else { furi_log_tx((const uint8_t*)data, size); } @@ -726,7 +728,7 @@ static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, s static size_t __furi_thread_stdin_read(FuriThread* thread, char* data, size_t size, FuriWait timeout) { if(thread->input.read_callback != NULL) { - return thread->input.read_callback(data, size, timeout); + return thread->input.read_callback(data, size, timeout, thread->input.context); } else { return 0; } @@ -754,17 +756,19 @@ FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void) { return thread->input.read_callback; } -void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback, void* context) { FuriThread* thread = furi_thread_get_current(); furi_check(thread); __furi_thread_stdout_flush(thread); thread->output.write_callback = callback; + thread->output.context = context; } -void furi_thread_set_stdin_callback(FuriThreadStdinReadCallback callback) { +void furi_thread_set_stdin_callback(FuriThreadStdinReadCallback callback, void* context) { FuriThread* thread = furi_thread_get_current(); furi_check(thread); thread->input.read_callback = callback; + thread->input.context = context; } size_t furi_thread_stdout_write(const char* data, size_t size) { diff --git a/furi/core/thread.h b/furi/core/thread.h index 219d839ee17..9abfde5cd85 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -74,8 +74,9 @@ typedef int32_t (*FuriThreadCallback)(void* context); * * @param[in] data pointer to the data to be written to the standard out * @param[in] size size of the data in bytes + * @param[in] context optional context */ -typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size); +typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size, void* context); /** * @brief Standard input callback function pointer type @@ -85,9 +86,11 @@ typedef void (*FuriThreadStdoutWriteCallback)(const char* data, size_t size); * @param[out] buffer buffer to read data into * @param[in] size maximum number of bytes to read into the buffer * @param[in] timeout how long to wait for (in ticks) before giving up + * @param[in] context optional context * @returns number of bytes that was actually read into the buffer */ -typedef size_t (*FuriThreadStdinReadCallback)(char* buffer, size_t size, FuriWait timeout); +typedef size_t ( + *FuriThreadStdinReadCallback)(char* buffer, size_t size, FuriWait timeout, void* context); /** * @brief State change callback function pointer type. @@ -490,14 +493,16 @@ FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void); /** Set standard output callback for the current thread. * * @param[in] callback pointer to the callback function or NULL to clear + * @param[in] context context to be passed to the callback */ -void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); +void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback, void* context); /** Set standard input callback for the current thread. * * @param[in] callback pointer to the callback function or NULL to clear + * @param[in] context context to be passed to the callback */ -void furi_thread_set_stdin_callback(FuriThreadStdinReadCallback callback); +void furi_thread_set_stdin_callback(FuriThreadStdinReadCallback callback, void* context); /** Write data to buffered standard output. * diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 2b247d6f30c..23421712d01 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,78.2,, +Version,+,79.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/cli/cli.h,, @@ -1680,8 +1680,8 @@ Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCa Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdin_callback,void,FuriThreadStdinReadCallback -Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdin_callback,void,"FuriThreadStdinReadCallback, void*" +Function,+,furi_thread_set_stdout_callback,void,"FuriThreadStdoutWriteCallback, void*" Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*" Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdin_read,size_t,"char*, size_t, FuriWait" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 8418b6e0bcc..6f9fc5466e6 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,78.2,, +Version,+,79.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, @@ -1899,8 +1899,8 @@ Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCa Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" -Function,+,furi_thread_set_stdin_callback,void,FuriThreadStdinReadCallback -Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback +Function,+,furi_thread_set_stdin_callback,void,"FuriThreadStdinReadCallback, void*" +Function,+,furi_thread_set_stdout_callback,void,"FuriThreadStdoutWriteCallback, void*" Function,+,furi_thread_signal,_Bool,"const FuriThread*, uint32_t, void*" Function,+,furi_thread_start,void,FuriThread* Function,+,furi_thread_stdin_read,size_t,"char*, size_t, FuriWait"