mirror of
https://github.com/flipperdevices/flipperzero-firmware.git
synced 2025-12-12 12:51:22 +04:00
[FL-3958] Stdio API improvements (#4110)
* improve thread stdio callback signatures * pipe stdout timeout * update api symbols Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
@@ -30,7 +30,9 @@ static size_t mock_in_cb(char* buffer, size_t size, FuriWait wait, void* context
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test_stdin(void) {
|
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);
|
furi_thread_set_stdin_callback(mock_in_cb, CONTEXT_MAGIC);
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
@@ -63,13 +65,14 @@ void test_stdin(void) {
|
|||||||
fgets(buf, sizeof(buf), stdin);
|
fgets(buf, sizeof(buf), stdin);
|
||||||
mu_assert_string_eq(" World!\n", buf);
|
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
|
// stdout
|
||||||
|
|
||||||
static FuriString* mock_out;
|
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) {
|
static void mock_out_cb(const char* data, size_t size, void* context) {
|
||||||
furi_check(context == CONTEXT_MAGIC);
|
furi_check(context == CONTEXT_MAGIC);
|
||||||
@@ -83,7 +86,7 @@ static void assert_and_clear_mock_out(const char* expected) {
|
|||||||
// return the original stdout callback for the duration of the check
|
// 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,
|
// if the check fails, we don't want the error to end up in our buffer,
|
||||||
// we want to be able to see it!
|
// 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));
|
mu_assert_string_eq(expected, furi_string_get_cstr(mock_out));
|
||||||
furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC);
|
furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC);
|
||||||
|
|
||||||
@@ -91,7 +94,7 @@ static void assert_and_clear_mock_out(const char* expected) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test_stdout(void) {
|
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);
|
furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC);
|
||||||
mock_out = furi_string_alloc();
|
mock_out = furi_string_alloc();
|
||||||
|
|
||||||
@@ -104,5 +107,5 @@ void test_stdout(void) {
|
|||||||
assert_and_clear_mock_out("Hello!");
|
assert_and_clear_mock_out("Hello!");
|
||||||
|
|
||||||
furi_string_free(mock_out);
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -758,16 +758,22 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) {
|
|||||||
return 0;
|
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();
|
FuriThread* thread = furi_thread_get_current();
|
||||||
furi_check(thread);
|
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();
|
FuriThread* thread = furi_thread_get_current();
|
||||||
furi_check(thread);
|
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) {
|
void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback, void* context) {
|
||||||
|
|||||||
@@ -479,16 +479,18 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id);
|
|||||||
/**
|
/**
|
||||||
* @brief Get the standard output callback for the current thead.
|
* @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.
|
* @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.
|
/** Set standard output callback for the current thread.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ struct PipeSide {
|
|||||||
PipeSideDataArrivedCallback on_data_arrived;
|
PipeSideDataArrivedCallback on_data_arrived;
|
||||||
PipeSideSpaceFreedCallback on_space_freed;
|
PipeSideSpaceFreedCallback on_space_freed;
|
||||||
PipeSideBrokenCallback on_pipe_broken;
|
PipeSideBrokenCallback on_pipe_broken;
|
||||||
|
FuriWait stdout_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
PipeSideBundle pipe_alloc(size_t capacity, size_t trigger_level) {
|
PipeSideBundle pipe_alloc(size_t capacity, size_t trigger_level) {
|
||||||
@@ -52,12 +53,14 @@ PipeSideBundle pipe_alloc_ex(PipeSideReceiveSettings alice, PipeSideReceiveSetti
|
|||||||
.shared = shared,
|
.shared = shared,
|
||||||
.sending = alice_to_bob,
|
.sending = alice_to_bob,
|
||||||
.receiving = bob_to_alice,
|
.receiving = bob_to_alice,
|
||||||
|
.stdout_timeout = FuriWaitForever,
|
||||||
};
|
};
|
||||||
*bobs_side = (PipeSide){
|
*bobs_side = (PipeSide){
|
||||||
.role = PipeRoleBob,
|
.role = PipeRoleBob,
|
||||||
.shared = shared,
|
.shared = shared,
|
||||||
.sending = bob_to_alice,
|
.sending = bob_to_alice,
|
||||||
.receiving = alice_to_bob,
|
.receiving = alice_to_bob,
|
||||||
|
.stdout_timeout = FuriWaitForever,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (PipeSideBundle){.alices_side = alices_side, .bobs_side = bobs_side};
|
return (PipeSideBundle){.alices_side = alices_side, .bobs_side = bobs_side};
|
||||||
@@ -100,7 +103,8 @@ static void _pipe_stdout_cb(const char* data, size_t size, void* context) {
|
|||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
PipeSide* pipe = context;
|
PipeSide* pipe = context;
|
||||||
while(size) {
|
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;
|
data += sent;
|
||||||
size -= sent;
|
size -= sent;
|
||||||
}
|
}
|
||||||
@@ -118,6 +122,11 @@ void pipe_install_as_stdio(PipeSide* pipe) {
|
|||||||
furi_thread_set_stdin_callback(_pipe_stdin_cb, 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) {
|
size_t pipe_receive(PipeSide* pipe, void* data, size_t length, FuriWait timeout) {
|
||||||
furi_check(pipe);
|
furi_check(pipe);
|
||||||
return furi_stream_buffer_receive(pipe->receiving, data, length, timeout);
|
return furi_stream_buffer_receive(pipe->receiving, data, length, timeout);
|
||||||
|
|||||||
@@ -147,6 +147,16 @@ void pipe_free(PipeSide* pipe);
|
|||||||
*/
|
*/
|
||||||
void pipe_install_as_stdio(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.
|
* @brief Receives data from the pipe.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
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.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
@@ -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_signal_callback,FuriThreadSignalCallback,const FuriThread*
|
||||||
Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId
|
Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId
|
||||||
Function,+,furi_thread_get_state,FuriThreadState,FuriThread*
|
Function,+,furi_thread_get_state,FuriThreadState,FuriThread*
|
||||||
Function,+,furi_thread_get_stdin_callback,FuriThreadStdinReadCallback,
|
Function,+,furi_thread_get_stdin_callback,void,"FuriThreadStdinReadCallback*, void**"
|
||||||
Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback,
|
Function,+,furi_thread_get_stdout_callback,void,"FuriThreadStdoutWriteCallback*, void**"
|
||||||
Function,+,furi_thread_is_suspended,_Bool,FuriThreadId
|
Function,+,furi_thread_is_suspended,_Bool,FuriThreadId
|
||||||
Function,+,furi_thread_join,_Bool,FuriThread*
|
Function,+,furi_thread_join,_Bool,FuriThread*
|
||||||
Function,+,furi_thread_list_alloc,FuriThreadList*,
|
Function,+,furi_thread_list_alloc,FuriThreadList*,
|
||||||
@@ -2333,6 +2333,7 @@ Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, Fur
|
|||||||
Function,+,pipe_set_callback_context,void,"PipeSide*, void*"
|
Function,+,pipe_set_callback_context,void,"PipeSide*, void*"
|
||||||
Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent"
|
Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent"
|
||||||
Function,+,pipe_set_space_freed_callback,void,"PipeSide*, PipeSideSpaceFreedCallback, 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_spaces_available,size_t,PipeSide*
|
||||||
Function,+,pipe_state,PipeState,PipeSide*
|
Function,+,pipe_state,PipeState,PipeSide*
|
||||||
Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*"
|
Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*"
|
||||||
|
|||||||
|
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,81.1,,
|
Version,+,82.0,,
|
||||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
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.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
@@ -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_signal_callback,FuriThreadSignalCallback,const FuriThread*
|
||||||
Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId
|
Function,+,furi_thread_get_stack_space,uint32_t,FuriThreadId
|
||||||
Function,+,furi_thread_get_state,FuriThreadState,FuriThread*
|
Function,+,furi_thread_get_state,FuriThreadState,FuriThread*
|
||||||
Function,+,furi_thread_get_stdin_callback,FuriThreadStdinReadCallback,
|
Function,+,furi_thread_get_stdin_callback,void,"FuriThreadStdinReadCallback*, void**"
|
||||||
Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback,
|
Function,+,furi_thread_get_stdout_callback,void,"FuriThreadStdoutWriteCallback*, void**"
|
||||||
Function,+,furi_thread_is_suspended,_Bool,FuriThreadId
|
Function,+,furi_thread_is_suspended,_Bool,FuriThreadId
|
||||||
Function,+,furi_thread_join,_Bool,FuriThread*
|
Function,+,furi_thread_join,_Bool,FuriThread*
|
||||||
Function,+,furi_thread_list_alloc,FuriThreadList*,
|
Function,+,furi_thread_list_alloc,FuriThreadList*,
|
||||||
@@ -2970,6 +2970,7 @@ Function,+,pipe_set_broken_callback,void,"PipeSide*, PipeSideBrokenCallback, Fur
|
|||||||
Function,+,pipe_set_callback_context,void,"PipeSide*, void*"
|
Function,+,pipe_set_callback_context,void,"PipeSide*, void*"
|
||||||
Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent"
|
Function,+,pipe_set_data_arrived_callback,void,"PipeSide*, PipeSideDataArrivedCallback, FuriEventLoopEvent"
|
||||||
Function,+,pipe_set_space_freed_callback,void,"PipeSide*, PipeSideSpaceFreedCallback, 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_spaces_available,size_t,PipeSide*
|
||||||
Function,+,pipe_state,PipeState,PipeSide*
|
Function,+,pipe_state,PipeState,PipeSide*
|
||||||
Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*"
|
Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*"
|
||||||
|
|||||||
|
Reference in New Issue
Block a user