Skip to content

Commit

Permalink
feat: stdio callback context
Browse files Browse the repository at this point in the history
  • Loading branch information
portasynthinca3 committed Nov 7, 2024
1 parent 9f2e934 commit f1eb60b
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 29 deletions.
20 changes: 12 additions & 8 deletions applications/debug/unit_tests/tests/furi/furi_stdio_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#define TAG "StdioTest"

#define CONTEXT_MAGIC ((void*)0xDEADBEEF)

// stdin

static char mock_in[256];
Expand All @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -60,15 +63,16 @@ 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

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]);
Expand All @@ -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!");
Expand All @@ -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);
}
10 changes: 5 additions & 5 deletions applications/services/cli/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}

Expand All @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion applications/services/cli/cli_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

Expand Down
9 changes: 8 additions & 1 deletion applications/services/cli/cli_vcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down Expand Up @@ -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,
Expand Down
12 changes: 8 additions & 4 deletions furi/core/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
typedef struct {
FuriThreadStdoutWriteCallback write_callback;
FuriString* buffer;
void* context;
} FuriThreadStdout;

typedef struct {
FuriThreadStdinReadCallback read_callback;
FuriString* unread_buffer; // <! stores data from `ungetc` and friends
void* context;
} FuriThreadStdin;

struct FuriThread {
Expand Down Expand Up @@ -716,7 +718,7 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id) {

static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size) {
if(thread->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);
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand Down
13 changes: 9 additions & 4 deletions furi/core/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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.
*
Expand Down
6 changes: 3 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,+,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,,
Expand Down Expand Up @@ -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"
Expand Down
6 changes: 3 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,+,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,,
Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit f1eb60b

Please sign in to comment.