mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
Merge remote-tracking branch 'OFW/dev' into dev
This commit is contained in:
108
applications/debug/unit_tests/tests/furi/furi_stdio_test.c
Normal file
108
applications/debug/unit_tests/tests/furi/furi_stdio_test.c
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#include <furi.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../test.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#define TAG "StdioTest"
|
||||||
|
|
||||||
|
#define CONTEXT_MAGIC ((void*)0xDEADBEEF)
|
||||||
|
|
||||||
|
// stdin
|
||||||
|
|
||||||
|
static char mock_in[256];
|
||||||
|
static size_t mock_in_len, mock_in_pos;
|
||||||
|
|
||||||
|
static void set_mock_in(const char* str) {
|
||||||
|
size_t len = strlen(str);
|
||||||
|
strcpy(mock_in, str);
|
||||||
|
mock_in_len = len;
|
||||||
|
mock_in_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
mock_in_pos += size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_stdin(void) {
|
||||||
|
FuriThreadStdinReadCallback in_cb = furi_thread_get_stdin_callback();
|
||||||
|
furi_thread_set_stdin_callback(mock_in_cb, CONTEXT_MAGIC);
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
// plain in
|
||||||
|
set_mock_in("Hello, World!\n");
|
||||||
|
fgets(buf, sizeof(buf), stdin);
|
||||||
|
mu_assert_string_eq("Hello, World!\n", buf);
|
||||||
|
mu_assert_int_eq(EOF, getchar());
|
||||||
|
|
||||||
|
// ungetc
|
||||||
|
ungetc('i', stdin);
|
||||||
|
ungetc('H', stdin);
|
||||||
|
fgets(buf, sizeof(buf), stdin);
|
||||||
|
mu_assert_string_eq("Hi", buf);
|
||||||
|
mu_assert_int_eq(EOF, getchar());
|
||||||
|
|
||||||
|
// ungetc + plain in
|
||||||
|
set_mock_in(" World");
|
||||||
|
ungetc('i', stdin);
|
||||||
|
ungetc('H', stdin);
|
||||||
|
fgets(buf, sizeof(buf), stdin);
|
||||||
|
mu_assert_string_eq("Hi World", buf);
|
||||||
|
mu_assert_int_eq(EOF, getchar());
|
||||||
|
|
||||||
|
// partial plain in
|
||||||
|
set_mock_in("Hello, World!\n");
|
||||||
|
fgets(buf, strlen("Hello") + 1, stdin);
|
||||||
|
mu_assert_string_eq("Hello", buf);
|
||||||
|
mu_assert_int_eq(',', getchar());
|
||||||
|
fgets(buf, sizeof(buf), stdin);
|
||||||
|
mu_assert_string_eq(" World!\n", buf);
|
||||||
|
|
||||||
|
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, 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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC);
|
||||||
|
mock_out = furi_string_alloc();
|
||||||
|
|
||||||
|
puts("Hello, World!");
|
||||||
|
assert_and_clear_mock_out("Hello, World!\n");
|
||||||
|
|
||||||
|
printf("He");
|
||||||
|
printf("llo!");
|
||||||
|
fflush(stdout);
|
||||||
|
assert_and_clear_mock_out("Hello!");
|
||||||
|
|
||||||
|
furi_string_free(mock_out);
|
||||||
|
furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC);
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ void test_furi_memmgr(void);
|
|||||||
void test_furi_event_loop(void);
|
void test_furi_event_loop(void);
|
||||||
void test_errno_saving(void);
|
void test_errno_saving(void);
|
||||||
void test_furi_primitives(void);
|
void test_furi_primitives(void);
|
||||||
|
void test_stdin(void);
|
||||||
|
void test_stdout(void);
|
||||||
|
|
||||||
static int foo = 0;
|
static int foo = 0;
|
||||||
|
|
||||||
@@ -52,6 +54,11 @@ MU_TEST(mu_test_furi_primitives) {
|
|||||||
test_furi_primitives();
|
test_furi_primitives();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MU_TEST(mu_test_stdio) {
|
||||||
|
test_stdin();
|
||||||
|
test_stdout();
|
||||||
|
}
|
||||||
|
|
||||||
MU_TEST_SUITE(test_suite) {
|
MU_TEST_SUITE(test_suite) {
|
||||||
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||||
MU_RUN_TEST(test_check);
|
MU_RUN_TEST(test_check);
|
||||||
@@ -61,6 +68,7 @@ MU_TEST_SUITE(test_suite) {
|
|||||||
MU_RUN_TEST(mu_test_furi_pubsub);
|
MU_RUN_TEST(mu_test_furi_pubsub);
|
||||||
MU_RUN_TEST(mu_test_furi_memmgr);
|
MU_RUN_TEST(mu_test_furi_memmgr);
|
||||||
MU_RUN_TEST(mu_test_furi_event_loop);
|
MU_RUN_TEST(mu_test_furi_event_loop);
|
||||||
|
MU_RUN_TEST(mu_test_stdio);
|
||||||
MU_RUN_TEST(mu_test_errno_saving);
|
MU_RUN_TEST(mu_test_errno_saving);
|
||||||
MU_RUN_TEST(mu_test_furi_primitives);
|
MU_RUN_TEST(mu_test_furi_primitives);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -435,9 +435,9 @@ void cli_session_open(Cli* cli, void* session) {
|
|||||||
cli->session = session;
|
cli->session = session;
|
||||||
if(cli->session != NULL) {
|
if(cli->session != NULL) {
|
||||||
cli->session->init();
|
cli->session->init();
|
||||||
furi_thread_set_stdout_callback(cli->session->tx_stdout);
|
furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL);
|
||||||
} else {
|
} else {
|
||||||
furi_thread_set_stdout_callback(NULL);
|
furi_thread_set_stdout_callback(NULL, NULL);
|
||||||
}
|
}
|
||||||
furi_semaphore_release(cli->idle_sem);
|
furi_semaphore_release(cli->idle_sem);
|
||||||
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
|
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
|
||||||
@@ -451,7 +451,7 @@ void cli_session_close(Cli* cli) {
|
|||||||
cli->session->deinit();
|
cli->session->deinit();
|
||||||
}
|
}
|
||||||
cli->session = NULL;
|
cli->session = NULL;
|
||||||
furi_thread_set_stdout_callback(NULL);
|
furi_thread_set_stdout_callback(NULL, NULL);
|
||||||
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
|
furi_check(furi_mutex_release(cli->mutex) == FuriStatusOk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,9 +465,9 @@ int32_t cli_srv(void* p) {
|
|||||||
furi_record_create(RECORD_CLI, cli);
|
furi_record_create(RECORD_CLI, cli);
|
||||||
|
|
||||||
if(cli->session != NULL) {
|
if(cli->session != NULL) {
|
||||||
furi_thread_set_stdout_callback(cli->session->tx_stdout);
|
furi_thread_set_stdout_callback(cli->session->tx_stdout, NULL);
|
||||||
} else {
|
} else {
|
||||||
furi_thread_set_stdout_callback(NULL);
|
furi_thread_set_stdout_callback(NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) {
|
if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) {
|
||||||
|
|||||||
@@ -28,8 +28,9 @@ struct CliSession {
|
|||||||
void (*init)(void);
|
void (*init)(void);
|
||||||
void (*deinit)(void);
|
void (*deinit)(void);
|
||||||
size_t (*rx)(uint8_t* buffer, size_t size, uint32_t timeout);
|
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)(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);
|
bool (*is_connected)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -243,6 +243,11 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) {
|
|||||||
return rx_cnt;
|
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) {
|
static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
|
||||||
furi_assert(vcp);
|
furi_assert(vcp);
|
||||||
furi_assert(buffer);
|
furi_assert(buffer);
|
||||||
@@ -268,7 +273,8 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
|
|||||||
VCP_DEBUG("tx %u end", 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);
|
cli_vcp_tx((const uint8_t*)data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,6 +317,7 @@ CliSession cli_vcp = {
|
|||||||
cli_vcp_init,
|
cli_vcp_init,
|
||||||
cli_vcp_deinit,
|
cli_vcp_deinit,
|
||||||
cli_vcp_rx,
|
cli_vcp_rx,
|
||||||
|
cli_vcp_rx_stdin,
|
||||||
cli_vcp_tx,
|
cli_vcp_tx,
|
||||||
cli_vcp_tx_stdout,
|
cli_vcp_tx_stdout,
|
||||||
cli_vcp_is_connected,
|
cli_vcp_is_connected,
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ To add unit tests for your protocol, follow these steps:
|
|||||||
|
|
||||||
1. Create a file named `test_<your_protocol_name>.irtest` in the [assets](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/debug/unit_tests/resources/unit_tests/infrared) directory.
|
1. Create a file named `test_<your_protocol_name>.irtest` in the [assets](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/debug/unit_tests/resources/unit_tests/infrared) directory.
|
||||||
2. Fill it with the test data (more on it below).
|
2. Fill it with the test data (more on it below).
|
||||||
3. Add the test code to [infrared_test.c](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/applications/debug/unit_tests/infrared/infrared_test.c).
|
3. Add the test code to [infrared_test.c](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/applications/debug/unit_tests/tests/infrared/infrared_test.c).
|
||||||
4. Build and install firmware with resources, install it on your Flipper and run the tests to see if they pass.
|
4. Build and install firmware with resources, install it on your Flipper and run the tests to see if they pass.
|
||||||
|
|
||||||
##### Test data format
|
##### Test data format
|
||||||
|
|||||||
@@ -106,5 +106,7 @@ void* aligned_malloc(size_t size, size_t alignment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void aligned_free(void* p) {
|
void aligned_free(void* p) {
|
||||||
|
if(p) {
|
||||||
free(((void**)p)[-1]);
|
free(((void**)p)[-1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,12 +129,12 @@ void furi_string_swap(FuriString* string_1, FuriString* string_2);
|
|||||||
|
|
||||||
/** Move string_2 content to string_1.
|
/** Move string_2 content to string_1.
|
||||||
*
|
*
|
||||||
* Set the string to the other one, and destroy the other one.
|
* Copy data from one string to another and destroy the source.
|
||||||
*
|
*
|
||||||
* @param string_1 The FuriString instance 1
|
* @param destination The destination FuriString
|
||||||
* @param string_2 The FuriString instance 2
|
* @param source The source FuriString
|
||||||
*/
|
*/
|
||||||
void furi_string_move(FuriString* string_1, FuriString* string_2);
|
void furi_string_move(FuriString* destination, FuriString* source);
|
||||||
|
|
||||||
/** Compute a hash for the string.
|
/** Compute a hash for the string.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -23,12 +23,17 @@
|
|||||||
|
|
||||||
#define THREAD_MAX_STACK_SIZE (UINT16_MAX * sizeof(StackType_t))
|
#define THREAD_MAX_STACK_SIZE (UINT16_MAX * sizeof(StackType_t))
|
||||||
|
|
||||||
typedef struct FuriThreadStdout FuriThreadStdout;
|
typedef struct {
|
||||||
|
|
||||||
struct FuriThreadStdout {
|
|
||||||
FuriThreadStdoutWriteCallback write_callback;
|
FuriThreadStdoutWriteCallback write_callback;
|
||||||
FuriString* buffer;
|
FuriString* buffer;
|
||||||
};
|
void* context;
|
||||||
|
} FuriThreadStdout;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FuriThreadStdinReadCallback read_callback;
|
||||||
|
FuriString* unread_buffer; // <! stores data from `ungetc` and friends
|
||||||
|
void* context;
|
||||||
|
} FuriThreadStdin;
|
||||||
|
|
||||||
struct FuriThread {
|
struct FuriThread {
|
||||||
StaticTask_t container;
|
StaticTask_t container;
|
||||||
@@ -55,6 +60,7 @@ struct FuriThread {
|
|||||||
size_t heap_size;
|
size_t heap_size;
|
||||||
|
|
||||||
FuriThreadStdout output;
|
FuriThreadStdout output;
|
||||||
|
FuriThreadStdin input;
|
||||||
|
|
||||||
// Keep all non-alignable byte types in one place,
|
// Keep all non-alignable byte types in one place,
|
||||||
// this ensures that the size of this structure is minimal
|
// this ensures that the size of this structure is minimal
|
||||||
@@ -136,6 +142,7 @@ static void furi_thread_body(void* context) {
|
|||||||
|
|
||||||
static void furi_thread_init_common(FuriThread* thread) {
|
static void furi_thread_init_common(FuriThread* thread) {
|
||||||
thread->output.buffer = furi_string_alloc();
|
thread->output.buffer = furi_string_alloc();
|
||||||
|
thread->input.unread_buffer = furi_string_alloc();
|
||||||
|
|
||||||
FuriThread* parent = NULL;
|
FuriThread* parent = NULL;
|
||||||
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
|
||||||
@@ -245,6 +252,7 @@ void furi_thread_free(FuriThread* thread) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
furi_string_free(thread->output.buffer);
|
furi_string_free(thread->output.buffer);
|
||||||
|
furi_string_free(thread->input.unread_buffer);
|
||||||
free(thread);
|
free(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,13 +718,22 @@ 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) {
|
static size_t __furi_thread_stdout_write(FuriThread* thread, const char* data, size_t size) {
|
||||||
if(thread->output.write_callback != NULL) {
|
if(thread->output.write_callback != NULL) {
|
||||||
thread->output.write_callback(data, size);
|
thread->output.write_callback(data, size, thread->output.context);
|
||||||
} else {
|
} else {
|
||||||
furi_log_tx((const uint8_t*)data, size);
|
furi_log_tx((const uint8_t*)data, size);
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, thread->input.context);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t __furi_thread_stdout_flush(FuriThread* thread) {
|
static int32_t __furi_thread_stdout_flush(FuriThread* thread) {
|
||||||
FuriString* buffer = thread->output.buffer;
|
FuriString* buffer = thread->output.buffer;
|
||||||
size_t size = furi_string_size(buffer);
|
size_t size = furi_string_size(buffer);
|
||||||
@@ -727,19 +744,33 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) {
|
|
||||||
FuriThread* thread = furi_thread_get_current();
|
|
||||||
furi_check(thread);
|
|
||||||
__furi_thread_stdout_flush(thread);
|
|
||||||
thread->output.write_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void) {
|
FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void) {
|
||||||
FuriThread* thread = furi_thread_get_current();
|
FuriThread* thread = furi_thread_get_current();
|
||||||
furi_check(thread);
|
furi_check(thread);
|
||||||
return thread->output.write_callback;
|
return thread->output.write_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void) {
|
||||||
|
FuriThread* thread = furi_thread_get_current();
|
||||||
|
furi_check(thread);
|
||||||
|
return thread->input.read_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* 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) {
|
size_t furi_thread_stdout_write(const char* data, size_t size) {
|
||||||
FuriThread* thread = furi_thread_get_current();
|
FuriThread* thread = furi_thread_get_current();
|
||||||
furi_check(thread);
|
furi_check(thread);
|
||||||
@@ -772,6 +803,31 @@ int32_t furi_thread_stdout_flush(void) {
|
|||||||
return __furi_thread_stdout_flush(thread);
|
return __furi_thread_stdout_flush(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t furi_thread_stdin_read(char* buffer, size_t size, FuriWait timeout) {
|
||||||
|
FuriThread* thread = furi_thread_get_current();
|
||||||
|
furi_check(thread);
|
||||||
|
|
||||||
|
size_t from_buffer = MIN(furi_string_size(thread->input.unread_buffer), size);
|
||||||
|
size_t from_input = size - from_buffer;
|
||||||
|
size_t from_input_actual =
|
||||||
|
__furi_thread_stdin_read(thread, buffer + from_buffer, from_input, timeout);
|
||||||
|
memcpy(buffer, furi_string_get_cstr(thread->input.unread_buffer), from_buffer);
|
||||||
|
furi_string_right(thread->input.unread_buffer, from_buffer);
|
||||||
|
|
||||||
|
return from_buffer + from_input_actual;
|
||||||
|
}
|
||||||
|
|
||||||
|
void furi_thread_stdin_unread(char* buffer, size_t size) {
|
||||||
|
FuriThread* thread = furi_thread_get_current();
|
||||||
|
furi_check(thread);
|
||||||
|
|
||||||
|
FuriString* new_buf = furi_string_alloc(); // there's no furi_string_alloc_set_strn :(
|
||||||
|
furi_string_set_strn(new_buf, buffer, size);
|
||||||
|
furi_string_cat(new_buf, thread->input.unread_buffer);
|
||||||
|
furi_string_free(thread->input.unread_buffer);
|
||||||
|
thread->input.unread_buffer = new_buf;
|
||||||
|
}
|
||||||
|
|
||||||
void furi_thread_suspend(FuriThreadId thread_id) {
|
void furi_thread_suspend(FuriThreadId thread_id) {
|
||||||
furi_check(thread_id);
|
furi_check(thread_id);
|
||||||
|
|
||||||
|
|||||||
@@ -74,8 +74,23 @@ typedef int32_t (*FuriThreadCallback)(void* context);
|
|||||||
*
|
*
|
||||||
* @param[in] data pointer to the data to be written to the standard out
|
* @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] 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
|
||||||
|
*
|
||||||
|
* The function to be used as a standard input callback MUST follow this signature.
|
||||||
|
*
|
||||||
|
* @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, void* context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief State change callback function pointer type.
|
* @brief State change callback function pointer type.
|
||||||
@@ -468,13 +483,30 @@ uint32_t furi_thread_get_stack_space(FuriThreadId thread_id);
|
|||||||
*/
|
*/
|
||||||
FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void);
|
FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the standard input callback for the current thead.
|
||||||
|
*
|
||||||
|
* @return pointer to the standard in callback function
|
||||||
|
*/
|
||||||
|
FuriThreadStdinReadCallback furi_thread_get_stdin_callback(void);
|
||||||
|
|
||||||
/** Set standard output callback for the current thread.
|
/** Set standard output callback for the current thread.
|
||||||
*
|
*
|
||||||
* @param[in] callback pointer to the callback function or NULL to clear
|
* @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* context);
|
||||||
|
|
||||||
/** Write data to buffered standard output.
|
/** Write data to buffered standard output.
|
||||||
|
*
|
||||||
|
* @note You can also use the standard C `putc`, `puts`, `printf` and friends.
|
||||||
*
|
*
|
||||||
* @param[in] data pointer to the data to be written
|
* @param[in] data pointer to the data to be written
|
||||||
* @param[in] size data size in bytes
|
* @param[in] size data size in bytes
|
||||||
@@ -489,6 +521,29 @@ size_t furi_thread_stdout_write(const char* data, size_t size);
|
|||||||
*/
|
*/
|
||||||
int32_t furi_thread_stdout_flush(void);
|
int32_t furi_thread_stdout_flush(void);
|
||||||
|
|
||||||
|
/** Read data from the standard input
|
||||||
|
*
|
||||||
|
* @note You can also use the standard C `getc`, `gets` and friends.
|
||||||
|
*
|
||||||
|
* @param[in] buffer pointer to the buffer to read data into
|
||||||
|
* @param[in] size how many bytes to read into the buffer
|
||||||
|
* @param[in] timeout how long to wait for (in ticks) before giving up
|
||||||
|
* @return number of bytes that was actually read
|
||||||
|
*/
|
||||||
|
size_t furi_thread_stdin_read(char* buffer, size_t size, FuriWait timeout);
|
||||||
|
|
||||||
|
/** Puts data back into the standard input buffer
|
||||||
|
*
|
||||||
|
* `furi_thread_stdin_read` will return the bytes in the same order that they
|
||||||
|
* were supplied to this function.
|
||||||
|
*
|
||||||
|
* @note You can also use the standard C `ungetc`.
|
||||||
|
*
|
||||||
|
* @param[in] buffer pointer to the buffer to get data from
|
||||||
|
* @param[in] size how many bytes to read from the buffer
|
||||||
|
*/
|
||||||
|
void furi_thread_stdin_unread(char* buffer, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Suspend a thread.
|
* @brief Suspend a thread.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -830,9 +830,7 @@ void elf_file_free(ELFFile* elf) {
|
|||||||
for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it);
|
for(ELFSectionDict_it(it, elf->sections); !ELFSectionDict_end_p(it);
|
||||||
ELFSectionDict_next(it)) {
|
ELFSectionDict_next(it)) {
|
||||||
const ELFSectionDict_itref_t* itref = ELFSectionDict_cref(it);
|
const ELFSectionDict_itref_t* itref = ELFSectionDict_cref(it);
|
||||||
if(itref->value.data) {
|
|
||||||
aligned_free(itref->value.data);
|
aligned_free(itref->value.data);
|
||||||
}
|
|
||||||
if(itref->value.fast_rel) {
|
if(itref->value.fast_rel) {
|
||||||
if(itref->value.fast_rel->data) {
|
if(itref->value.fast_rel->data) {
|
||||||
aligned_free(itref->value.fast_rel->data);
|
aligned_free(itref->value.fast_rel->data);
|
||||||
|
|||||||
@@ -44,18 +44,24 @@ wrapped_fn_list = [
|
|||||||
"vsiprintf",
|
"vsiprintf",
|
||||||
"vsniprintf",
|
"vsniprintf",
|
||||||
#
|
#
|
||||||
# Scanf is not implemented 4 now
|
# standard input
|
||||||
|
#
|
||||||
|
"fgetc",
|
||||||
|
"getc",
|
||||||
|
"getchar",
|
||||||
|
"fgets",
|
||||||
|
"ungetc",
|
||||||
|
#
|
||||||
|
# standard input, but unimplemented
|
||||||
|
#
|
||||||
|
"gets",
|
||||||
|
#
|
||||||
|
# scanf, not implemented for now
|
||||||
#
|
#
|
||||||
# "fscanf",
|
# "fscanf",
|
||||||
# "scanf",
|
# "scanf",
|
||||||
# "sscanf",
|
# "sscanf",
|
||||||
# "vsprintf",
|
# "vsprintf",
|
||||||
# "fgetc",
|
|
||||||
# "fgets",
|
|
||||||
# "getc",
|
|
||||||
# "getchar",
|
|
||||||
# "gets",
|
|
||||||
# "ungetc",
|
|
||||||
# "vfscanf",
|
# "vfscanf",
|
||||||
# "vscanf",
|
# "vscanf",
|
||||||
# "vsscanf",
|
# "vsscanf",
|
||||||
|
|||||||
@@ -51,11 +51,54 @@ int __wrap_snprintf(char* str, size_t size, const char* format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int __wrap_fflush(FILE* stream) {
|
int __wrap_fflush(FILE* stream) {
|
||||||
UNUSED(stream);
|
if(stream == stdout) furi_thread_stdout_flush();
|
||||||
furi_thread_stdout_flush();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __wrap_fgetc(FILE* stream) {
|
||||||
|
if(stream != stdin) return EOF;
|
||||||
|
char c;
|
||||||
|
if(furi_thread_stdin_read(&c, 1, FuriWaitForever) == 0) return EOF;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __wrap_getc(FILE* stream) {
|
||||||
|
return __wrap_fgetc(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __wrap_getchar(void) {
|
||||||
|
return __wrap_fgetc(stdin);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* __wrap_fgets(char* str, size_t n, FILE* stream) {
|
||||||
|
// leave space for the zero terminator
|
||||||
|
furi_check(n >= 1);
|
||||||
|
n--;
|
||||||
|
|
||||||
|
if(stream != stdin) {
|
||||||
|
*str = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read characters
|
||||||
|
int c;
|
||||||
|
do {
|
||||||
|
c = __wrap_fgetc(stdin);
|
||||||
|
if(c > 0) *(str++) = c;
|
||||||
|
} while(c != EOF && c != '\n' && --n);
|
||||||
|
|
||||||
|
// place zero terminator
|
||||||
|
*str = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __wrap_ungetc(int ch, FILE* stream) {
|
||||||
|
char c = ch;
|
||||||
|
if(stream != stdin) return EOF;
|
||||||
|
furi_thread_stdin_unread(&c, 1);
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__((__noreturn__)) void __wrap___assert(const char* file, int line, const char* e) {
|
__attribute__((__noreturn__)) void __wrap___assert(const char* file, int line, const char* e) {
|
||||||
UNUSED(file);
|
UNUSED(file);
|
||||||
UNUSED(line);
|
UNUSED(line);
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ int __wrap_putc(int ch, FILE* stream);
|
|||||||
int __wrap_snprintf(char* str, size_t size, const char* format, ...);
|
int __wrap_snprintf(char* str, size_t size, const char* format, ...);
|
||||||
int __wrap_fflush(FILE* stream);
|
int __wrap_fflush(FILE* stream);
|
||||||
|
|
||||||
|
int __wrap_fgetc(FILE* stream);
|
||||||
|
int __wrap_getc(FILE* stream);
|
||||||
|
int __wrap_getchar(void);
|
||||||
|
char* __wrap_fgets(char* str, size_t n, FILE* stream);
|
||||||
|
int __wrap_ungetc(int ch, FILE* stream);
|
||||||
|
|
||||||
__attribute__((__noreturn__)) void __wrap___assert(const char* file, int line, const char* e);
|
__attribute__((__noreturn__)) void __wrap___assert(const char* file, int line, const char* e);
|
||||||
|
|
||||||
__attribute__((__noreturn__)) void
|
__attribute__((__noreturn__)) void
|
||||||
|
|||||||
@@ -245,6 +245,8 @@ static Iso15693ParserCommand iso15693_parser_parse_1_out_of_256(Iso15693Parser*
|
|||||||
instance->parsed_frame, instance->next_byte_part * 4 + j / 2);
|
instance->parsed_frame, instance->next_byte_part * 4 + j / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
instance->zero_found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instance->next_byte_part = (instance->next_byte_part + 1) % 64;
|
instance->next_byte_part = (instance->next_byte_part + 1) % 64;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from flipper.app import App
|
from flipper.app import App
|
||||||
@@ -11,7 +10,10 @@ from flipper.utils.cdc import resolve_port
|
|||||||
|
|
||||||
|
|
||||||
class Main(App):
|
class Main(App):
|
||||||
# this is basic use without sub-commands, simply to reboot flipper / power it off, not meant as a full CLI wrapper
|
def __init__(self, no_exit=False):
|
||||||
|
super().__init__(no_exit)
|
||||||
|
self.test_results = None
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self.parser.add_argument("-p", "--port", help="CDC Port", default="auto")
|
self.parser.add_argument("-p", "--port", help="CDC Port", default="auto")
|
||||||
self.parser.add_argument(
|
self.parser.add_argument(
|
||||||
@@ -67,65 +69,109 @@ class Main(App):
|
|||||||
self.logger.info("Running unit tests")
|
self.logger.info("Running unit tests")
|
||||||
flipper.send("unit_tests" + "\r")
|
flipper.send("unit_tests" + "\r")
|
||||||
self.logger.info("Waiting for unit tests to complete")
|
self.logger.info("Waiting for unit tests to complete")
|
||||||
data = flipper.read.until(">: ")
|
|
||||||
self.logger.info("Parsing result")
|
|
||||||
|
|
||||||
lines = data.decode().split("\r\n")
|
|
||||||
|
|
||||||
tests_re = r"Failed tests: \d{0,}"
|
|
||||||
time_re = r"Consumed: \d{0,}"
|
|
||||||
leak_re = r"Leaked: \d{0,}"
|
|
||||||
status_re = r"Status: \w{3,}"
|
|
||||||
|
|
||||||
tests_pattern = re.compile(tests_re)
|
|
||||||
time_pattern = re.compile(time_re)
|
|
||||||
leak_pattern = re.compile(leak_re)
|
|
||||||
status_pattern = re.compile(status_re)
|
|
||||||
|
|
||||||
tests, elapsed_time, leak, status = None, None, None, None
|
tests, elapsed_time, leak, status = None, None, None, None
|
||||||
total = 0
|
total = 0
|
||||||
|
all_required_found = False
|
||||||
|
|
||||||
for line in lines:
|
full_output = []
|
||||||
|
|
||||||
|
tests_pattern = re.compile(r"Failed tests: \d{0,}")
|
||||||
|
time_pattern = re.compile(r"Consumed: \d{0,}")
|
||||||
|
leak_pattern = re.compile(r"Leaked: \d{0,}")
|
||||||
|
status_pattern = re.compile(r"Status: \w{3,}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while not all_required_found:
|
||||||
|
try:
|
||||||
|
line = flipper.read.until("\r\n", cut_eol=True).decode()
|
||||||
self.logger.info(line)
|
self.logger.info(line)
|
||||||
|
if "command not found," in line:
|
||||||
|
self.logger.error(f"Command not found: {line}")
|
||||||
|
return 1
|
||||||
|
|
||||||
if "()" in line:
|
if "()" in line:
|
||||||
total += 1
|
total += 1
|
||||||
|
self.logger.debug(f"Test completed: {line}")
|
||||||
|
|
||||||
if not tests:
|
if not tests:
|
||||||
tests = re.match(tests_pattern, line)
|
tests = tests_pattern.match(line)
|
||||||
if not elapsed_time:
|
if not elapsed_time:
|
||||||
elapsed_time = re.match(time_pattern, line)
|
elapsed_time = time_pattern.match(line)
|
||||||
if not leak:
|
if not leak:
|
||||||
leak = re.match(leak_pattern, line)
|
leak = leak_pattern.match(line)
|
||||||
if not status:
|
if not status:
|
||||||
status = re.match(status_pattern, line)
|
status = status_pattern.match(line)
|
||||||
|
|
||||||
|
pattern = re.compile(
|
||||||
|
r"(\[-]|\[\\]|\[\|]|\[/-]|\[[^\]]*\]|\x1b\[\d+D)"
|
||||||
|
)
|
||||||
|
line_to_append = pattern.sub("", line)
|
||||||
|
pattern = re.compile(r"\[3D[^\]]*")
|
||||||
|
line_to_append = pattern.sub("", line_to_append)
|
||||||
|
line_to_append = f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S,%f')} {line_to_append}"
|
||||||
|
|
||||||
|
full_output.append(line_to_append)
|
||||||
|
|
||||||
|
if tests and elapsed_time and leak and status:
|
||||||
|
all_required_found = True
|
||||||
|
try:
|
||||||
|
remaining = flipper.read.until(">: ", cut_eol=True).decode()
|
||||||
|
if remaining.strip():
|
||||||
|
full_output.append(remaining)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
break
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error reading output: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
if None in (tests, elapsed_time, leak, status):
|
if None in (tests, elapsed_time, leak, status):
|
||||||
self.logger.error(
|
raise RuntimeError(
|
||||||
f"Failed to parse output: {tests} {elapsed_time} {leak} {status}"
|
f"Failed to parse output: {tests} {elapsed_time} {leak} {status}"
|
||||||
)
|
)
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
leak = int(re.findall(r"[- ]\d+", leak.group(0))[0])
|
leak = int(re.findall(r"[- ]\d+", leak.group(0))[0])
|
||||||
status = re.findall(r"\w+", status.group(0))[1]
|
status = re.findall(r"\w+", status.group(0))[1]
|
||||||
tests = int(re.findall(r"\d+", tests.group(0))[0])
|
tests = int(re.findall(r"\d+", tests.group(0))[0])
|
||||||
elapsed_time = int(re.findall(r"\d+", elapsed_time.group(0))[0])
|
elapsed_time = int(re.findall(r"\d+", elapsed_time.group(0))[0])
|
||||||
|
|
||||||
|
test_results = {
|
||||||
|
"full_output": "\n".join(full_output),
|
||||||
|
"total_tests": total,
|
||||||
|
"failed_tests": tests,
|
||||||
|
"elapsed_time_ms": elapsed_time,
|
||||||
|
"memory_leak_bytes": leak,
|
||||||
|
"status": status,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.test_results = test_results
|
||||||
|
|
||||||
|
output_file = "unit_tests_output.txt"
|
||||||
|
with open(output_file, "w") as f:
|
||||||
|
f.write(test_results["full_output"])
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"::notice:: Total tests: {total} Failed tests: {tests} Status: {status} Elapsed time: {elapsed_time / 1000} s Memory leak: {leak} bytes"
|
||||||
|
)
|
||||||
|
|
||||||
if tests > 0 or status != "PASSED":
|
if tests > 0 or status != "PASSED":
|
||||||
self.logger.error(f"Got {tests} failed tests.")
|
self.logger.error(f"Got {tests} failed tests.")
|
||||||
self.logger.error(f"Leaked (not failing on this stat): {leak}")
|
self.logger.error(f"Leaked (not failing on this stat): {leak}")
|
||||||
self.logger.error(f"Status: {status}")
|
self.logger.error(f"Status: {status}")
|
||||||
self.logger.error(f"Time: {elapsed_time/1000} seconds")
|
self.logger.error(f"Time: {elapsed_time / 1000} seconds")
|
||||||
flipper.stop()
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
self.logger.info(f"Leaked (not failing on this stat): {leak}")
|
self.logger.info(f"Leaked (not failing on this stat): {leak}")
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
f"Tests ran successfully! Time elapsed {elapsed_time/1000} seconds. Passed {total} tests."
|
f"Tests ran successfully! Time elapsed {elapsed_time / 1000} seconds. Passed {total} tests."
|
||||||
)
|
)
|
||||||
|
|
||||||
flipper.stop()
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
finally:
|
||||||
|
flipper.stop()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
Main()()
|
Main()()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
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.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,,
|
||||||
@@ -371,11 +371,16 @@ Function,-,__utoa,char*,"unsigned, char*, int"
|
|||||||
Function,+,__wrap___assert,void,"const char*, int, const char*"
|
Function,+,__wrap___assert,void,"const char*, int, const char*"
|
||||||
Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*"
|
Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*"
|
||||||
Function,+,__wrap_fflush,int,FILE*
|
Function,+,__wrap_fflush,int,FILE*
|
||||||
|
Function,+,__wrap_fgetc,int,FILE*
|
||||||
|
Function,+,__wrap_fgets,char*,"char*, size_t, FILE*"
|
||||||
|
Function,+,__wrap_getc,int,FILE*
|
||||||
|
Function,+,__wrap_getchar,int,
|
||||||
Function,+,__wrap_printf,int,"const char*, ..."
|
Function,+,__wrap_printf,int,"const char*, ..."
|
||||||
Function,+,__wrap_putc,int,"int, FILE*"
|
Function,+,__wrap_putc,int,"int, FILE*"
|
||||||
Function,+,__wrap_putchar,int,int
|
Function,+,__wrap_putchar,int,int
|
||||||
Function,+,__wrap_puts,int,const char*
|
Function,+,__wrap_puts,int,const char*
|
||||||
Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..."
|
Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..."
|
||||||
|
Function,+,__wrap_ungetc,int,"int, FILE*"
|
||||||
Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list"
|
Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list"
|
||||||
Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..."
|
Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..."
|
||||||
Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..."
|
Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..."
|
||||||
@@ -1655,6 +1660,7 @@ 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_stdout_callback,FuriThreadStdoutWriteCallback,
|
Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback,
|
||||||
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*
|
||||||
@@ -1675,9 +1681,12 @@ Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCa
|
|||||||
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
|
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
|
||||||
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
|
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
|
||||||
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
|
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
|
||||||
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_signal,_Bool,"const FuriThread*, uint32_t, void*"
|
||||||
Function,+,furi_thread_start,void,FuriThread*
|
Function,+,furi_thread_start,void,FuriThread*
|
||||||
|
Function,+,furi_thread_stdin_read,size_t,"char*, size_t, FuriWait"
|
||||||
|
Function,+,furi_thread_stdin_unread,void,"char*, size_t"
|
||||||
Function,+,furi_thread_stdout_flush,int32_t,
|
Function,+,furi_thread_stdout_flush,int32_t,
|
||||||
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
|
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
|
||||||
Function,+,furi_thread_suspend,void,FuriThreadId
|
Function,+,furi_thread_suspend,void,FuriThreadId
|
||||||
|
|||||||
|
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,78.2,,
|
Version,+,79.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,,
|
||||||
@@ -451,11 +451,16 @@ Function,-,__utoa,char*,"unsigned, char*, int"
|
|||||||
Function,+,__wrap___assert,void,"const char*, int, const char*"
|
Function,+,__wrap___assert,void,"const char*, int, const char*"
|
||||||
Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*"
|
Function,+,__wrap___assert_func,void,"const char*, int, const char*, const char*"
|
||||||
Function,+,__wrap_fflush,int,FILE*
|
Function,+,__wrap_fflush,int,FILE*
|
||||||
|
Function,+,__wrap_fgetc,int,FILE*
|
||||||
|
Function,+,__wrap_fgets,char*,"char*, size_t, FILE*"
|
||||||
|
Function,+,__wrap_getc,int,FILE*
|
||||||
|
Function,+,__wrap_getchar,int,
|
||||||
Function,+,__wrap_printf,int,"const char*, ..."
|
Function,+,__wrap_printf,int,"const char*, ..."
|
||||||
Function,+,__wrap_putc,int,"int, FILE*"
|
Function,+,__wrap_putc,int,"int, FILE*"
|
||||||
Function,+,__wrap_putchar,int,int
|
Function,+,__wrap_putchar,int,int
|
||||||
Function,+,__wrap_puts,int,const char*
|
Function,+,__wrap_puts,int,const char*
|
||||||
Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..."
|
Function,+,__wrap_snprintf,int,"char*, size_t, const char*, ..."
|
||||||
|
Function,+,__wrap_ungetc,int,"int, FILE*"
|
||||||
Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list"
|
Function,+,__wrap_vsnprintf,int,"char*, size_t, const char*, va_list"
|
||||||
Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..."
|
Function,-,_asiprintf_r,int,"_reent*, char**, const char*, ..."
|
||||||
Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..."
|
Function,-,_asniprintf_r,char*,"_reent*, char*, size_t*, const char*, ..."
|
||||||
@@ -1918,6 +1923,7 @@ 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_stdout_callback,FuriThreadStdoutWriteCallback,
|
Function,+,furi_thread_get_stdout_callback,FuriThreadStdoutWriteCallback,
|
||||||
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*
|
||||||
@@ -1938,9 +1944,12 @@ Function,+,furi_thread_set_signal_callback,void,"FuriThread*, FuriThreadSignalCa
|
|||||||
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
|
Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t"
|
||||||
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
|
Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback"
|
||||||
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
|
Function,+,furi_thread_set_state_context,void,"FuriThread*, void*"
|
||||||
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_signal,_Bool,"const FuriThread*, uint32_t, void*"
|
||||||
Function,+,furi_thread_start,void,FuriThread*
|
Function,+,furi_thread_start,void,FuriThread*
|
||||||
|
Function,+,furi_thread_stdin_read,size_t,"char*, size_t, FuriWait"
|
||||||
|
Function,+,furi_thread_stdin_unread,void,"char*, size_t"
|
||||||
Function,+,furi_thread_stdout_flush,int32_t,
|
Function,+,furi_thread_stdout_flush,int32_t,
|
||||||
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
|
Function,+,furi_thread_stdout_write,size_t,"const char*, size_t"
|
||||||
Function,+,furi_thread_suspend,void,FuriThreadId
|
Function,+,furi_thread_suspend,void,FuriThreadId
|
||||||
|
|||||||
|
Reference in New Issue
Block a user