Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FL-3958] Stdio API improvements #4110

Merged
merged 5 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions applications/debug/unit_tests/tests/furi/furi_stdio_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ static size_t mock_in_cb(char* buffer, size_t size, FuriWait wait, void* context
}

void test_stdin(void) {
FuriThreadStdinReadCallback in_cb = furi_thread_get_stdin_callback();
FuriThreadStdinReadCallback in_cb;
void* in_ctx;
furi_thread_get_stdin_callback(&in_cb, &in_ctx);
furi_thread_set_stdin_callback(mock_in_cb, CONTEXT_MAGIC);
char buf[256];

Expand Down Expand Up @@ -63,13 +65,14 @@ void test_stdin(void) {
fgets(buf, sizeof(buf), stdin);
mu_assert_string_eq(" World!\n", buf);

furi_thread_set_stdin_callback(in_cb, CONTEXT_MAGIC);
furi_thread_set_stdin_callback(in_cb, in_ctx);
}

// stdout

static FuriString* mock_out;
FuriThreadStdoutWriteCallback original_out_cb;
static FuriThreadStdoutWriteCallback original_out_cb;
static void* original_out_ctx;

static void mock_out_cb(const char* data, size_t size, void* context) {
furi_check(context == CONTEXT_MAGIC);
Expand All @@ -83,15 +86,15 @@ 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, CONTEXT_MAGIC);
furi_thread_set_stdout_callback(original_out_cb, original_out_ctx);
mu_assert_string_eq(expected, furi_string_get_cstr(mock_out));
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_get_stdout_callback(&original_out_cb, &original_out_ctx);
furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC);
mock_out = furi_string_alloc();

Expand All @@ -104,5 +107,5 @@ void test_stdout(void) {
assert_and_clear_mock_out("Hello!");

furi_string_free(mock_out);
furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC);
furi_thread_set_stdout_callback(original_out_cb, original_out_ctx);
}
14 changes: 10 additions & 4 deletions furi/core/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -758,16 +758,22 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) {
return 0;
}

FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void) {
void furi_thread_get_stdout_callback(FuriThreadStdoutWriteCallback* callback, void** context) {
FuriThread* thread = furi_thread_get_current();
furi_check(thread);
return thread->output.write_callback;
furi_check(callback);
furi_check(context);
*callback = thread->output.write_callback;
*context = thread->output.context;
}

FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void) {
void furi_thread_get_stdin_callback(FuriThreadStdinReadCallback* callback, void** context) {
FuriThread* thread = furi_thread_get_current();
furi_check(thread);
return thread->input.read_callback;
furi_check(callback);
furi_check(context);
*callback = thread->input.read_callback;
*context = thread->input.context;
}

void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback, void* context) {
Expand Down
10 changes: 6 additions & 4 deletions furi/core/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,16 +479,18 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id);
/**
* @brief Get the standard output callback for the current thead.
*
* @return pointer to the standard out callback function
* @param[out] callback where to store the stdout callback
* @param[out] context where to store the context
*/
FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void);
void furi_thread_get_stdout_callback(FuriThreadStdoutWriteCallback* callback, void** context);

/**
* @brief Get the standard input callback for the current thead.
*
* @return pointer to the standard in callback function
* @param[out] callback where to store the stdin callback
* @param[out] context where to store the context
*/
FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void);
void furi_thread_get_stdin_callback(FuriThreadStdinReadCallback* callback, void** context);

/** Set standard output callback for the current thread.
*
Expand Down
11 changes: 10 additions & 1 deletion lib/toolbox/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct PipeSide {
PipeSideDataArrivedCallback on_data_arrived;
PipeSideSpaceFreedCallback on_space_freed;
PipeSideBrokenCallback on_pipe_broken;
FuriWait stdout_timeout;
};

PipeSideBundle pipe_alloc(size_t capacity, size_t trigger_level) {
Expand Down Expand Up @@ -52,12 +53,14 @@ PipeSideBundle pipe_alloc_ex(PipeSideReceiveSettings alice, PipeSideReceiveSetti
.shared = shared,
.sending = alice_to_bob,
.receiving = bob_to_alice,
.stdout_timeout = FuriWaitForever,
};
*bobs_side = (PipeSide){
.role = PipeRoleBob,
.shared = shared,
.sending = bob_to_alice,
.receiving = alice_to_bob,
.stdout_timeout = FuriWaitForever,
};

return (PipeSideBundle){.alices_side = alices_side, .bobs_side = bobs_side};
Expand Down Expand Up @@ -100,7 +103,8 @@ static void _pipe_stdout_cb(const char* data, size_t size, void* context) {
furi_assert(context);
PipeSide* pipe = context;
while(size) {
size_t sent = pipe_send(pipe, data, size, FuriWaitForever);
size_t sent = pipe_send(pipe, data, size, pipe->stdout_timeout);
if(!sent) break;
data += sent;
size -= sent;
}
Expand All @@ -118,6 +122,11 @@ void pipe_install_as_stdio(PipeSide* pipe) {
furi_thread_set_stdin_callback(_pipe_stdin_cb, pipe);
}

void pipe_set_stdout_timeout(PipeSide* pipe, FuriWait timeout) {
furi_check(pipe);
pipe->stdout_timeout = timeout;
}

size_t pipe_receive(PipeSide* pipe, void* data, size_t length, FuriWait timeout) {
furi_check(pipe);
return furi_stream_buffer_receive(pipe->receiving, data, length, timeout);
Expand Down
10 changes: 10 additions & 0 deletions lib/toolbox/pipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,16 @@ void pipe_free(PipeSide* pipe);
*/
void pipe_install_as_stdio(PipeSide* pipe);

/**
* @brief Sets the timeout for `stdout` write operations
*
* @note This value is set to `FuriWaitForever` when the pipe is created
*
* @param [in] pipe Pipe side to set the timeout of
* @param [in] timeout Timeout value in ticks
*/
void pipe_set_stdout_timeout(PipeSide* pipe, FuriWait timeout);

/**
* @brief Receives data from the pipe.
*
Expand Down
7 changes: 4 additions & 3 deletions targets/f18/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,81.1,,
Version,+,82.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,,
Expand Down Expand Up @@ -1666,8 +1666,8 @@ Function,+,furi_thread_get_return_code,int32_t,FuriThread*
Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread*
Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId
Function,+,furi_thread_get_state,FuriThreadState,FuriThread*
Function,+,furi_thread_get_stdin_callback,FuriThreadStdinReadCallback,
Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback,
Function,+,furi_thread_get_stdin_callback,void,"FuriThreadStdinReadCallback*, void**"
Function,+,furi_thread_get_stdout_callback,void,"FuriThreadStdoutWriteCallback*, void**"
Function,+,furi_thread_is_suspended,_Bool,FuriThreadId
Function,+,furi_thread_join,_Bool,FuriThread*
Function,+,furi_thread_list_alloc,FuriThreadList*,
Expand Down Expand Up @@ -2333,6 +2333,7 @@ Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, Fur
Function,+,pipe_set_callback_context,void,"PipeSide*, void*"
Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent"
Function,+,pipe_set_space_freed_callback,void,"PipeSide*, PipeSideSpaceFreedCallback, FuriEventLoopEvent"
Function,+,pipe_set_stdout_timeout,void,"PipeSide*, FuriWait"
Function,+,pipe_spaces_available,size_t,PipeSide*
Function,+,pipe_state,PipeState,PipeSide*
Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*"
Expand Down
7 changes: 4 additions & 3 deletions targets/f7/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,81.1,,
Version,+,82.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,,
Expand Down Expand Up @@ -1886,8 +1886,8 @@ Function,+,furi_thread_get_return_code,int32_t,FuriThread*
Function,+,furi_thread_get_signal_callback,FuriThreadSignalCallback,const FuriThread*
Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId
Function,+,furi_thread_get_state,FuriThreadState,FuriThread*
Function,+,furi_thread_get_stdin_callback,FuriThreadStdinReadCallback,
Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback,
Function,+,furi_thread_get_stdin_callback,void,"FuriThreadStdinReadCallback*, void**"
Function,+,furi_thread_get_stdout_callback,void,"FuriThreadStdoutWriteCallback*, void**"
Function,+,furi_thread_is_suspended,_Bool,FuriThreadId
Function,+,furi_thread_join,_Bool,FuriThread*
Function,+,furi_thread_list_alloc,FuriThreadList*,
Expand Down Expand Up @@ -2970,6 +2970,7 @@ Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, Fur
Function,+,pipe_set_callback_context,void,"PipeSide*, void*"
Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent"
Function,+,pipe_set_space_freed_callback,void,"PipeSide*, PipeSideSpaceFreedCallback, FuriEventLoopEvent"
Function,+,pipe_set_stdout_timeout,void,"PipeSide*, FuriWait"
Function,+,pipe_spaces_available,size_t,PipeSide*
Function,+,pipe_state,PipeState,PipeSide*
Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*"
Expand Down
Loading