This commit is contained in:
Willy-JL
2024-05-21 04:10:46 +01:00
80 changed files with 1512 additions and 746 deletions

View File

@@ -91,7 +91,7 @@
"label": "[Debug:unit_tests] Flash (USB)",
"group": "build",
"type": "shell",
"command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb"
"command": "./fbt FIRMWARE_APP_SET=unit_tests FORCE=1 flash_usb_full"
},
{
"label": "[Debug] Flash (USB, with resources)",

View File

@@ -20,6 +20,9 @@
- USB/BT Remote: Added back new UI for Mouse Clicker from OFW (by @gsurkov)
- UL: USB/BT Remote: Fix Mouse Jiggler Stealth icon in BT (by @xMasterX)
- OFW: JS: Refactored and fixed `math` and `textbox` modules (by @nminaylov & @skotopes)
- OFW: GUI: Text Box rework (by @gornekich)
- OFW: Icons: Compression fixes & larger dimension support (by @hedger)
- OFW: FuriHal: Add flash ops stats, workaround bug in SHCI_C2_SetSystemClock (by @skotopes)
### Fixed:
- Storage: Fix process aliases in rename (by @Willy-JL)

View File

@@ -0,0 +1,10 @@
App(
appid="text_box_element_test",
name="Text Box Element Test",
apptype=FlipperAppType.DEBUG,
entry_point="text_box_element_test_app",
requires=["gui"],
stack_size=1 * 1024,
order=140,
fap_category="Debug",
)

View File

@@ -71,7 +71,7 @@ static void text_box_test_input_callback(InputEvent* input_event, void* ctx) {
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
}
int32_t text_box_test_app(void* p) {
int32_t text_box_element_test_app(void* p) {
UNUSED(p);
FuriMessageQueue* event_queue = furi_message_queue_alloc(32, sizeof(InputEvent));
furi_check(event_queue);

View File

@@ -1,8 +1,8 @@
App(
appid="text_box_test",
name="Text Box Test",
appid="text_box_view_test",
name="Text Box View Test",
apptype=FlipperAppType.DEBUG,
entry_point="text_box_test_app",
entry_point="text_box_view_test_app",
requires=["gui"],
stack_size=1 * 1024,
order=140,

View File

@@ -0,0 +1,133 @@
#include <furi.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/text_box.h>
#include <gui/view_stack.h>
#define TAG "TextBoxViewTest"
typedef struct {
TextBoxFont font;
TextBoxFocus focus;
const char* text;
} TextBoxViewTestContent;
static const TextBoxViewTestContent text_box_view_test_content_arr[] = {
{
.font = TextBoxFontText,
.focus = TextBoxFocusStart,
.text = "Hello, let's test text box. Press Right and Left to switch content",
},
{
.font = TextBoxFontText,
.focus = TextBoxFocusStart,
.text =
"Verify that symbols don't overlap borders: llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllend",
},
{
.font = TextBoxFontText,
.focus = TextBoxFocusStart,
.text =
"\n\n\n Start from several newline chars. Verify that scrolling doesn't break.\n\n\n\n\nThe end",
},
{
.font = TextBoxFontText,
.focus = TextBoxFocusStart,
.text =
"Let's test big text.\n\n The ARM Cortex-M is a group of 32-bit RISC ARM processor cores licensed by ARM Limited. These cores are optimized for low-cost and energy-efficient integrated circuits, which have been embedded in tens of billions of consumer devices.[1] Though they are most often the main component of microcontroller chips, sometimes they are embedded inside other types of chips too. The Cortex-M family consists of Cortex-M0,[2] Cortex-M0+,[3] Cortex-M1,[4] Cortex-M3,[5] Cortex-M4,[6] Cortex-M7,[7] Cortex-M23,[8] Cortex-M33,[9] Cortex-M35P,[10] Cortex-M52,[11] Cortex-M55,[12] Cortex-M85.[13] A floating-point unit (FPU) option is available for Cortex-M4 / M7 / M33 / M35P / M52 / M55 / M85 cores, and when included in the silicon these cores are sometimes known as \"Cortex-MxF\", where 'x' is the core variant.\n\nThe ARM Cortex-M family are ARM microprocessor cores that are designed for use in microcontrollers, ASICs, ASSPs, FPGAs, and SoCs. Cortex-M cores are commonly used as dedicated microcontroller chips, but also are hidden inside of SoC chips as power management controllers, I/O controllers, system controllers, touch screen controllers, smart battery controllers, and sensor controllers. The main difference from Cortex-A cores is that Cortex-M cores have no memory management unit (MMU) for virtual memory, considered essential for full-fledged operating systems. Cortex-M programs instead run bare metal or on one of the many real-time operating systems which support a Cortex-M.Though 8-bit microcontrollers were very popular in the past, Cortex-M has slowly been chipping away at the 8-bit market as the prices of low-end Cortex-M chips have moved downward. Cortex-M have become a popular replacements for 8-bit chips in applications that benefit from 32-bit math operations, and replacing older legacy ARM cores such as ARM7 and ARM9.",
},
{
.font = TextBoxFontText,
.focus = TextBoxFocusEnd,
.text =
"The same but with EndFocus\n\n The ARM Cortex-M is a group of 32-bit RISC ARM processor cores licensed by ARM Limited. These cores are optimized for low-cost and energy-efficient integrated circuits, which have been embedded in tens of billions of consumer devices.[1] Though they are most often the main component of microcontroller chips, sometimes they are embedded inside other types of chips too. The Cortex-M family consists of Cortex-M0,[2] Cortex-M0+,[3] Cortex-M1,[4] Cortex-M3,[5] Cortex-M4,[6] Cortex-M7,[7] Cortex-M23,[8] Cortex-M33,[9] Cortex-M35P,[10] Cortex-M52,[11] Cortex-M55,[12] Cortex-M85.[13] A floating-point unit (FPU) option is available for Cortex-M4 / M7 / M33 / M35P / M52 / M55 / M85 cores, and when included in the silicon these cores are sometimes known as \"Cortex-MxF\", where 'x' is the core variant.\n\nThe ARM Cortex-M family are ARM microprocessor cores that are designed for use in microcontrollers, ASICs, ASSPs, FPGAs, and SoCs. Cortex-M cores are commonly used as dedicated microcontroller chips, but also are hidden inside of SoC chips as power management controllers, I/O controllers, system controllers, touch screen controllers, smart battery controllers, and sensor controllers. The main difference from Cortex-A cores is that Cortex-M cores have no memory management unit (MMU) for virtual memory, considered essential for full-fledged operating systems. Cortex-M programs instead run bare metal or on one of the many real-time operating systems which support a Cortex-M.Though 8-bit microcontrollers were very popular in the past, Cortex-M has slowly been chipping away at the 8-bit market as the prices of low-end Cortex-M chips have moved downward. Cortex-M have become a popular replacements for 8-bit chips in applications that benefit from 32-bit math operations, and replacing older legacy ARM cores such as ARM7 and ARM9.",
},
{
.font = TextBoxFontHex,
.focus = TextBoxFocusEnd,
.text =
"0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999\n0000 0000 0000 0000\n1111 1111 1111 1111\n2222 2222 2222 2222\n3333 3333 3333 3333\n4444 4444 4444 4444\n5555 5555 5555 5555\n6666 6666 6666 6666\n7777 7777 7777 7777\n8888 8888 8888 8888\n9999 9999 9999 9999",
},
};
typedef struct {
TextBox* text_box;
ViewDispatcher* view_dispatcher;
size_t current_content_i;
} TextBoxViewTest;
static void text_box_update_view(TextBoxViewTest* instance) {
text_box_reset(instance->text_box);
const TextBoxViewTestContent* content =
&text_box_view_test_content_arr[instance->current_content_i];
text_box_set_font(instance->text_box, content->font);
text_box_set_focus(instance->text_box, content->focus);
text_box_set_text(instance->text_box, content->text);
}
static bool text_box_switch_view_input_callback(InputEvent* event, void* context) {
bool consumed = false;
TextBoxViewTest* instance = context;
size_t contents_cnt = COUNT_OF(text_box_view_test_content_arr);
if(event->type == InputTypeShort) {
if(event->key == InputKeyRight) {
if(instance->current_content_i < contents_cnt - 1) {
instance->current_content_i++;
text_box_update_view(instance);
consumed = true;
}
} else if(event->key == InputKeyLeft) {
if(instance->current_content_i > 0) {
instance->current_content_i--;
text_box_update_view(instance);
consumed = true;
}
} else if(event->key == InputKeyBack) {
view_dispatcher_stop(instance->view_dispatcher);
}
}
return consumed;
}
int32_t text_box_view_test_app(void* p) {
UNUSED(p);
Gui* gui = furi_record_open(RECORD_GUI);
ViewDispatcher* view_dispatcher = view_dispatcher_alloc();
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
view_dispatcher_enable_queue(view_dispatcher);
TextBoxViewTest instance = {
.text_box = text_box_alloc(),
.current_content_i = 0,
.view_dispatcher = view_dispatcher,
};
text_box_update_view(&instance);
View* text_box_switch_view = view_alloc();
view_set_input_callback(text_box_switch_view, text_box_switch_view_input_callback);
view_set_context(text_box_switch_view, &instance);
ViewStack* view_stack = view_stack_alloc();
view_stack_add_view(view_stack, text_box_switch_view);
view_stack_add_view(view_stack, text_box_get_view(instance.text_box));
view_dispatcher_add_view(view_dispatcher, 0, view_stack_get_view(view_stack));
view_dispatcher_switch_to_view(view_dispatcher, 0);
view_dispatcher_run(view_dispatcher);
view_dispatcher_remove_view(view_dispatcher, 0);
view_dispatcher_free(view_dispatcher);
view_stack_free(view_stack);
view_free(text_box_switch_view);
text_box_free(instance.text_box);
furi_record_close(RECORD_GUI);
return 0;
}

View File

@@ -2,8 +2,9 @@ App(
appid="unit_tests",
apptype=FlipperAppType.STARTUP,
entry_point="unit_tests_on_system_start",
sources=["unit_tests.c", "test_runner.c", "unit_test_api_table.cpp"],
cdefines=["APP_UNIT_TESTS"],
requires=["system_settings"],
requires=["system_settings", "subghz_start"],
provides=["delay_test"],
resources="resources",
order=100,
@@ -12,9 +13,210 @@ App(
App(
appid="delay_test",
name="Delay Test",
sources=["tests/common/*.c", "tests/rpc/*.c"],
apptype=FlipperAppType.SYSTEM,
entry_point="delay_test_app",
stack_size=1 * 1024,
requires=["unit_tests"],
order=110,
)
App(
appid="test_varint",
sources=["tests/common/*.c", "tests/varint/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_furi",
sources=["tests/common/*.c", "tests/furi/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_furi_hal",
sources=["tests/common/*.c", "tests/furi_hal/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_furi_hal_crypto",
sources=["tests/common/*.c", "tests/furi_hal_crypto/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_furi_string",
sources=["tests/common/*.c", "tests/furi_string/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_storage",
sources=["tests/common/*.c", "tests/storage/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_stream",
sources=["tests/common/*.c", "tests/stream/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_dirwalk",
sources=["tests/common/*.c", "tests/dirwalk/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_manifest",
sources=["tests/common/*.c", "tests/manifest/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_flipper_format",
sources=["tests/common/*.c", "tests/flipper_format/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_flipper_format_string",
sources=["tests/common/*.c", "tests/flipper_format_string/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_rpc",
sources=["tests/common/*.c", "tests/rpc/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_subghz",
sources=["tests/common/*.c", "tests/subghz/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_infrared",
sources=["tests/common/*.c", "tests/infrared/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_nfc",
sources=["tests/common/*.c", "tests/nfc/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_power",
sources=["tests/common/*.c", "tests/power/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_protocol_dict",
sources=["tests/common/*.c", "tests/protocol_dict/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_lfrfid",
sources=["tests/common/*.c", "tests/lfrfid/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_bit_lib",
sources=["tests/common/*.c", "tests/bit_lib/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_datetime",
sources=["tests/common/*.c", "tests/datetime/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_float_tools",
sources=["tests/common/*.c", "tests/float_tools/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_bt",
sources=["tests/common/*.c", "tests/bt/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_dialogs_file_browser_options",
sources=["tests/common/*.c", "tests/dialogs_file_browser_options/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_expansion",
sources=["tests/common/*.c", "tests/expansion/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)
App(
appid="test_compress",
sources=["tests/common/*.c", "tests/compress/*.c"],
apptype=FlipperAppType.PLUGIN,
entry_point="get_api",
requires=["unit_tests"],
)

View File

@@ -1,293 +0,0 @@
#include "../minunit.h"
#include <furi.h>
void test_furi_memmgr(void) {
void* ptr;
// allocate memory case
ptr = malloc(100);
mu_check(ptr != NULL);
// test that memory is zero-initialized after allocation
for(int i = 0; i < 100; i++) {
mu_assert_int_eq(0, ((uint8_t*)ptr)[i]);
}
free(ptr);
// reallocate memory case
ptr = malloc(100);
memset(ptr, 66, 100);
ptr = realloc(ptr, 200);
mu_check(ptr != NULL);
// test that memory is really reallocated
for(int i = 0; i < 100; i++) {
mu_assert_int_eq(66, ((uint8_t*)ptr)[i]);
}
free(ptr);
// allocate and zero-initialize array (calloc)
ptr = calloc(100, 2);
mu_check(ptr != NULL);
for(int i = 0; i < 100 * 2; i++) {
mu_assert_int_eq(0, ((uint8_t*)ptr)[i]);
}
free(ptr);
}
static void test_memmgr_malloc(const size_t allocation_size) {
uint8_t* ptr = NULL;
const char* error_message = NULL;
FURI_CRITICAL_ENTER();
ptr = malloc(allocation_size);
// test that we can allocate memory
if(ptr == NULL) {
error_message = "malloc failed";
}
// test that memory is zero-initialized after allocation
for(size_t i = 0; i < allocation_size; i++) {
if(ptr[i] != 0) {
error_message = "memory is not zero-initialized after malloc";
break;
}
}
memset(ptr, 0x55, allocation_size);
free(ptr);
// test that memory is zero-initialized after free
// we know that allocator can use this memory for inner purposes
// so we check that memory at least partially zero-initialized
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuse-after-free"
size_t zero_count = 0;
for(size_t i = 0; i < allocation_size; i++) {
if(ptr[i] == 0) {
zero_count++;
}
}
#pragma GCC diagnostic pop
// check that at least 75% of memory is zero-initialized
if(zero_count < (allocation_size * 0.75)) {
error_message = "seems that memory is not zero-initialized after free (malloc)";
}
FURI_CRITICAL_EXIT();
if(error_message != NULL) {
mu_fail(error_message);
}
}
static void test_memmgr_realloc(const size_t allocation_size) {
uint8_t* ptr = NULL;
const char* error_message = NULL;
FURI_CRITICAL_ENTER();
ptr = realloc(ptr, allocation_size);
// test that we can allocate memory
if(ptr == NULL) {
error_message = "realloc(NULL) failed";
}
// test that memory is zero-initialized after allocation
for(size_t i = 0; i < allocation_size; i++) {
if(ptr[i] != 0) {
error_message = "memory is not zero-initialized after realloc(NULL)";
break;
}
}
memset(ptr, 0x55, allocation_size);
ptr = realloc(ptr, allocation_size * 2);
// test that we can reallocate memory
if(ptr == NULL) {
error_message = "realloc failed";
}
// test that memory content is preserved
for(size_t i = 0; i < allocation_size; i++) {
if(ptr[i] != 0x55) {
error_message = "memory is not reallocated after realloc";
break;
}
}
// test that remaining memory is zero-initialized
size_t non_zero_count = 0;
for(size_t i = allocation_size; i < allocation_size * 2; i++) {
if(ptr[i] != 0) {
non_zero_count += 1;
}
}
// check that at most of memory is zero-initialized
// we know that allocator not always can restore content size from a pointer
// so we check against small threshold
if(non_zero_count > 4) {
error_message = "seems that memory is not zero-initialized after realloc";
}
uint8_t* null_ptr = realloc(ptr, 0);
// test that we can free memory
if(null_ptr != NULL) {
error_message = "realloc(0) failed";
}
// test that memory is zero-initialized after realloc(0)
// we know that allocator can use this memory for inner purposes
// so we check that memory at least partially zero-initialized
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuse-after-free"
size_t zero_count = 0;
for(size_t i = 0; i < allocation_size; i++) {
if(ptr[i] == 0) {
zero_count++;
}
}
#pragma GCC diagnostic pop
// check that at least 75% of memory is zero-initialized
if(zero_count < (allocation_size * 0.75)) {
error_message = "seems that memory is not zero-initialized after realloc(0)";
}
FURI_CRITICAL_EXIT();
if(error_message != NULL) {
mu_fail(error_message);
}
}
static void test_memmgr_alloc_aligned(const size_t allocation_size, const size_t alignment) {
uint8_t* ptr = NULL;
const char* error_message = NULL;
FURI_CRITICAL_ENTER();
ptr = aligned_alloc(alignment, allocation_size);
// test that we can allocate memory
if(ptr == NULL) {
error_message = "aligned_alloc failed";
}
// test that memory is aligned
if(((uintptr_t)ptr % alignment) != 0) {
error_message = "memory is not aligned after aligned_alloc";
}
// test that memory is zero-initialized after allocation
for(size_t i = 0; i < allocation_size; i++) {
if(ptr[i] != 0) {
error_message = "memory is not zero-initialized after aligned_alloc";
break;
}
}
memset(ptr, 0x55, allocation_size);
free(ptr);
// test that memory is zero-initialized after free
// we know that allocator can use this memory for inner purposes
// so we check that memory at least partially zero-initialized
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuse-after-free"
size_t zero_count = 0;
for(size_t i = 0; i < allocation_size; i++) {
if(ptr[i] == 0) {
zero_count++;
}
}
#pragma GCC diagnostic pop
// check that at least 75% of memory is zero-initialized
if(zero_count < (allocation_size * 0.75)) {
error_message = "seems that memory is not zero-initialized after free (aligned_alloc)";
}
FURI_CRITICAL_EXIT();
if(error_message != NULL) {
mu_fail(error_message);
}
}
void test_furi_memmgr_advanced(void) {
const size_t sizes[] = {50, 100, 500, 1000, 5000, 10000};
const size_t sizes_count = sizeof(sizes) / sizeof(sizes[0]);
const size_t alignments[] = {4, 8, 16, 32, 64, 128, 256, 512, 1024};
const size_t alignments_count = sizeof(alignments) / sizeof(alignments[0]);
// do test without memory fragmentation
{
for(size_t i = 0; i < sizes_count; i++) {
test_memmgr_malloc(sizes[i]);
}
for(size_t i = 0; i < sizes_count; i++) {
test_memmgr_realloc(sizes[i]);
}
for(size_t i = 0; i < sizes_count; i++) {
for(size_t j = 0; j < alignments_count; j++) {
test_memmgr_alloc_aligned(sizes[i], alignments[j]);
}
}
}
// do test with memory fragmentation
{
void* blocks[sizes_count];
void* guards[sizes_count - 1];
// setup guards
for(size_t i = 0; i < sizes_count; i++) {
blocks[i] = malloc(sizes[i]);
if(i < sizes_count - 1) {
guards[i] = malloc(sizes[i]);
}
}
for(size_t i = 0; i < sizes_count; i++) {
free(blocks[i]);
}
// do test
for(size_t i = 0; i < sizes_count; i++) {
test_memmgr_malloc(sizes[i]);
}
for(size_t i = 0; i < sizes_count; i++) {
test_memmgr_realloc(sizes[i]);
}
for(size_t i = 0; i < sizes_count; i++) {
for(size_t j = 0; j < alignments_count; j++) {
test_memmgr_alloc_aligned(sizes[i], alignments[j]);
}
}
// cleanup guards
for(size_t i = 0; i < sizes_count - 1; i++) {
free(guards[i]);
}
}
}

View File

@@ -1,168 +0,0 @@
#include <stdio.h>
#include <furi.h>
#include <furi_hal.h>
#include "minunit_vars.h"
#include <notification/notification_messages.h>
#include <cli/cli.h>
#include <loader/loader.h>
#define TAG "UnitTests"
int run_minunit_test_furi(void);
int run_minunit_test_furi_hal(void);
int run_minunit_test_furi_hal_crypto(void);
int run_minunit_test_furi_string(void);
int run_minunit_test_infrared(void);
int run_minunit_test_rpc(void);
int run_minunit_test_manifest(void);
int run_minunit_test_flipper_format(void);
int run_minunit_test_flipper_format_string(void);
int run_minunit_test_stream(void);
int run_minunit_test_storage(void);
int run_minunit_test_subghz(void);
int run_minunit_test_dirwalk(void);
int run_minunit_test_power(void);
int run_minunit_test_protocol_dict(void);
int run_minunit_test_lfrfid_protocols(void);
int run_minunit_test_nfc(void);
int run_minunit_test_bit_lib(void);
int run_minunit_test_datetime(void);
int run_minunit_test_float_tools(void);
int run_minunit_test_bt(void);
int run_minunit_test_dialogs_file_browser_options(void);
int run_minunit_test_expansion(void);
typedef int (*UnitTestEntry)(void);
typedef struct {
const char* name;
const UnitTestEntry entry;
} UnitTest;
const UnitTest unit_tests[] = {
{.name = "furi", .entry = run_minunit_test_furi},
{.name = "furi_hal", .entry = run_minunit_test_furi_hal},
{.name = "furi_hal_crypto", .entry = run_minunit_test_furi_hal_crypto},
{.name = "furi_string", .entry = run_minunit_test_furi_string},
{.name = "storage", .entry = run_minunit_test_storage},
{.name = "stream", .entry = run_minunit_test_stream},
{.name = "dirwalk", .entry = run_minunit_test_dirwalk},
{.name = "manifest", .entry = run_minunit_test_manifest},
{.name = "flipper_format", .entry = run_minunit_test_flipper_format},
{.name = "flipper_format_string", .entry = run_minunit_test_flipper_format_string},
{.name = "rpc", .entry = run_minunit_test_rpc},
{.name = "subghz", .entry = run_minunit_test_subghz},
{.name = "infrared", .entry = run_minunit_test_infrared},
{.name = "nfc", .entry = run_minunit_test_nfc},
{.name = "power", .entry = run_minunit_test_power},
{.name = "protocol_dict", .entry = run_minunit_test_protocol_dict},
{.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols},
{.name = "bit_lib", .entry = run_minunit_test_bit_lib},
{.name = "datetime", .entry = run_minunit_test_datetime},
{.name = "float_tools", .entry = run_minunit_test_float_tools},
{.name = "bt", .entry = run_minunit_test_bt},
{.name = "dialogs_file_browser_options",
.entry = run_minunit_test_dialogs_file_browser_options},
{.name = "expansion", .entry = run_minunit_test_expansion},
};
void minunit_print_progress(void) {
static const char progress[] = {'\\', '|', '/', '-'};
static uint8_t progress_counter = 0;
static uint32_t last_tick = 0;
uint32_t current_tick = furi_get_tick();
if(current_tick - last_tick > 20) {
last_tick = current_tick;
printf("[%c]\033[3D", progress[++progress_counter % COUNT_OF(progress)]);
fflush(stdout);
}
}
void minunit_print_fail(const char* str) {
printf(_FURI_LOG_CLR_E "%s\r\n" _FURI_LOG_CLR_RESET, str);
}
void minunit_printf_warning(const char* format, ...) {
FuriString* str = furi_string_alloc();
va_list args;
va_start(args, format);
furi_string_vprintf(str, format, args);
va_end(args);
printf(_FURI_LOG_CLR_W "%s\r\n" _FURI_LOG_CLR_RESET, furi_string_get_cstr(str));
furi_string_free(str);
}
void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
UNUSED(args);
UNUSED(context);
minunit_run = 0;
minunit_assert = 0;
minunit_fail = 0;
minunit_status = 0;
Loader* loader = furi_record_open(RECORD_LOADER);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
// TODO FL-3491: lock device while test running
if(loader_is_locked(loader)) {
printf("RPC: stop all applications to run tests\r\n");
notification_message(notification, &sequence_blink_magenta_100);
} else {
notification_message_block(notification, &sequence_set_only_blue_255);
uint32_t heap_before = memmgr_get_free_heap();
uint32_t cycle_counter = furi_get_tick();
for(size_t i = 0; i < COUNT_OF(unit_tests); i++) {
if(cli_cmd_interrupt_received(cli)) {
break;
}
if(furi_string_size(args)) {
if(furi_string_cmp_str(args, unit_tests[i].name) == 0) {
unit_tests[i].entry();
} else {
printf("Skipping %s\r\n", unit_tests[i].name);
}
} else {
unit_tests[i].entry();
}
}
if(minunit_run != 0) {
printf("\r\nFailed tests: %u\r\n", minunit_fail);
// Time report
cycle_counter = (furi_get_tick() - cycle_counter);
printf("Consumed: %lu ms\r\n", cycle_counter);
// Wait for tested services and apps to deallocate memory
furi_delay_ms(200);
uint32_t heap_after = memmgr_get_free_heap();
printf("Leaked: %ld\r\n", heap_before - heap_after);
// Final Report
if(minunit_fail == 0) {
notification_message(notification, &sequence_success);
printf("Status: PASSED\r\n");
} else {
notification_message(notification, &sequence_error);
printf("Status: FAILED\r\n");
}
}
}
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_LOADER);
}
void unit_tests_on_system_start(void) {
#ifdef SRV_CLI
Cli* cli = furi_record_open(RECORD_CLI);
// We need to launch apps from tests, so we cannot lock loader
cli_add_command(cli, "unit_tests", CliCommandFlagParallelSafe, unit_tests_cli, NULL);
furi_record_close(RECORD_CLI);
#endif
}

View File

@@ -0,0 +1,216 @@
#include "test_runner.h"
#include "tests/test_api.h"
#include <cli/cli.h>
#include <toolbox/path.h>
#include <loader/loader.h>
#include <storage/storage.h>
#include <notification/notification_messages.h>
#include <loader/firmware_api/firmware_api.h>
#include <flipper_application/flipper_application.h>
#include <flipper_application/api_hashtable/api_hashtable.h>
#include <flipper_application/plugins/composite_resolver.h>
extern const ElfApiInterface* const unit_tests_api_interface;
#define TAG "TestRunner"
#define PLUGINS_PATH "/ext/apps_data/unit_tests/plugins"
struct TestRunner {
Storage* storage;
Loader* loader;
NotificationApp* notification;
// Temporary used things
Cli* cli;
FuriString* args;
// ELF related stuff
CompositeApiResolver* composite_resolver;
// Report data
int minunit_run;
int minunit_assert;
int minunit_fail;
int minunit_status;
};
TestRunner* test_runner_alloc(Cli* cli, FuriString* args) {
TestRunner* instance = malloc(sizeof(TestRunner));
instance->storage = furi_record_open(RECORD_STORAGE);
instance->loader = furi_record_open(RECORD_LOADER);
instance->notification = furi_record_open(RECORD_NOTIFICATION);
instance->cli = cli;
instance->args = args;
instance->composite_resolver = composite_api_resolver_alloc();
composite_api_resolver_add(instance->composite_resolver, firmware_api_interface);
composite_api_resolver_add(instance->composite_resolver, unit_tests_api_interface);
return instance;
}
void test_runner_free(TestRunner* instance) {
furi_assert(instance);
composite_api_resolver_free(instance->composite_resolver);
furi_record_close(RECORD_NOTIFICATION);
instance->notification = NULL;
furi_record_close(RECORD_LOADER);
instance->loader = NULL;
furi_record_close(RECORD_STORAGE);
instance->storage = NULL;
free(instance);
}
static bool test_runner_run_plugin(TestRunner* instance, const char* path) {
furi_assert(instance);
FURI_LOG_D(TAG, "Loading %s", path);
FlipperApplication* lib = flipper_application_alloc(
instance->storage, composite_api_resolver_get(instance->composite_resolver));
bool result = false;
instance->minunit_fail = -1;
do {
FlipperApplicationPreloadStatus preload_res = flipper_application_preload(lib, path);
if(preload_res != FlipperApplicationPreloadStatusSuccess) {
FURI_LOG_E(TAG, "Failed to preload %s, %d", path, preload_res);
break;
}
if(!flipper_application_is_plugin(lib)) {
FURI_LOG_E(TAG, "Not a plugin %s", path);
break;
}
FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(lib);
if(load_status != FlipperApplicationLoadStatusSuccess) {
FURI_LOG_E(TAG, "Failed to load %s", path);
break;
}
const FlipperAppPluginDescriptor* app_descriptor =
flipper_application_plugin_get_descriptor(lib);
const TestApi* test = app_descriptor->entry_point;
instance->minunit_fail = test->run();
instance->minunit_run += test->get_minunit_run();
instance->minunit_assert += test->get_minunit_assert();
instance->minunit_status += test->get_minunit_status();
result = (instance->minunit_fail == 0);
} while(false);
flipper_application_free(lib);
return result;
}
static void test_runner_run_internal(TestRunner* instance) {
furi_assert(instance);
char file_name_buffer[256];
FuriString* file_name = furi_string_alloc();
FuriString* file_basename = furi_string_alloc();
File* directory = storage_file_alloc(instance->storage);
do {
if(!storage_dir_open(directory, PLUGINS_PATH)) {
FURI_LOG_E(TAG, "Failed to open directory %s", PLUGINS_PATH);
break;
}
while(true) {
if(cli_cmd_interrupt_received(instance->cli)) {
break;
}
if(!storage_dir_read(directory, NULL, file_name_buffer, sizeof(file_name_buffer))) {
break;
}
furi_string_set(file_name, file_name_buffer);
if(!furi_string_end_with_str(file_name, ".fal")) {
continue;
}
path_concat(PLUGINS_PATH, file_name_buffer, file_name);
path_extract_filename(file_name, file_basename, true);
const char* file_basename_cstr = furi_string_get_cstr(file_basename);
bool result = true;
if(furi_string_size(instance->args)) {
if(furi_string_cmp_str(instance->args, file_basename_cstr) == 0) {
result = test_runner_run_plugin(instance, furi_string_get_cstr(file_name));
} else {
printf("Skipping %s\r\n", file_basename_cstr);
}
} else {
result = test_runner_run_plugin(instance, furi_string_get_cstr(file_name));
}
if(!result) {
printf("Failed to execute test: %s\r\n", file_basename_cstr);
break;
}
}
} while(false);
storage_dir_close(directory);
storage_file_free(directory);
furi_string_free(file_name);
furi_string_free(file_basename);
}
void test_runner_run(TestRunner* instance) {
furi_assert(instance);
// TODO FL-3491: lock device while test running
if(loader_is_locked(instance->loader)) {
printf("RPC: stop all applications to run tests\r\n");
notification_message(instance->notification, &sequence_blink_magenta_100);
} else {
notification_message_block(instance->notification, &sequence_set_only_blue_255);
uint32_t heap_before = memmgr_get_free_heap();
uint32_t cycle_counter = furi_get_tick();
test_runner_run_internal(instance);
if(instance->minunit_run != 0) {
printf("\r\nFailed tests: %d\r\n", instance->minunit_fail);
// Time report
cycle_counter = (furi_get_tick() - cycle_counter);
printf("Consumed: %lu ms\r\n", cycle_counter);
// Wait for tested services and apps to deallocate memory
furi_delay_ms(200);
uint32_t heap_after = memmgr_get_free_heap();
printf("Leaked: %ld\r\n", heap_before - heap_after);
// Final Report
if(instance->minunit_fail == 0) {
notification_message(instance->notification, &sequence_success);
printf("Status: PASSED\r\n");
} else {
notification_message(instance->notification, &sequence_error);
printf("Status: FAILED\r\n");
}
}
}
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <furi.h>
typedef struct TestRunner TestRunner;
typedef struct Cli Cli;
TestRunner* test_runner_alloc(Cli* cli, FuriString* args);
void test_runner_free(TestRunner* isntance);
void test_runner_run(TestRunner* isntance);

View File

@@ -1,5 +1,5 @@
#include <furi.h>
#include "../minunit.h"
#include "../test.h"
#include <bit_lib/bit_lib.h>
MU_TEST(test_bit_lib_increment_index) {
@@ -738,3 +738,5 @@ int run_minunit_test_bit_lib(void) {
MU_RUN_SUITE(test_bit_lib);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_bit_lib)

View File

@@ -1,6 +1,6 @@
#include <furi.h>
#include <furi_hal.h>
#include "../minunit.h"
#include "../test.h"
#include <bt/bt_service/bt_keys_storage.h>
#include <storage/storage.h>
@@ -108,3 +108,5 @@ int run_minunit_test_bt(void) {
MU_RUN_SUITE(test_bt);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_bt)

View File

@@ -0,0 +1,42 @@
#include "../test.h"
#include "../minunit_vars.h"
#include <furi.h>
void minunit_print_progress(void) {
static const char progress[] = {'\\', '|', '/', '-'};
static uint8_t progress_counter = 0;
static uint32_t last_tick = 0;
uint32_t current_tick = furi_get_tick();
if(current_tick - last_tick > 20) {
last_tick = current_tick;
printf("[%c]\033[3D", progress[++progress_counter % COUNT_OF(progress)]);
fflush(stdout);
}
}
void minunit_print_fail(const char* str) {
printf(_FURI_LOG_CLR_E "%s\r\n" _FURI_LOG_CLR_RESET, str);
}
void minunit_printf_warning(const char* format, ...) {
FuriString* str = furi_string_alloc();
va_list args;
va_start(args, format);
furi_string_vprintf(str, format, args);
va_end(args);
printf(_FURI_LOG_CLR_W "%s\r\n" _FURI_LOG_CLR_RESET, furi_string_get_cstr(str));
furi_string_free(str);
}
int get_minunit_run(void) {
return minunit_run;
}
int get_minunit_assert(void) {
return minunit_assert;
}
int get_minunit_status(void) {
return minunit_status;
}

View File

@@ -0,0 +1,159 @@
#include "../test.h"
#include <toolbox/compress.h>
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_random.h>
#include <storage/storage.h>
#include <stdint.h>
#define COMPRESS_UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/compress/" path)
static void compress_test_reference_comp_decomp() {
Storage* storage = furi_record_open(RECORD_STORAGE);
File* compressed_file = storage_file_alloc(storage);
File* decompressed_file = storage_file_alloc(storage);
mu_assert(
storage_file_open(
compressed_file,
COMPRESS_UNIT_TESTS_PATH("compressed.bin"),
FSAM_READ,
FSOM_OPEN_EXISTING),
"Failed to open compressed file");
mu_assert(
storage_file_open(
decompressed_file,
COMPRESS_UNIT_TESTS_PATH("uncompressed.bin"),
FSAM_READ,
FSOM_OPEN_EXISTING),
"Failed to open decompressed file");
uint64_t compressed_ref_size = storage_file_size(compressed_file);
uint64_t decompressed_ref_size = storage_file_size(decompressed_file);
mu_assert(compressed_ref_size > 0 && decompressed_ref_size > 0, "Invalid file sizes");
uint8_t* compressed_ref_buff = malloc(compressed_ref_size);
uint8_t* decompressed_ref_buff = malloc(decompressed_ref_size);
mu_assert(
storage_file_read(compressed_file, compressed_ref_buff, compressed_ref_size) ==
compressed_ref_size,
"Failed to read compressed file");
mu_assert(
storage_file_read(decompressed_file, decompressed_ref_buff, decompressed_ref_size) ==
decompressed_ref_size,
"Failed to read decompressed file");
storage_file_free(compressed_file);
storage_file_free(decompressed_file);
furi_record_close(RECORD_STORAGE);
uint8_t* temp_buffer = malloc(1024);
Compress* comp = compress_alloc(1024);
size_t encoded_size = 0;
mu_assert(
compress_encode(
comp, decompressed_ref_buff, decompressed_ref_size, temp_buffer, 1024, &encoded_size),
"Compress failed");
mu_assert(encoded_size == compressed_ref_size, "Encoded size is not equal to reference size");
mu_assert(
memcmp(temp_buffer, compressed_ref_buff, compressed_ref_size) == 0,
"Encoded buffer is not equal to reference");
size_t decoded_size = 0;
mu_assert(
compress_decode(
comp, compressed_ref_buff, compressed_ref_size, temp_buffer, 1024, &decoded_size),
"Decompress failed");
mu_assert(
decoded_size == decompressed_ref_size, "Decoded size is not equal to reference size");
mu_assert(
memcmp(temp_buffer, decompressed_ref_buff, decompressed_ref_size) == 0,
"Decoded buffer is not equal to reference");
compress_free(comp);
free(temp_buffer);
free(compressed_ref_buff);
free(decompressed_ref_buff);
}
static void compress_test_random_comp_decomp() {
static const size_t src_buffer_size = 1024;
static const size_t encoded_buffer_size = 1024;
static const size_t small_buffer_size = src_buffer_size / 32;
// We only fill half of the buffer with random data, so if anything goes wrong, there's no overflow
static const size_t src_data_size = src_buffer_size / 2;
Compress* comp = compress_alloc(src_buffer_size);
uint8_t* src_buff = malloc(src_buffer_size);
uint8_t* encoded_buff = malloc(encoded_buffer_size);
uint8_t* decoded_buff = malloc(src_buffer_size);
uint8_t* small_buff = malloc(small_buffer_size);
furi_hal_random_fill_buf(src_buff, src_data_size);
size_t encoded_size = 0;
mu_assert(
compress_encode(
comp, src_buff, src_data_size, encoded_buff, encoded_buffer_size, &encoded_size),
"Compress failed");
mu_assert(encoded_size > 0, "Encoded size is zero");
size_t small_enc_dec_size = 0;
mu_assert(
compress_encode(
comp, src_buff, src_data_size, small_buff, small_buffer_size, &small_enc_dec_size) ==
false,
"Compress to small buffer failed");
size_t decoded_size = 0;
mu_assert(
compress_decode(
comp, encoded_buff, encoded_size, decoded_buff, src_buffer_size, &decoded_size),
"Decompress failed");
mu_assert(decoded_size == src_data_size, "Decoded size is not equal to source size");
mu_assert(
memcmp(src_buff, decoded_buff, src_data_size) == 0,
"Decoded buffer is not equal to source");
mu_assert(
compress_decode(
comp, encoded_buff, encoded_size, small_buff, small_buffer_size, &small_enc_dec_size) ==
false,
"Decompress to small buffer failed");
free(small_buff);
free(src_buff);
free(encoded_buff);
free(decoded_buff);
compress_free(comp);
}
MU_TEST_SUITE(test_compress) {
MU_RUN_TEST(compress_test_random_comp_decomp);
MU_RUN_TEST(compress_test_reference_comp_decomp);
}
int run_minunit_test_compress(void) {
MU_RUN_SUITE(test_compress);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_compress)

View File

@@ -1,5 +1,5 @@
#include <furi.h>
#include "../minunit.h"
#include "../test.h"
#include <datetime/datetime.h>
@@ -189,3 +189,5 @@ int run_minunit_test_datetime(void) {
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_datetime)

View File

@@ -1,6 +1,6 @@
#include <dialogs/dialogs.h>
#include "../minunit.h"
#include "../test.h"
MU_TEST(test_dialog_file_browser_set_basic_options_should_init_all_fields) {
mu_assert(
@@ -30,3 +30,5 @@ int run_minunit_test_dialogs_file_browser_options(void) {
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_dialogs_file_browser_options)

View File

@@ -1,4 +1,4 @@
#include "../minunit.h"
#include "../test.h"
#include <furi.h>
#include <m-dict.h>
#include <toolbox/dir_walk.h>
@@ -270,3 +270,5 @@ int run_minunit_test_dirwalk(void) {
MU_RUN_SUITE(test_dirwalk_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_dirwalk)

View File

@@ -1,4 +1,4 @@
#include "../minunit.h"
#include "../test.h"
#include <furi.h>
#include <furi_hal_random.h>
@@ -198,3 +198,5 @@ int run_minunit_test_expansion(void) {
MU_RUN_SUITE(test_expansion_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_expansion)

View File

@@ -2,7 +2,7 @@
#include <flipper_format/flipper_format.h>
#include <flipper_format/flipper_format_i.h>
#include <toolbox/stream/stream.h>
#include "../minunit.h"
#include "../test.h"
#define TEST_DIR TEST_DIR_NAME "/"
#define TEST_DIR_NAME EXT_PATH("unit_tests_tmp")
@@ -549,3 +549,5 @@ int run_minunit_test_flipper_format(void) {
MU_RUN_SUITE(flipper_format);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_flipper_format)

View File

@@ -3,7 +3,7 @@
#include <flipper_format/flipper_format_i.h>
#include <toolbox/stream/stream.h>
#include <storage/storage.h>
#include "../minunit.h"
#include "../test.h"
static const char* test_filetype = "Flipper Format test";
static const uint32_t test_version = 666;
@@ -335,3 +335,5 @@ int run_minunit_test_flipper_format_string(void) {
MU_RUN_SUITE(flipper_format_string_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_flipper_format_string)

View File

@@ -1,7 +1,7 @@
#include <float.h>
#include <float_tools.h>
#include "../minunit.h"
#include "../test.h"
MU_TEST(float_tools_equal_test) {
mu_check(float_is_equal(FLT_MAX, FLT_MAX));
@@ -58,3 +58,5 @@ int run_minunit_test_float_tools(void) {
MU_RUN_SUITE(float_tools_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_float_tools)

View File

@@ -1,7 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <furi.h>
#include "../minunit.h"
#include "../test.h"
const uint32_t context_value = 0xdeadbeef;
const uint32_t notify_value_0 = 0x12345678;

View File

@@ -1,7 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <furi.h>
#include "../minunit.h"
#include "../test.h"
#define TEST_RECORD_NAME "test/holding"

View File

@@ -1,7 +1,7 @@
#include <stdio.h>
#include <furi.h>
#include <furi_hal.h>
#include "../minunit.h"
#include "../test.h"
// v2 tests
void test_furi_create_open(void);
@@ -57,3 +57,5 @@ int run_minunit_test_furi(void) {
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_furi)

View File

@@ -4,7 +4,7 @@
#include <furi.h>
#include <furi_hal.h>
#include <lp5562_reg.h>
#include "../minunit.h"
#include "../test.h"
#include <stdlib.h>
#define DATA_SIZE 4
@@ -232,3 +232,5 @@ int run_minunit_test_furi_hal(void) {
MU_RUN_SUITE(furi_hal_i2c_ext_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_furi_hal)

View File

@@ -1,7 +1,7 @@
#include <stdio.h>
#include <furi.h>
#include <furi_hal.h>
#include "../minunit.h"
#include "../test.h"
static const uint8_t key_ctr_1[32] = {
0x77, 0x6B, 0xEF, 0xF2, 0x85, 0x1D, 0xB0, 0x6F, 0x4C, 0x8A, 0x05, 0x42, 0xC8, 0x69, 0x6F, 0x6C,
@@ -600,3 +600,5 @@ int run_minunit_test_furi_hal_crypto(void) {
MU_RUN_SUITE(furi_hal_crypto_gcm_test);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_furi_hal_crypto)

View File

@@ -1,5 +1,5 @@
#include <furi.h>
#include "../minunit.h"
#include "../test.h"
static void test_setup(void) {
}
@@ -467,3 +467,5 @@ int run_minunit_test_furi_string(void) {
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_furi_string)

View File

@@ -2,7 +2,7 @@
#include <flipper_format.h>
#include <infrared.h>
#include <common/infrared_common_i.h>
#include "../minunit.h"
#include "../test.h"
#define IR_TEST_FILES_DIR EXT_PATH("unit_tests/infrared/")
#define IR_TEST_FILE_PREFIX "test_"
@@ -549,3 +549,5 @@ int run_minunit_test_infrared(void) {
MU_RUN_SUITE(infrared_test);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_infrared)

View File

@@ -1,5 +1,5 @@
#include <furi.h>
#include "../minunit.h"
#include "../test.h"
#include <toolbox/protocols/protocol_dict.h>
#include <lfrfid/protocols/lfrfid_protocols.h>
#include <toolbox/pulse_protocols/pulse_glue.h>
@@ -551,3 +551,5 @@ int run_minunit_test_lfrfid_protocols(void) {
MU_RUN_SUITE(test_lfrfid_protocols_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_lfrfid_protocols)

View File

@@ -1,5 +1,5 @@
#include <furi.c>
#include "../minunit.h"
#include "../test.h"
#include <update_util/resources/manifest.h>
#define TAG "Manifest"
@@ -73,3 +73,5 @@ int run_minunit_test_manifest(void) {
MU_RUN_SUITE(manifest_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_manifest)

View File

@@ -24,7 +24,7 @@
#include <toolbox/keys_dict.h>
#include <nfc/nfc.h>
#include "../minunit.h"
#include "../test.h"
#define TAG "NfcTest"
@@ -820,3 +820,5 @@ int run_minunit_test_nfc(void) {
MU_RUN_SUITE(nfc);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_nfc)

View File

@@ -1,6 +1,6 @@
#include <furi.h>
#include <furi_hal.h>
#include "../minunit.h"
#include "../test.h"
static void power_test_deinit(void) {
// Try to reset to default charge voltage limit
@@ -67,3 +67,5 @@ int run_minunit_test_power(void) {
MU_RUN_SUITE(test_power_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_power)

View File

@@ -1,5 +1,5 @@
#include <furi.h>
#include "../minunit.h"
#include "../test.h"
#include <toolbox/protocols/protocol_dict.h>
typedef enum {
@@ -220,3 +220,5 @@ int run_minunit_test_protocol_dict(void) {
MU_RUN_SUITE(test_protocol_dict_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_protocol_dict)

View File

@@ -17,7 +17,7 @@
#include <lib/toolbox/path.h>
#include <m-list.h>
#include "../minunit.h"
#include "../test.h"
#include <protobuf_version.h>
#include <pb.h>
@@ -1864,3 +1864,5 @@ int32_t delay_test_app(void* p) {
return 0;
}
TEST_API_DEFINE(run_minunit_test_rpc)

View File

@@ -1,4 +1,4 @@
#include "../minunit.h"
#include "../test.h"
#include <furi.h>
#include <storage/storage.h>
@@ -712,3 +712,5 @@ int run_minunit_test_storage(void) {
MU_RUN_SUITE(test_md5_calc_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_storage)

View File

@@ -4,7 +4,7 @@
#include <toolbox/stream/file_stream.h>
#include <toolbox/stream/buffered_file_stream.h>
#include <storage/storage.h>
#include "../minunit.h"
#include "../test.h"
static const char* stream_test_data = "I write differently from what I speak, "
"I speak differently from what I think, "
@@ -530,3 +530,5 @@ int run_minunit_test_stream(void) {
MU_RUN_SUITE(stream_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_stream)

View File

@@ -1,6 +1,6 @@
#include <furi.h>
#include <furi_hal.h>
#include "../minunit.h"
#include "../test.h"
#include <lib/subghz/receiver.h>
#include <lib/subghz/transmitter.h>
#include <lib/subghz/subghz_keystore.h>
@@ -914,3 +914,5 @@ int run_minunit_test_subghz(void) {
MU_RUN_SUITE(subghz);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_subghz)

View File

@@ -0,0 +1,12 @@
#pragma once
// Framework
#include "minunit.h"
#include "test_api.h"
int get_minunit_run(void);
int get_minunit_assert(void);
int get_minunit_status(void);

View File

@@ -0,0 +1,29 @@
#pragma once
#include <flipper_application/flipper_application.h>
#define APPID "UnitTest"
#define API_VERSION (0u)
typedef struct {
int (*run)(void);
int (*get_minunit_run)(void);
int (*get_minunit_assert)(void);
int (*get_minunit_status)(void);
} TestApi;
#define TEST_API_DEFINE(entrypoint) \
const TestApi test_api = { \
.run = entrypoint, \
.get_minunit_run = get_minunit_run, \
.get_minunit_assert = get_minunit_assert, \
.get_minunit_status = get_minunit_status, \
}; \
const FlipperAppPluginDescriptor app_descriptor = { \
.appid = APPID, \
.ep_api_version = API_VERSION, \
.entry_point = &test_api, \
}; \
const FlipperAppPluginDescriptor* get_api(void) { \
return &app_descriptor; \
}

View File

@@ -1,6 +1,8 @@
#include <furi.h>
#include <furi_hal.h>
#include "../minunit.h"
#include "../test.h"
#include <toolbox/varint.h>
#include <toolbox/profiler.h>
@@ -86,3 +88,5 @@ int run_minunit_test_varint(void) {
MU_RUN_SUITE(test_varint_suite);
return MU_EXIT_CODE;
}
TEST_API_DEFINE(run_minunit_test_varint)

View File

@@ -0,0 +1,19 @@
#include <flipper_application/api_hashtable/api_hashtable.h>
#include <flipper_application/api_hashtable/compilesort.hpp>
#include "unit_test_api_table_i.h"
static_assert(!has_hash_collisions(unit_tests_api_table), "Detected API method hash collision!");
constexpr HashtableApiInterface unit_tests_hashtable_api_interface{
{
.api_version_major = 0,
.api_version_minor = 0,
.resolver_callback = &elf_resolve_from_hashtable,
},
unit_tests_api_table.cbegin(),
unit_tests_api_table.cend(),
};
extern "C" const ElfApiInterface* const unit_tests_api_interface =
&unit_tests_hashtable_api_interface;

View File

@@ -0,0 +1,29 @@
#include <update_util/resources/manifest.h>
#include <nfc/protocols/slix/slix_i.h>
#include <nfc/protocols/iso15693_3/iso15693_3_poller_i.h>
#include <FreeRTOS.h>
#include <FreeRTOS-Kernel/include/queue.h>
#include <rpc/rpc_i.h>
#include <flipper.pb.h>
static constexpr auto unit_tests_api_table = sort(create_array_t<sym_entry>(
API_METHOD(resource_manifest_reader_alloc, ResourceManifestReader*, (Storage*)),
API_METHOD(resource_manifest_reader_free, void, (ResourceManifestReader*)),
API_METHOD(resource_manifest_reader_open, bool, (ResourceManifestReader*, const char* filename)),
API_METHOD(resource_manifest_reader_next, ResourceManifestEntry*, (ResourceManifestReader*)),
API_METHOD(resource_manifest_reader_previous, ResourceManifestEntry*, (ResourceManifestReader*)),
API_METHOD(slix_process_iso15693_3_error, SlixError, (Iso15693_3Error)),
API_METHOD(iso15693_3_poller_get_data, const Iso15693_3Data*, (Iso15693_3Poller*)),
API_METHOD(rpc_system_storage_get_error, PB_CommandStatus, (FS_Error)),
API_METHOD(xQueueSemaphoreTake, BaseType_t, (QueueHandle_t, TickType_t)),
API_METHOD(vQueueDelete, void, (QueueHandle_t)),
API_METHOD(
xQueueGenericCreate,
QueueHandle_t,
(const UBaseType_t, const UBaseType_t, const uint8_t)),
API_METHOD(
xQueueGenericSend,
BaseType_t,
(QueueHandle_t, const void* const, TickType_t, const BaseType_t)),
API_VARIABLE(PB_Main_msg, PB_Main_msg_t)));

View File

@@ -0,0 +1,21 @@
#include <furi.h>
#include <cli/cli.h>
#include "test_runner.h"
void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
UNUSED(context);
TestRunner* test_runner = test_runner_alloc(cli, args);
test_runner_run(test_runner);
test_runner_free(test_runner);
}
void unit_tests_on_system_start(void) {
#ifdef SRV_CLI
Cli* cli = furi_record_open(RECORD_CLI);
cli_add_command(cli, "unit_tests", CliCommandFlagParallelSafe, unit_tests_cli, NULL);
furi_record_close(RECORD_CLI);
#endif
}

View File

@@ -14,7 +14,7 @@ App(
],
stack_size=1 * 1024,
order=1000,
sdk_headers=["bt_service/bt.h", "bt_settings.h"],
sdk_headers=["bt_service/bt.h", "bt_service/bt_keys_storage.h", "bt_settings.h"],
)
App(

View File

@@ -3,6 +3,10 @@
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct BtKeysStorage BtKeysStorage;
BtKeysStorage* bt_keys_storage_alloc(const char* keys_storage_path);
@@ -18,3 +22,7 @@ bool bt_keys_storage_load(BtKeysStorage* instance);
bool bt_keys_storage_update(BtKeysStorage* instance, uint8_t* start_addr, uint32_t size);
bool bt_keys_storage_delete(BtKeysStorage* instance);
#ifdef __cplusplus
}
#endif

View File

@@ -1,6 +1,5 @@
#include "slideshow.h"
#include <stddef.h>
#include <storage/storage.h>
#include <gui/icon.h>
#include <core/dangerous_defines.h>

View File

@@ -17,7 +17,7 @@ const CanvasFontParameters canvas_font_params[FontTotalNumber] = {
Canvas* canvas_init(void) {
Canvas* canvas = malloc(sizeof(Canvas));
canvas->compress_icon = compress_icon_alloc();
canvas->compress_icon = compress_icon_alloc(ICON_DECOMPRESSOR_BUFFER_SIZE);
// Initialize mutex
canvas->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
@@ -424,7 +424,7 @@ void canvas_draw_icon_ex(
x += canvas->offset_x;
y += canvas->offset_y;
uint8_t* icon_data = NULL;
compress_icon_decode(canvas->compress_icon, icon_get_data(icon), &icon_data);
compress_icon_decode(canvas->compress_icon, icon_get_frame_data(icon, 0), &icon_data);
canvas_draw_u8g2_bitmap(
&canvas->fb, x, y, icon_get_width(icon), icon_get_height(icon), icon_data, rotation);
}
@@ -436,7 +436,7 @@ void canvas_draw_icon(Canvas* canvas, int32_t x, int32_t y, const Icon* icon) {
x += canvas->offset_x;
y += canvas->offset_y;
uint8_t* icon_data = NULL;
compress_icon_decode(canvas->compress_icon, icon_get_data(icon), &icon_data);
compress_icon_decode(canvas->compress_icon, icon_get_frame_data(icon, 0), &icon_data);
canvas_draw_u8g2_bitmap(
&canvas->fb, x, y, icon_get_width(icon), icon_get_height(icon), icon_data, IconRotation0);
}

View File

@@ -12,6 +12,8 @@
#include <m-algo.h>
#include <furi.h>
#define ICON_DECOMPRESSOR_BUFFER_SIZE (128u * 64 / 8)
#ifdef __cplusplus
extern "C" {
#endif

View File

@@ -1,13 +1,16 @@
#include "icon.h"
#include "icon_i.h"
#include <furi.h>
uint8_t icon_get_width(const Icon* instance) {
#include <furi.h>
uint16_t icon_get_width(const Icon* instance) {
furi_check(instance);
return instance->width;
}
uint8_t icon_get_height(const Icon* instance) {
uint16_t icon_get_height(const Icon* instance) {
furi_check(instance);
return instance->height;
@@ -16,5 +19,14 @@ uint8_t icon_get_height(const Icon* instance) {
const uint8_t* icon_get_data(const Icon* instance) {
furi_check(instance);
return instance->frames[0];
return icon_get_frame_data(instance, 0);
}
uint32_t icon_get_frame_count(const Icon* instance) {
return instance->frame_count;
}
const uint8_t* icon_get_frame_data(const Icon* instance, uint32_t frame) {
furi_check(frame < instance->frame_count);
return instance->frames[frame];
}

View File

@@ -6,6 +6,7 @@
#pragma once
#include <stdint.h>
#include <core/common_defines.h>
#ifdef __cplusplus
extern "C" {
@@ -19,7 +20,7 @@ typedef struct Icon Icon;
*
* @return width in pixels
*/
uint8_t icon_get_width(const Icon* instance);
uint16_t icon_get_width(const Icon* instance);
/** Get icon height
*
@@ -27,15 +28,32 @@ uint8_t icon_get_width(const Icon* instance);
*
* @return height in pixels
*/
uint8_t icon_get_height(const Icon* instance);
uint16_t icon_get_height(const Icon* instance);
/** Get Icon XBM bitmap data
/** Get Icon XBM bitmap data for the first frame
*
* @param[in] instance pointer to Icon data
*
* @return pointer to XBM bitmap data
* @return pointer to compressed XBM bitmap data
*/
const uint8_t* icon_get_data(const Icon* instance);
FURI_DEPRECATED const uint8_t* icon_get_data(const Icon* instance);
/** Get Icon frame count
*
* @param[in] instance pointer to Icon data
*
* @return frame count
*/
uint32_t icon_get_frame_count(const Icon* instance);
/** Get Icon XBM bitmap data for a particular frame
*
* @param[in] instance pointer to Icon data
* @param[in] frame frame index
*
* @return pointer to compressed XBM bitmap data
*/
const uint8_t* icon_get_frame_data(const Icon* instance, uint32_t frame);
#ifdef __cplusplus
}

View File

@@ -4,11 +4,11 @@
*/
#pragma once
#include "icon.h"
#include <stdint.h>
struct Icon {
const uint8_t width;
const uint8_t height;
const uint16_t width;
const uint16_t height;
const uint8_t frame_count;
const uint8_t frame_rate;
const uint8_t* const* frames;

View File

@@ -4,8 +4,13 @@
#include <furi.h>
#include <stdint.h>
#define TEXT_BOX_MAX_SYMBOL_WIDTH (10)
#define TEXT_BOX_LINE_WIDTH (120)
#define TEXT_BOX_TEXT_WIDTH (120)
#define TEXT_BOX_TEXT_HEIGHT (56)
#define TEXT_BOX_MAX_LINES_PER_SCREEN (10)
#define TEXT_BOX_LINES_SCROLL_SPEED_MEDIUM (3)
#define TEXT_BOX_LINES_SCROLL_SPEED_FAST (5)
#define TEXT_BOX_LINES_SCROLL_SPEED_SATURATION (9)
struct TextBox {
View* view;
@@ -14,13 +19,19 @@ struct TextBox {
};
typedef struct {
const char* text;
char* text_pos;
FuriString* text_formatted;
int32_t scroll_pos;
int32_t scroll_num;
TextBoxFont font;
TextBoxFocus focus;
const char* text;
int32_t scroll_pos;
int32_t scroll_num;
int32_t lines_on_screen;
int32_t line_offset;
int32_t text_offset;
FuriString* text_on_screen;
FuriString* text_line;
bool formatted;
} TextBoxModel;
@@ -29,20 +40,11 @@ static void text_box_process_down(TextBox* text_box, uint8_t lines) {
text_box->view,
TextBoxModel * model,
{
if(model->scroll_pos < model->scroll_num - lines) {
if(model->scroll_pos + lines < model->scroll_num) {
model->scroll_pos += lines;
for(uint8_t i = 0; i < lines; i++) {
// Search next line start
while(*model->text_pos++ != '\n')
;
}
} else if(lines > 1) {
lines = model->scroll_num - model->scroll_pos - 1;
} else {
if(model->scroll_num > 0) {
model->scroll_pos = model->scroll_num - 1;
for(uint8_t i = 0; i < lines; i++) {
// Search next line start
while(*model->text_pos++ != '\n')
;
}
}
},
@@ -54,67 +56,194 @@ static void text_box_process_up(TextBox* text_box, uint8_t lines) {
text_box->view,
TextBoxModel * model,
{
if(model->scroll_pos > lines - 1) {
if(model->scroll_pos - lines > 0) {
model->scroll_pos -= lines;
for(uint8_t i = 0; i < lines; i++) {
// Reach last symbol of previous line
model->text_pos--;
// Search previous line start
while((model->text_pos != model->text) && (*(--model->text_pos) != '\n'))
;
if(*model->text_pos == '\n') {
model->text_pos++;
}
}
} else if(lines > 1) {
lines = model->scroll_pos;
} else {
model->scroll_pos = 0;
model->text_pos = (char*)model->text;
}
},
true);
}
static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) {
size_t i = 0;
size_t line_width = 0;
const char* str = model->text;
size_t line_num = 0;
static bool text_box_view_input_callback(InputEvent* event, void* context) {
furi_assert(context);
while(str[i] != '\0') {
char symb = str[i++];
if(symb != '\n') {
TextBox* text_box = context;
bool consumed = false;
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
int32_t scroll_speed = 1;
if(text_box->button_held_for_ticks > TEXT_BOX_LINES_SCROLL_SPEED_FAST) {
if(text_box->button_held_for_ticks % 2) {
scroll_speed = 0;
} else {
scroll_speed =
(text_box->button_held_for_ticks > TEXT_BOX_LINES_SCROLL_SPEED_SATURATION) ?
TEXT_BOX_LINES_SCROLL_SPEED_FAST :
TEXT_BOX_LINES_SCROLL_SPEED_MEDIUM;
}
}
if(event->key == InputKeyDown) {
text_box_process_down(text_box, scroll_speed);
consumed = true;
} else if(event->key == InputKeyUp) {
text_box_process_up(text_box, scroll_speed);
consumed = true;
}
text_box->button_held_for_ticks++;
} else if(event->type == InputTypeRelease) {
text_box->button_held_for_ticks = 0;
consumed = true;
}
return consumed;
}
static bool text_box_end_of_text_reached(TextBoxModel* model) {
return model->text[model->text_offset] == '\0';
}
static bool text_box_start_of_text_reached(TextBoxModel* model) {
return model->text_offset == 0;
}
static void text_box_seek_next_line(Canvas* canvas, TextBoxModel* model) {
size_t line_width = 0;
while(!text_box_end_of_text_reached(model)) {
char symb = model->text[model->text_offset];
if(symb == '\n') {
model->text_offset++;
break;
} else {
size_t glyph_width = canvas_glyph_width(canvas, symb);
if(line_width + glyph_width > TEXT_BOX_LINE_WIDTH) {
line_num++;
line_width = 0;
furi_string_push_back(model->text_formatted, '\n');
if(line_width + glyph_width > TEXT_BOX_TEXT_WIDTH) {
break;
}
line_width += glyph_width;
model->text_offset++;
}
}
}
static void text_box_seek_end_of_prev_line(TextBoxModel* model) {
do {
if(text_box_start_of_text_reached(model)) break;
model->text_offset--;
if(text_box_start_of_text_reached(model)) break;
if(model->text[model->text_offset] == '\n') {
model->text_offset--;
}
} while(false);
}
static void text_box_seek_prev_paragraph(TextBoxModel* model) {
while(!text_box_start_of_text_reached(model)) {
if(model->text[model->text_offset] == '\n') {
model->text_offset++;
break;
}
model->text_offset--;
}
}
static void text_box_seek_prev_line(Canvas* canvas, TextBoxModel* model) {
int32_t start_text_offset = model->text_offset;
text_box_seek_end_of_prev_line(model);
text_box_seek_prev_paragraph(model);
int32_t current_text_offset = model->text_offset;
while(true) {
text_box_seek_next_line(canvas, model);
if(model->text_offset == start_text_offset) {
break;
}
current_text_offset = model->text_offset;
}
model->text_offset = current_text_offset;
}
static void text_box_move_line_offset(Canvas* canvas, TextBoxModel* model, int32_t line_offset) {
if(line_offset >= 0) {
for(int32_t i = 0; i < line_offset; i++) {
text_box_seek_next_line(canvas, model);
}
} else {
line_num++;
line_width = 0;
}
furi_string_push_back(model->text_formatted, symb);
}
line_num++;
model->text = furi_string_get_cstr(model->text_formatted);
model->text_pos = (char*)model->text;
size_t lines_on_screen = 56 / canvas_current_font_height(canvas);
if(model->focus == TextBoxFocusEnd && line_num > lines_on_screen) {
// Set text position to 5th line from the end
const char* end = model->text + furi_string_size(model->text_formatted);
for(size_t i = 0; i < line_num - lines_on_screen; i++) {
while(model->text_pos < end) {
if(*model->text_pos++ == '\n') break;
for(int32_t i = 0; i < (-line_offset); i++) {
text_box_seek_prev_line(canvas, model);
}
}
model->scroll_num = line_num - (lines_on_screen - 1);
model->scroll_pos = line_num - lines_on_screen;
} else {
model->scroll_num = MAX(line_num - (lines_on_screen - 1), 0u);
}
static void text_box_update_screen_text(Canvas* canvas, TextBoxModel* model) {
furi_string_reset(model->text_on_screen);
furi_string_reset(model->text_line);
int32_t start_text_offset = model->text_offset;
for(int32_t i = 0; i < model->lines_on_screen; i++) {
int32_t current_line_text_offset = model->text_offset;
text_box_seek_next_line(canvas, model);
int32_t next_line_text_offset = model->text_offset;
furi_string_set_strn(
model->text_line,
&model->text[current_line_text_offset],
next_line_text_offset - current_line_text_offset);
size_t str_len = furi_string_size(model->text_line);
if(furi_string_get_char(model->text_line, str_len - 1) != '\n') {
furi_string_push_back(model->text_line, '\n');
}
furi_string_cat(model->text_on_screen, model->text_line);
if(text_box_end_of_text_reached(model)) break;
current_line_text_offset = next_line_text_offset;
}
model->text_offset = start_text_offset;
}
static void text_box_update_text_on_screen(Canvas* canvas, TextBoxModel* model) {
int32_t line_offset = model->scroll_pos - model->line_offset;
text_box_move_line_offset(canvas, model, line_offset);
text_box_update_screen_text(canvas, model);
model->line_offset = model->scroll_pos;
}
static void text_box_prepare_model(Canvas* canvas, TextBoxModel* model) {
int32_t lines_num = 0;
model->text_offset = 0;
model->scroll_num = 0;
model->scroll_pos = 0;
model->line_offset = 0;
model->lines_on_screen = TEXT_BOX_TEXT_HEIGHT / canvas_current_font_height(canvas);
// Cache text offset to quick final text offset update if TextBoxFocusEnd is set
int32_t window_offset[TEXT_BOX_MAX_LINES_PER_SCREEN] = {};
do {
window_offset[lines_num % model->lines_on_screen] = model->text_offset;
text_box_seek_next_line(canvas, model);
lines_num++;
} while(!text_box_end_of_text_reached(model));
lines_num++;
if(model->focus == TextBoxFocusEnd) {
if(lines_num > model->lines_on_screen) {
model->text_offset = window_offset[(lines_num - 1) % model->lines_on_screen];
}
} else {
model->text_offset = 0;
}
if(lines_num > model->lines_on_screen) {
model->scroll_num = lines_num - model->lines_on_screen;
model->scroll_pos = (model->focus == TextBoxFocusEnd) ? model->scroll_num - 1 : 0;
}
text_box_update_screen_text(canvas, model);
model->line_offset = model->scroll_pos;
}
static void text_box_view_draw_callback(Canvas* canvas, void* _model) {
@@ -132,44 +261,17 @@ static void text_box_view_draw_callback(Canvas* canvas, void* _model) {
}
if(!model->formatted) {
text_box_insert_endline(canvas, model);
text_box_prepare_model(canvas, model);
model->formatted = true;
}
elements_slightly_rounded_frame(canvas, 0, 0, 124, 64);
elements_multiline_text(canvas, 3, 11, model->text_pos);
elements_scrollbar(canvas, model->scroll_pos, model->scroll_num);
}
static bool text_box_view_input_callback(InputEvent* event, void* context) {
furi_assert(context);
TextBox* text_box = context;
bool consumed = false;
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
int32_t scroll_speed = 1;
if(text_box->button_held_for_ticks > 5) {
if(text_box->button_held_for_ticks % 2) {
scroll_speed = 0;
} else {
scroll_speed = text_box->button_held_for_ticks > 9 ? 5 : 3;
if(model->line_offset != model->scroll_pos) {
text_box_update_text_on_screen(canvas, model);
}
}
if(event->key == InputKeyDown) {
text_box_process_down(text_box, scroll_speed);
consumed = true;
} else if(event->key == InputKeyUp) {
text_box_process_up(text_box, scroll_speed);
consumed = true;
}
text_box->button_held_for_ticks++;
} else if(event->type == InputTypeRelease) {
text_box->button_held_for_ticks = 0;
consumed = true;
}
return consumed;
elements_multiline_text(canvas, 3, 11, furi_string_get_cstr(model->text_on_screen));
}
TextBox* text_box_alloc(void) {
@@ -185,7 +287,8 @@ TextBox* text_box_alloc(void) {
TextBoxModel * model,
{
model->text = NULL;
model->text_formatted = furi_string_alloc_set("");
model->text_on_screen = furi_string_alloc();
model->text_line = furi_string_alloc();
model->formatted = false;
model->font = TextBoxFontText;
},
@@ -198,7 +301,13 @@ void text_box_free(TextBox* text_box) {
furi_check(text_box);
with_view_model(
text_box->view, TextBoxModel * model, { furi_string_free(model->text_formatted); }, true);
text_box->view,
TextBoxModel * model,
{
furi_string_free(model->text_on_screen);
furi_string_free(model->text_line);
},
true);
view_free(text_box->view);
free(text_box);
}
@@ -216,9 +325,15 @@ void text_box_reset(TextBox* text_box) {
TextBoxModel * model,
{
model->text = NULL;
furi_string_set(model->text_formatted, "");
model->font = TextBoxFontText;
model->focus = TextBoxFocusStart;
furi_string_reset(model->text_line);
furi_string_reset(model->text_on_screen);
model->line_offset = 0;
model->text_offset = 0;
model->lines_on_screen = 0;
model->scroll_num = 0;
model->scroll_pos = 0;
model->formatted = false;
},
true);
@@ -227,16 +342,12 @@ void text_box_reset(TextBox* text_box) {
void text_box_set_text(TextBox* text_box, const char* text) {
furi_check(text_box);
furi_check(text);
size_t str_length = strlen(text);
size_t formating_margin = str_length * TEXT_BOX_MAX_SYMBOL_WIDTH / TEXT_BOX_LINE_WIDTH;
with_view_model(
text_box->view,
TextBoxModel * model,
{
model->text = text;
furi_string_reset(model->text_formatted);
furi_string_reserve(model->text_formatted, str_length + formating_margin);
model->formatted = false;
},
true);

View File

@@ -10,19 +10,6 @@
static_assert(!has_hash_collisions(elf_api_table), "Detected API method hash collision!");
#ifdef APP_UNIT_TESTS
constexpr HashtableApiInterface mock_elf_api_interface{
{
.api_version_major = 0,
.api_version_minor = 0,
.resolver_callback = &elf_resolve_from_hashtable,
},
nullptr,
nullptr,
};
const ElfApiInterface* const firmware_api_interface = &mock_elf_api_interface;
#else
constexpr HashtableApiInterface elf_api_interface{
{
.api_version_major = (elf_api_version >> 16),
@@ -33,7 +20,6 @@ constexpr HashtableApiInterface elf_api_interface{
elf_api_table.cend(),
};
const ElfApiInterface* const firmware_api_interface = &elf_api_interface;
#endif
extern "C" void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor) {
*major = firmware_api_interface->api_version_major;

View File

@@ -547,6 +547,12 @@ static LoaderStatus loader_start_external_app(
FURI_LOG_I(TAG, "Starting app");
if(flipper_application_is_plugin(loader->app.fap)) {
status = loader_make_status_error(
LoaderStatusErrorInternal, error_message, "Plugin %s is not runnable", path);
break;
}
loader->app.thread = flipper_application_alloc_thread(loader->app.fap, args);
FuriString* app_name = furi_string_alloc();
path_extract_filename_no_ext(path, app_name);

View File

@@ -92,7 +92,7 @@ static bool loader_applications_item_callback(
path, loader_applications_app->storage, icon_ptr, item_name);
} else {
path_extract_filename(path, item_name, false);
memcpy(*icon_ptr, icon_get_data(&I_js_script_10px), FAP_MANIFEST_MAX_ICON_SIZE);
memcpy(*icon_ptr, icon_get_frame_data(&I_js_script_10px, 0), FAP_MANIFEST_MAX_ICON_SIZE);
return true;
}
}

View File

@@ -7,6 +7,10 @@
#include <flipper.pb.h>
#include <cli/cli.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void* (*RpcSystemAlloc)(RpcSession* session);
typedef void (*RpcSystemFree)(void* context);
typedef void (*PBMessageHandler)(const PB_Main* msg_request, void* context);
@@ -45,3 +49,7 @@ void rpc_debug_print_data(const char* prefix, uint8_t* buffer, size_t size);
void rpc_cli_command_start_session(Cli* cli, FuriString* args, void* context);
PB_CommandStatus rpc_system_storage_get_error(FS_Error fs_error);
#ifdef __cplusplus
}
#endif

View File

@@ -35,6 +35,7 @@ env.Append(
File("protocols/mf_classic/mf_classic_poller.h"),
File("protocols/mf_desfire/mf_desfire_poller.h"),
File("protocols/emv/emv_poller.h"),
File("protocols/slix/slix_poller.h"),
File("protocols/st25tb/st25tb_poller.h"),
File("protocols/felica/felica_poller.h"),
# Listeners

View File

@@ -660,4 +660,4 @@ NfcError nfc_felica_listener_set_sensf_res_data(
return nfc_process_hal_error(error);
}
#endif // APP_UNIT_TESTS
#endif // FW_CFG_unit_tests

View File

@@ -13,7 +13,6 @@ env.Append(
File("registry.h"),
File("subghz_worker.h"),
File("subghz_tx_rx_worker.h"),
File("subghz_file_encoder_worker.h"),
File("transmitter.h"),
File("protocols/raw.h"),
File("protocols/public_api.h"),
@@ -27,6 +26,7 @@ env.Append(
File("subghz_protocol_registry.h"),
File("devices/cc1101_configs.h"),
File("devices/cc1101_int/cc1101_int_interconnect.h"),
File("subghz_file_encoder_worker.h"),
],
)

View File

@@ -35,6 +35,9 @@ env.Append(
File("simple_array.h"),
File("bit_buffer.h"),
File("keys_dict.h"),
File("pulse_protocols/pulse_glue.h"),
File("md5_calc.h"),
File("varint.h"),
],
)

View File

@@ -3,6 +3,9 @@
#include <furi.h>
#include <lib/heatshrink/heatshrink_encoder.h>
#include <lib/heatshrink/heatshrink_decoder.h>
#include <stdint.h>
#define TAG "Compress"
/** Defines encoder and decoder window size */
#define COMPRESS_EXP_BUFF_SIZE_LOG (8u)
@@ -10,9 +13,16 @@
/** Defines encoder and decoder lookahead buffer size */
#define COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG (4u)
/** Buffer sizes for input and output data */
#define COMPRESS_ICON_ENCODED_BUFF_SIZE (1024u)
#define COMPRESS_ICON_DECODED_BUFF_SIZE (1024u)
/** Buffer size for input data */
#define COMPRESS_ICON_ENCODED_BUFF_SIZE (256u)
static bool compress_decode_internal(
heatshrink_decoder* decoder,
const uint8_t* data_in,
size_t data_in_size,
uint8_t* data_out,
size_t data_out_size,
size_t* data_res_size);
typedef struct {
uint8_t is_compressed;
@@ -24,55 +34,51 @@ _Static_assert(sizeof(CompressHeader) == 4, "Incorrect CompressHeader size");
struct CompressIcon {
heatshrink_decoder* decoder;
uint8_t decoded_buff[COMPRESS_ICON_DECODED_BUFF_SIZE];
uint8_t* buffer;
size_t buffer_size;
};
CompressIcon* compress_icon_alloc(void) {
CompressIcon* compress_icon_alloc(size_t decode_buf_size) {
CompressIcon* instance = malloc(sizeof(CompressIcon));
instance->decoder = heatshrink_decoder_alloc(
COMPRESS_ICON_ENCODED_BUFF_SIZE,
COMPRESS_EXP_BUFF_SIZE_LOG,
COMPRESS_LOOKAHEAD_BUFF_SIZE_LOG);
heatshrink_decoder_reset(instance->decoder);
memset(instance->decoded_buff, 0, sizeof(instance->decoded_buff));
instance->buffer_size = decode_buf_size + 4; /* To account for heatshrink's poller quirks */
instance->buffer = malloc(instance->buffer_size);
return instance;
}
void compress_icon_free(CompressIcon* instance) {
furi_check(instance);
free(instance->buffer);
heatshrink_decoder_free(instance->decoder);
free(instance);
}
void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** decoded_buff) {
void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** output) {
furi_check(instance);
furi_check(icon_data);
furi_check(decoded_buff);
furi_check(output);
CompressHeader* header = (CompressHeader*)icon_data;
if(header->is_compressed) {
size_t data_processed = 0;
heatshrink_decoder_sink(
size_t decoded_size = 0;
/* If decompression fails - check that decode_buf_size is large enough */
furi_check(compress_decode_internal(
instance->decoder,
(uint8_t*)&icon_data[sizeof(CompressHeader)],
header->compressed_buff_size,
&data_processed);
while(1) {
HSD_poll_res res = heatshrink_decoder_poll(
instance->decoder,
instance->decoded_buff,
sizeof(instance->decoded_buff),
&data_processed);
furi_check((res == HSDR_POLL_EMPTY) || (res == HSDR_POLL_MORE));
if(res != HSDR_POLL_MORE) {
break;
}
}
heatshrink_decoder_reset(instance->decoder);
*decoded_buff = instance->decoded_buff;
icon_data,
/* Decoder will check/process headers again - need to pass them */
sizeof(CompressHeader) + header->compressed_buff_size,
instance->buffer,
instance->buffer_size,
&decoded_size));
*output = instance->buffer;
} else {
*decoded_buff = (uint8_t*)&icon_data[1];
*output = (uint8_t*)&icon_data[1];
}
}
@@ -81,12 +87,6 @@ struct Compress {
heatshrink_decoder* decoder;
};
static void compress_reset(Compress* compress) {
furi_assert(compress);
heatshrink_encoder_reset(compress->encoder);
heatshrink_decoder_reset(compress->decoder);
}
Compress* compress_alloc(uint16_t compress_buff_size) {
Compress* compress = malloc(sizeof(Compress));
compress->encoder =
@@ -105,16 +105,16 @@ void compress_free(Compress* compress) {
free(compress);
}
bool compress_encode(
Compress* compress,
static bool compress_encode_internal(
heatshrink_encoder* encoder,
uint8_t* data_in,
size_t data_in_size,
uint8_t* data_out,
size_t data_out_size,
size_t* data_res_size) {
furi_assert(compress);
furi_assert(data_in);
furi_assert(data_in_size);
furi_check(encoder);
furi_check(data_in);
furi_check(data_in_size);
size_t sink_size = 0;
size_t poll_size = 0;
@@ -125,10 +125,10 @@ bool compress_encode(
size_t sunk = 0;
size_t res_buff_size = sizeof(CompressHeader);
// Sink data to encoding buffer
/* Sink data to encoding buffer */
while((sunk < data_in_size) && !encode_failed) {
sink_res = heatshrink_encoder_sink(
compress->encoder, &data_in[sunk], data_in_size - sunk, &sink_size);
sink_res =
heatshrink_encoder_sink(encoder, &data_in[sunk], data_in_size - sunk, &sink_size);
if(sink_res != HSER_SINK_OK) {
encode_failed = true;
break;
@@ -136,10 +136,7 @@ bool compress_encode(
sunk += sink_size;
do {
poll_res = heatshrink_encoder_poll(
compress->encoder,
&data_out[res_buff_size],
data_out_size - res_buff_size,
&poll_size);
encoder, &data_out[res_buff_size], data_out_size - res_buff_size, &poll_size);
if(poll_res < 0) {
encode_failed = true;
break;
@@ -148,31 +145,30 @@ bool compress_encode(
} while(poll_res == HSER_POLL_MORE);
}
// Notify sinking complete and poll encoded data
finish_res = heatshrink_encoder_finish(compress->encoder);
/* Notify sinking complete and poll encoded data */
finish_res = heatshrink_encoder_finish(encoder);
if(finish_res < 0) {
encode_failed = true;
} else {
do {
poll_res = heatshrink_encoder_poll(
compress->encoder,
&data_out[res_buff_size],
data_out_size - 4 - res_buff_size,
&poll_size);
encoder, &data_out[res_buff_size], data_out_size - res_buff_size, &poll_size);
if(poll_res < 0) {
encode_failed = true;
break;
}
res_buff_size += poll_size;
finish_res = heatshrink_encoder_finish(compress->encoder);
finish_res = heatshrink_encoder_finish(encoder);
} while(finish_res != HSER_FINISH_DONE);
}
bool result = true;
// Write encoded data to output buffer if compression is efficient. Else - write header and original data
/* Write encoded data to output buffer if compression is efficient. Otherwise, write header and original data */
if(!encode_failed && (res_buff_size < data_in_size + 1)) {
CompressHeader header = {
.is_compressed = 0x01, .reserved = 0x00, .compressed_buff_size = res_buff_size};
.is_compressed = 0x01,
.reserved = 0x00,
.compressed_buff_size = res_buff_size - sizeof(CompressHeader)};
memcpy(data_out, &header, sizeof(header));
*data_res_size = res_buff_size;
} else if(data_out_size > data_in_size) {
@@ -183,22 +179,21 @@ bool compress_encode(
*data_res_size = 0;
result = false;
}
compress_reset(compress);
heatshrink_encoder_reset(encoder);
return result;
}
bool compress_decode(
Compress* compress,
uint8_t* data_in,
static bool compress_decode_internal(
heatshrink_decoder* decoder,
const uint8_t* data_in,
size_t data_in_size,
uint8_t* data_out,
size_t data_out_size,
size_t* data_res_size) {
furi_assert(compress);
furi_assert(data_in);
furi_assert(data_out);
furi_assert(data_res_size);
furi_check(decoder);
furi_check(data_in);
furi_check(data_out);
furi_check(data_res_size);
bool result = false;
bool decode_failed = false;
@@ -211,12 +206,15 @@ bool compress_decode(
CompressHeader* header = (CompressHeader*)data_in;
if(header->is_compressed) {
// Sink data to decoding buffer
/* Sink data to decoding buffer */
size_t compressed_size = header->compressed_buff_size;
size_t sunk = sizeof(CompressHeader);
size_t sunk = 0;
while(sunk < compressed_size && !decode_failed) {
sink_res = heatshrink_decoder_sink(
compress->decoder, &data_in[sunk], compressed_size - sunk, &sink_size);
decoder,
(uint8_t*)&data_in[sizeof(CompressHeader) + sunk],
compressed_size - sunk,
&sink_size);
if(sink_res < 0) {
decode_failed = true;
break;
@@ -224,25 +222,28 @@ bool compress_decode(
sunk += sink_size;
do {
poll_res = heatshrink_decoder_poll(
compress->decoder, &data_out[res_buff_size], data_out_size, &poll_size);
if(poll_res < 0) {
decoder, &data_out[res_buff_size], data_out_size - res_buff_size, &poll_size);
if((poll_res < 0) || ((data_out_size - res_buff_size) == 0)) {
decode_failed = true;
break;
}
res_buff_size += poll_size;
} while(poll_res == HSDR_POLL_MORE);
}
// Notify sinking complete and poll decoded data
/* Notify sinking complete and poll decoded data */
if(!decode_failed) {
finish_res = heatshrink_decoder_finish(compress->decoder);
finish_res = heatshrink_decoder_finish(decoder);
if(finish_res < 0) {
decode_failed = true;
} else {
do {
poll_res = heatshrink_decoder_poll(
compress->decoder, &data_out[res_buff_size], data_out_size, &poll_size);
decoder,
&data_out[res_buff_size],
data_out_size - res_buff_size,
&poll_size);
res_buff_size += poll_size;
finish_res = heatshrink_decoder_finish(compress->decoder);
finish_res = heatshrink_decoder_finish(decoder);
} while(finish_res != HSDR_FINISH_DONE);
}
}
@@ -253,9 +254,31 @@ bool compress_decode(
*data_res_size = data_in_size - 1;
result = true;
} else {
/* Not enough space in output buffer */
result = false;
}
compress_reset(compress);
heatshrink_decoder_reset(decoder);
return result;
}
bool compress_encode(
Compress* compress,
uint8_t* data_in,
size_t data_in_size,
uint8_t* data_out,
size_t data_out_size,
size_t* data_res_size) {
return compress_encode_internal(
compress->encoder, data_in, data_in_size, data_out, data_out_size, data_res_size);
}
bool compress_decode(
Compress* compress,
uint8_t* data_in,
size_t data_in_size,
uint8_t* data_out,
size_t data_out_size,
size_t* data_res_size) {
return compress_decode_internal(
compress->decoder, data_in, data_in_size, data_out, data_out_size, data_res_size);
}

View File

@@ -16,10 +16,14 @@ extern "C" {
typedef struct CompressIcon CompressIcon;
/** Initialize icon compressor
*
* @param[in] decode_buf_size The icon buffer size for decoding. Ensure that
* it's big enough for any icons that you are
* planning to decode with it.
*
* @return Compress Icon instance
*/
CompressIcon* compress_icon_alloc(void);
CompressIcon* compress_icon_alloc(size_t decode_buf_size);
/** Free icon compressor
*
@@ -29,14 +33,16 @@ void compress_icon_free(CompressIcon* instance);
/** Decompress icon
*
* @warning decoded_buff pointer set by this function is valid till next
* @warning output pointer set by this function is valid till next
* `compress_icon_decode` or `compress_icon_free` call
*
* @param instance The Compress Icon instance
* @param icon_data pointer to icon data
* @param[in] decoded_buff pointer to decoded buffer pointer
* @param icon_data pointer to icon data.
* @param[in] output pointer to decoded buffer pointer. Data in buffer is
* valid till next call. If icon data was not compressed,
* pointer within icon_data is returned
*/
void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** decoded_buff);
void compress_icon_decode(CompressIcon* instance, const uint8_t* icon_data, uint8_t** output);
/** Compress control structure */
typedef struct Compress Compress;

View File

@@ -26,8 +26,8 @@ ICONS_TEMPLATE_C_FRAME = "const uint8_t {name}[] = {data};\n"
ICONS_TEMPLATE_C_DATA = "const uint8_t* const {name}[] = {data};\n"
ICONS_TEMPLATE_C_ICONS = "Icon {name} = {{.width={width},.height={height},.frame_count={frame_count},.frame_rate={frame_rate},.frames=_{name}}};\n"
MAX_IMAGE_WIDTH = 128
MAX_IMAGE_HEIGHT = 64
MAX_IMAGE_WIDTH = 2**16 - 1
MAX_IMAGE_HEIGHT = 2**16 - 1
class Main(App):

View File

@@ -352,10 +352,10 @@ class AppBuildset:
).append(app)
def get_ext_apps(self):
return self.extapps
return list(self.extapps)
def get_incompatible_ext_apps(self):
return self.incompatible_extapps
return list(self.incompatible_extapps)
def _check_conflicts(self):
conflicts = []
@@ -400,14 +400,30 @@ class AppBuildset:
def _group_plugins(self):
known_extensions = self.get_apps_of_type(FlipperAppType.PLUGIN, all_known=True)
for extension_app in known_extensions:
keep_app = False
for parent_app_id in extension_app.requires:
try:
parent_app = self.appmgr.get(parent_app_id)
parent_app._plugins.append(extension_app)
if (
parent_app.apptype in self.BUILTIN_APP_TYPES
and parent_app_id in self.appnames
) or parent_app.apptype not in self.BUILTIN_APP_TYPES:
keep_app |= True
except FlipperManifestException:
self._writer(
f"Module {extension_app.appid} has unknown parent {parent_app_id}"
)
keep_app = True
# Debug output for plugin parentage
# print(
# f"Module {extension_app.appid} has parents {extension_app.requires} keep={keep_app}"
# )
if not keep_app and extension_app in self.extapps:
# print(f"Excluding plugin {extension_app.appid}")
self.extapps.remove(extension_app)
def get_apps_cdefs(self):
cdefs = set()
@@ -433,9 +449,11 @@ class AppBuildset:
return sorted(
filter(
lambda app: app.apptype == apptype,
(
self.appmgr.known_apps.values()
if all_known
else map(self.appmgr.get, self.appnames),
else map(self.appmgr.get, self.appnames)
),
),
key=lambda app: app.order,
)

View File

@@ -497,6 +497,7 @@ def _gather_app_components(env, appname) -> AppDeploymentComponents:
else:
# host app is a built-in app
components.add_app(artifacts_app_to_run)
if host_app.name:
components.extra_launch_args = f"-a {host_app.name}"
else:
raise UserError("Host app is unknown")

View File

@@ -198,6 +198,7 @@ def gen_sdk_data(sdk_cache: SdkCache):
api_def.extend(
(f"#include <{h.name}>" for h in sdk_cache.get_headers()),
)
api_def.append('#pragma GCC diagnostic ignored "-Wdeprecated-declarations"')
api_def.append(f"const int elf_api_version = {sdk_cache.version.as_int()};")

View File

@@ -1,6 +1,7 @@
entry,status,name,type,params
Version,+,61.2,,
Version,+,62.3,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
Header,+,applications/services/dialogs/dialogs.h,,
@@ -156,10 +157,12 @@ Header,+,lib/toolbox/hex.h,,
Header,+,lib/toolbox/keys_dict.h,,
Header,+,lib/toolbox/manchester_decoder.h,,
Header,+,lib/toolbox/manchester_encoder.h,,
Header,+,lib/toolbox/md5_calc.h,,
Header,+,lib/toolbox/name_generator.h,,
Header,+,lib/toolbox/path.h,,
Header,+,lib/toolbox/pretty_format.h,,
Header,+,lib/toolbox/protocols/protocol_dict.h,,
Header,+,lib/toolbox/pulse_protocols/pulse_glue.h,,
Header,+,lib/toolbox/saved_struct.h,,
Header,+,lib/toolbox/simple_array.h,,
Header,+,lib/toolbox/stream/buffered_file_stream.h,,
@@ -168,6 +171,7 @@ Header,+,lib/toolbox/stream/stream.h,,
Header,+,lib/toolbox/stream/string_stream.h,,
Header,+,lib/toolbox/tar/tar_archive.h,,
Header,+,lib/toolbox/value_index.h,,
Header,+,lib/toolbox/varint.h,,
Header,+,lib/toolbox/version.h,,
Header,+,targets/f18/furi_hal/furi_hal_resources.h,,
Header,+,targets/f18/furi_hal/furi_hal_spi_config.h,,
@@ -678,8 +682,15 @@ Function,+,ble_svc_serial_update_tx,_Bool,"BleServiceSerial*, uint8_t*, uint16_t
Function,-,bsearch,void*,"const void*, const void*, size_t, size_t, __compar_fn_t"
Function,+,bt_disconnect,void,Bt*
Function,+,bt_forget_bonded_devices,void,Bt*
Function,+,bt_keys_storage_alloc,BtKeysStorage*,const char*
Function,+,bt_keys_storage_delete,_Bool,BtKeysStorage*
Function,+,bt_keys_storage_free,void,BtKeysStorage*
Function,+,bt_keys_storage_load,_Bool,BtKeysStorage*
Function,+,bt_keys_storage_set_default_path,void,Bt*
Function,+,bt_keys_storage_set_file_path,void,"BtKeysStorage*, const char*"
Function,+,bt_keys_storage_set_ram_params,void,"BtKeysStorage*, uint8_t*, uint16_t"
Function,+,bt_keys_storage_set_storage_path,void,"Bt*, const char*"
Function,+,bt_keys_storage_update,_Bool,"BtKeysStorage*, uint8_t*, uint32_t"
Function,+,bt_profile_restore_default,_Bool,Bt*
Function,+,bt_profile_start,FuriHalBleProfileBase*,"Bt*, const FuriHalBleProfileTemplate*, FuriHalBleProfileParams"
Function,+,bt_set_status_changed_callback,void,"Bt*, BtStatusChangedCallback, void*"
@@ -771,7 +782,7 @@ Function,+,compress_alloc,Compress*,uint16_t
Function,+,compress_decode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*"
Function,+,compress_encode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*"
Function,+,compress_free,void,Compress*
Function,+,compress_icon_alloc,CompressIcon*,
Function,+,compress_icon_alloc,CompressIcon*,size_t
Function,+,compress_icon_decode,void,"CompressIcon*, const uint8_t*, uint8_t**"
Function,+,compress_icon_free,void,CompressIcon*
Function,-,copysign,double,"double, double"
@@ -1488,7 +1499,7 @@ Function,+,furi_mutex_free,void,FuriMutex*
Function,+,furi_mutex_get_owner,FuriThreadId,FuriMutex*
Function,+,furi_mutex_release,FuriStatus,FuriMutex*
Function,+,furi_pubsub_alloc,FuriPubSub*,
Function,-,furi_pubsub_free,void,FuriPubSub*
Function,+,furi_pubsub_free,void,FuriPubSub*
Function,+,furi_pubsub_publish,void,"FuriPubSub*, void*"
Function,+,furi_pubsub_subscribe,FuriPubSubSubscription*,"FuriPubSub*, FuriPubSubCallback, void*"
Function,+,furi_pubsub_unsubscribe,void,"FuriPubSub*, FuriPubSubSubscription*"
@@ -1673,8 +1684,10 @@ Function,+,icon_animation_set_update_callback,void,"IconAnimation*, IconAnimatio
Function,+,icon_animation_start,void,IconAnimation*
Function,+,icon_animation_stop,void,IconAnimation*
Function,+,icon_get_data,const uint8_t*,const Icon*
Function,+,icon_get_height,uint8_t,const Icon*
Function,+,icon_get_width,uint8_t,const Icon*
Function,+,icon_get_frame_count,uint32_t,const Icon*
Function,+,icon_get_frame_data,const uint8_t*,"const Icon*, uint32_t"
Function,+,icon_get_height,uint16_t,const Icon*
Function,+,icon_get_width,uint16_t,const Icon*
Function,-,ilogb,int,double
Function,-,ilogbf,int,float
Function,-,ilogbl,int,long double
@@ -1978,6 +1991,8 @@ Function,-,mbedtls_sha256_update,int,"mbedtls_sha256_context*, const unsigned ch
Function,-,mblen,int,"const char*, size_t"
Function,-,mbstowcs,size_t,"wchar_t*, const char*, size_t"
Function,-,mbtowc,int,"wchar_t*, const char*, size_t"
Function,+,md5_calc_file,_Bool,"File*, const char*, unsigned char[16], FS_Error*"
Function,+,md5_string_calc_file,_Bool,"File*, const char*, FuriString*, FS_Error*"
Function,-,memccpy,void*,"void*, const void*, int, size_t"
Function,+,memchr,void*,"const void*, int, size_t"
Function,+,memcmp,int,"const void*, const void*, size_t"
@@ -2252,6 +2267,11 @@ Function,+,protocol_dict_render_brief_data,void,"ProtocolDict*, FuriString*, siz
Function,+,protocol_dict_render_data,void,"ProtocolDict*, FuriString*, size_t"
Function,+,protocol_dict_render_uid,void,"ProtocolDict*, FuriString*, size_t"
Function,+,protocol_dict_set_data,void,"ProtocolDict*, size_t, const uint8_t*, size_t"
Function,+,pulse_glue_alloc,PulseGlue*,
Function,+,pulse_glue_free,void,PulseGlue*
Function,+,pulse_glue_pop,void,"PulseGlue*, uint32_t*, uint32_t*"
Function,+,pulse_glue_push,_Bool,"PulseGlue*, _Bool, uint32_t"
Function,+,pulse_glue_reset,void,PulseGlue*
Function,-,pulse_reader_alloc,PulseReader*,"const GpioPin*, uint32_t"
Function,-,pulse_reader_free,void,PulseReader*
Function,-,pulse_reader_receive,uint32_t,"PulseReader*, int"
@@ -2640,6 +2660,12 @@ Function,+,variable_item_list_set_selected_item,void,"VariableItemList*, uint8_t
Function,+,variable_item_set_current_value_index,void,"VariableItem*, uint8_t"
Function,+,variable_item_set_current_value_text,void,"VariableItem*, const char*"
Function,+,variable_item_set_values_count,void,"VariableItem*, uint8_t"
Function,+,varint_int32_length,size_t,int32_t
Function,+,varint_int32_pack,size_t,"int32_t, uint8_t*"
Function,+,varint_int32_unpack,size_t,"int32_t*, const uint8_t*, size_t"
Function,+,varint_uint32_length,size_t,uint32_t
Function,+,varint_uint32_pack,size_t,"uint32_t, uint8_t*"
Function,+,varint_uint32_unpack,size_t,"uint32_t*, const uint8_t*, size_t"
Function,-,vasiprintf,int,"char**, const char*, __gnuc_va_list"
Function,-,vasniprintf,char*,"char*, size_t*, const char*, __gnuc_va_list"
Function,-,vasnprintf,char*,"char*, size_t*, const char*, __gnuc_va_list"
1 entry status name type params
2 Version + 61.2 62.3
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/bt/bt_service/bt_keys_storage.h
5 Header + applications/services/cli/cli.h
6 Header + applications/services/cli/cli_vcp.h
7 Header + applications/services/dialogs/dialogs.h
157 Header + lib/toolbox/keys_dict.h
158 Header + lib/toolbox/manchester_decoder.h
159 Header + lib/toolbox/manchester_encoder.h
160 Header + lib/toolbox/md5_calc.h
161 Header + lib/toolbox/name_generator.h
162 Header + lib/toolbox/path.h
163 Header + lib/toolbox/pretty_format.h
164 Header + lib/toolbox/protocols/protocol_dict.h
165 Header + lib/toolbox/pulse_protocols/pulse_glue.h
166 Header + lib/toolbox/saved_struct.h
167 Header + lib/toolbox/simple_array.h
168 Header + lib/toolbox/stream/buffered_file_stream.h
171 Header + lib/toolbox/stream/string_stream.h
172 Header + lib/toolbox/tar/tar_archive.h
173 Header + lib/toolbox/value_index.h
174 Header + lib/toolbox/varint.h
175 Header + lib/toolbox/version.h
176 Header + targets/f18/furi_hal/furi_hal_resources.h
177 Header + targets/f18/furi_hal/furi_hal_spi_config.h
682 Function - bsearch void* const void*, const void*, size_t, size_t, __compar_fn_t
683 Function + bt_disconnect void Bt*
684 Function + bt_forget_bonded_devices void Bt*
685 Function + bt_keys_storage_alloc BtKeysStorage* const char*
686 Function + bt_keys_storage_delete _Bool BtKeysStorage*
687 Function + bt_keys_storage_free void BtKeysStorage*
688 Function + bt_keys_storage_load _Bool BtKeysStorage*
689 Function + bt_keys_storage_set_default_path void Bt*
690 Function + bt_keys_storage_set_file_path void BtKeysStorage*, const char*
691 Function + bt_keys_storage_set_ram_params void BtKeysStorage*, uint8_t*, uint16_t
692 Function + bt_keys_storage_set_storage_path void Bt*, const char*
693 Function + bt_keys_storage_update _Bool BtKeysStorage*, uint8_t*, uint32_t
694 Function + bt_profile_restore_default _Bool Bt*
695 Function + bt_profile_start FuriHalBleProfileBase* Bt*, const FuriHalBleProfileTemplate*, FuriHalBleProfileParams
696 Function + bt_set_status_changed_callback void Bt*, BtStatusChangedCallback, void*
782 Function + compress_decode _Bool Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*
783 Function + compress_encode _Bool Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*
784 Function + compress_free void Compress*
785 Function + compress_icon_alloc CompressIcon* size_t
786 Function + compress_icon_decode void CompressIcon*, const uint8_t*, uint8_t**
787 Function + compress_icon_free void CompressIcon*
788 Function - copysign double double, double
1499 Function + furi_mutex_get_owner FuriThreadId FuriMutex*
1500 Function + furi_mutex_release FuriStatus FuriMutex*
1501 Function + furi_pubsub_alloc FuriPubSub*
1502 Function - + furi_pubsub_free void FuriPubSub*
1503 Function + furi_pubsub_publish void FuriPubSub*, void*
1504 Function + furi_pubsub_subscribe FuriPubSubSubscription* FuriPubSub*, FuriPubSubCallback, void*
1505 Function + furi_pubsub_unsubscribe void FuriPubSub*, FuriPubSubSubscription*
1684 Function + icon_animation_start void IconAnimation*
1685 Function + icon_animation_stop void IconAnimation*
1686 Function + icon_get_data const uint8_t* const Icon*
1687 Function + icon_get_height icon_get_frame_count uint8_t uint32_t const Icon*
1688 Function + icon_get_width icon_get_frame_data uint8_t const uint8_t* const Icon* const Icon*, uint32_t
1689 Function + icon_get_height uint16_t const Icon*
1690 Function + icon_get_width uint16_t const Icon*
1691 Function - ilogb int double
1692 Function - ilogbf int float
1693 Function - ilogbl int long double
1991 Function - mblen int const char*, size_t
1992 Function - mbstowcs size_t wchar_t*, const char*, size_t
1993 Function - mbtowc int wchar_t*, const char*, size_t
1994 Function + md5_calc_file _Bool File*, const char*, unsigned char[16], FS_Error*
1995 Function + md5_string_calc_file _Bool File*, const char*, FuriString*, FS_Error*
1996 Function - memccpy void* void*, const void*, int, size_t
1997 Function + memchr void* const void*, int, size_t
1998 Function + memcmp int const void*, const void*, size_t
2267 Function + protocol_dict_render_data void ProtocolDict*, FuriString*, size_t
2268 Function + protocol_dict_render_uid void ProtocolDict*, FuriString*, size_t
2269 Function + protocol_dict_set_data void ProtocolDict*, size_t, const uint8_t*, size_t
2270 Function + pulse_glue_alloc PulseGlue*
2271 Function + pulse_glue_free void PulseGlue*
2272 Function + pulse_glue_pop void PulseGlue*, uint32_t*, uint32_t*
2273 Function + pulse_glue_push _Bool PulseGlue*, _Bool, uint32_t
2274 Function + pulse_glue_reset void PulseGlue*
2275 Function - pulse_reader_alloc PulseReader* const GpioPin*, uint32_t
2276 Function - pulse_reader_free void PulseReader*
2277 Function - pulse_reader_receive uint32_t PulseReader*, int
2660 Function + variable_item_set_current_value_index void VariableItem*, uint8_t
2661 Function + variable_item_set_current_value_text void VariableItem*, const char*
2662 Function + variable_item_set_values_count void VariableItem*, uint8_t
2663 Function + varint_int32_length size_t int32_t
2664 Function + varint_int32_pack size_t int32_t, uint8_t*
2665 Function + varint_int32_unpack size_t int32_t*, const uint8_t*, size_t
2666 Function + varint_uint32_length size_t uint32_t
2667 Function + varint_uint32_pack size_t uint32_t, uint8_t*
2668 Function + varint_uint32_unpack size_t uint32_t*, const uint8_t*, size_t
2669 Function - vasiprintf int char**, const char*, __gnuc_va_list
2670 Function - vasniprintf char* char*, size_t*, const char*, __gnuc_va_list
2671 Function - vasnprintf char* char*, size_t*, const char*, __gnuc_va_list

View File

@@ -31,7 +31,6 @@
"mjs",
"mbedtls",
"flipper_application",
"toolbox",
"u8g2",
"nanopb",
"update_util",
@@ -39,6 +38,7 @@
"flipperformat",
"flipper18",
"bit_lib",
"toolbox",
"datetime"
],
"excluded_sources": [

View File

@@ -1,10 +1,11 @@
entry,status,name,type,params
Version,+,61.2,,
Version,+,62.3,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/main/archive/helpers/archive_helpers_ext.h,,
Header,+,applications/main/subghz/subghz_fap.h,,
Header,+,applications/services/applications.h,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Header,+,applications/services/bt/bt_settings.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@@ -173,6 +174,7 @@ Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.h,,
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h,,
Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h,,
Header,+,lib/nfc/protocols/slix/slix.h,,
Header,+,lib/nfc/protocols/slix/slix_poller.h,,
Header,+,lib/nfc/protocols/st25tb/st25tb.h,,
Header,+,lib/nfc/protocols/st25tb/st25tb_poller.h,,
Header,+,lib/nfc/protocols/st25tb/st25tb_poller_sync.h,,
@@ -239,10 +241,12 @@ Header,+,lib/toolbox/hex.h,,
Header,+,lib/toolbox/keys_dict.h,,
Header,+,lib/toolbox/manchester_decoder.h,,
Header,+,lib/toolbox/manchester_encoder.h,,
Header,+,lib/toolbox/md5_calc.h,,
Header,+,lib/toolbox/name_generator.h,,
Header,+,lib/toolbox/path.h,,
Header,+,lib/toolbox/pretty_format.h,,
Header,+,lib/toolbox/protocols/protocol_dict.h,,
Header,+,lib/toolbox/pulse_protocols/pulse_glue.h,,
Header,+,lib/toolbox/saved_struct.h,,
Header,+,lib/toolbox/simple_array.h,,
Header,+,lib/toolbox/stream/buffered_file_stream.h,,
@@ -251,6 +255,7 @@ Header,+,lib/toolbox/stream/stream.h,,
Header,+,lib/toolbox/stream/string_stream.h,,
Header,+,lib/toolbox/tar/tar_archive.h,,
Header,+,lib/toolbox/value_index.h,,
Header,+,lib/toolbox/varint.h,,
Header,+,lib/toolbox/version.h,,
Header,+,targets/f7/ble_glue/furi_ble/event_dispatcher.h,,
Header,+,targets/f7/ble_glue/furi_ble/gatt.h,,
@@ -779,8 +784,15 @@ Function,-,bsearch,void*,"const void*, const void*, size_t, size_t, __compar_fn_
Function,-,bt_close_rpc_connection,void,Bt*
Function,+,bt_disconnect,void,Bt*
Function,+,bt_forget_bonded_devices,void,Bt*
Function,+,bt_keys_storage_alloc,BtKeysStorage*,const char*
Function,+,bt_keys_storage_delete,_Bool,BtKeysStorage*
Function,+,bt_keys_storage_free,void,BtKeysStorage*
Function,+,bt_keys_storage_load,_Bool,BtKeysStorage*
Function,+,bt_keys_storage_set_default_path,void,Bt*
Function,+,bt_keys_storage_set_file_path,void,"BtKeysStorage*, const char*"
Function,+,bt_keys_storage_set_ram_params,void,"BtKeysStorage*, uint8_t*, uint16_t"
Function,+,bt_keys_storage_set_storage_path,void,"Bt*, const char*"
Function,+,bt_keys_storage_update,_Bool,"BtKeysStorage*, uint8_t*, uint32_t"
Function,-,bt_open_rpc_connection,void,Bt*
Function,+,bt_profile_restore_default,_Bool,Bt*
Function,+,bt_profile_start,FuriHalBleProfileBase*,"Bt*, const FuriHalBleProfileTemplate*, FuriHalBleProfileParams"
@@ -877,7 +889,7 @@ Function,+,compress_alloc,Compress*,uint16_t
Function,+,compress_decode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*"
Function,+,compress_encode,_Bool,"Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*"
Function,+,compress_free,void,Compress*
Function,+,compress_icon_alloc,CompressIcon*,
Function,+,compress_icon_alloc,CompressIcon*,size_t
Function,+,compress_icon_decode,void,"CompressIcon*, const uint8_t*, uint8_t**"
Function,+,compress_icon_free,void,CompressIcon*
Function,-,copysign,double,"double, double"
@@ -1789,7 +1801,7 @@ Function,+,furi_mutex_free,void,FuriMutex*
Function,+,furi_mutex_get_owner,FuriThreadId,FuriMutex*
Function,+,furi_mutex_release,FuriStatus,FuriMutex*
Function,+,furi_pubsub_alloc,FuriPubSub*,
Function,-,furi_pubsub_free,void,FuriPubSub*
Function,+,furi_pubsub_free,void,FuriPubSub*
Function,+,furi_pubsub_publish,void,"FuriPubSub*, void*"
Function,+,furi_pubsub_subscribe,FuriPubSubSubscription*,"FuriPubSub*, FuriPubSubCallback, void*"
Function,+,furi_pubsub_unsubscribe,void,"FuriPubSub*, FuriPubSubSubscription*"
@@ -2018,8 +2030,10 @@ Function,+,icon_animation_set_update_callback,void,"IconAnimation*, IconAnimatio
Function,+,icon_animation_start,void,IconAnimation*
Function,+,icon_animation_stop,void,IconAnimation*
Function,+,icon_get_data,const uint8_t*,const Icon*
Function,+,icon_get_height,uint8_t,const Icon*
Function,+,icon_get_width,uint8_t,const Icon*
Function,+,icon_get_frame_count,uint32_t,const Icon*
Function,+,icon_get_frame_data,const uint8_t*,"const Icon*, uint32_t"
Function,+,icon_get_height,uint16_t,const Icon*
Function,+,icon_get_width,uint16_t,const Icon*
Function,-,ilogb,int,double
Function,-,ilogbf,int,float
Function,-,ilogbl,int,long double
@@ -2491,6 +2505,8 @@ Function,-,mbedtls_sha256_update,int,"mbedtls_sha256_context*, const unsigned ch
Function,-,mblen,int,"const char*, size_t"
Function,-,mbstowcs,size_t,"wchar_t*, const char*, size_t"
Function,-,mbtowc,int,"wchar_t*, const char*, size_t"
Function,+,md5_calc_file,_Bool,"File*, const char*, unsigned char[16], FS_Error*"
Function,+,md5_string_calc_file,_Bool,"File*, const char*, FuriString*, FS_Error*"
Function,-,memccpy,void*,"void*, const void*, int, size_t"
Function,+,memchr,void*,"const void*, int, size_t"
Function,+,memcmp,int,"const void*, const void*, size_t"
@@ -2966,6 +2982,11 @@ Function,+,protocol_dict_render_brief_data,void,"ProtocolDict*, FuriString*, siz
Function,+,protocol_dict_render_data,void,"ProtocolDict*, FuriString*, size_t"
Function,+,protocol_dict_render_uid,void,"ProtocolDict*, FuriString*, size_t"
Function,+,protocol_dict_set_data,void,"ProtocolDict*, size_t, const uint8_t*, size_t"
Function,+,pulse_glue_alloc,PulseGlue*,
Function,+,pulse_glue_free,void,PulseGlue*
Function,+,pulse_glue_pop,void,"PulseGlue*, uint32_t*, uint32_t*"
Function,+,pulse_glue_push,_Bool,"PulseGlue*, _Bool, uint32_t"
Function,+,pulse_glue_reset,void,PulseGlue*
Function,-,pulse_reader_alloc,PulseReader*,"const GpioPin*, uint32_t"
Function,-,pulse_reader_free,void,PulseReader*
Function,-,pulse_reader_receive,uint32_t,"PulseReader*, int"
@@ -3125,6 +3146,11 @@ Function,+,slix_is_counter_increment_protected,_Bool,const SlixData*
Function,+,slix_is_equal,_Bool,"const SlixData*, const SlixData*"
Function,+,slix_is_privacy_mode,_Bool,const SlixData*
Function,+,slix_load,_Bool,"SlixData*, FlipperFormat*, uint32_t"
Function,+,slix_poller_get_nxp_system_info,SlixError,"SlixPoller*, SlixSystemInfo*"
Function,+,slix_poller_get_random_number,SlixError,"SlixPoller*, SlixRandomNumber*"
Function,+,slix_poller_read_signature,SlixError,"SlixPoller*, SlixSignature*"
Function,+,slix_poller_send_frame,SlixError,"SlixPoller*, const BitBuffer*, BitBuffer*, uint32_t"
Function,+,slix_poller_set_password,SlixError,"SlixPoller*, SlixPasswordType, SlixPassword, SlixRandomNumber"
Function,+,slix_reset,void,SlixData*
Function,+,slix_save,_Bool,"const SlixData*, FlipperFormat*"
Function,+,slix_set_uid,_Bool,"SlixData*, const uint8_t*, size_t"
@@ -3622,6 +3648,12 @@ Function,+,variable_item_set_current_value_text,void,"VariableItem*, const char*
Function,+,variable_item_set_item_label,void,"VariableItem*, const char*"
Function,+,variable_item_set_locked,void,"VariableItem*, _Bool, const char*"
Function,+,variable_item_set_values_count,void,"VariableItem*, uint8_t"
Function,+,varint_int32_length,size_t,int32_t
Function,+,varint_int32_pack,size_t,"int32_t, uint8_t*"
Function,+,varint_int32_unpack,size_t,"int32_t*, const uint8_t*, size_t"
Function,+,varint_uint32_length,size_t,uint32_t
Function,+,varint_uint32_pack,size_t,"uint32_t, uint8_t*"
Function,+,varint_uint32_unpack,size_t,"uint32_t*, const uint8_t*, size_t"
Function,-,vasiprintf,int,"char**, const char*, __gnuc_va_list"
Function,-,vasniprintf,char*,"char*, size_t*, const char*, __gnuc_va_list"
Function,-,vasnprintf,char*,"char*, size_t*, const char*, __gnuc_va_list"
1 entry status name type params
2 Version + 61.2 62.3
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/main/archive/helpers/archive_helpers_ext.h
5 Header + applications/main/subghz/subghz_fap.h
6 Header + applications/services/applications.h
7 Header + applications/services/bt/bt_service/bt.h
8 Header + applications/services/bt/bt_service/bt_keys_storage.h
9 Header + applications/services/bt/bt_settings.h
10 Header + applications/services/cli/cli.h
11 Header + applications/services/cli/cli_vcp.h
174 Header + lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h
175 Header + lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h
176 Header + lib/nfc/protocols/slix/slix.h
177 Header + lib/nfc/protocols/slix/slix_poller.h
178 Header + lib/nfc/protocols/st25tb/st25tb.h
179 Header + lib/nfc/protocols/st25tb/st25tb_poller.h
180 Header + lib/nfc/protocols/st25tb/st25tb_poller_sync.h
241 Header + lib/toolbox/keys_dict.h
242 Header + lib/toolbox/manchester_decoder.h
243 Header + lib/toolbox/manchester_encoder.h
244 Header + lib/toolbox/md5_calc.h
245 Header + lib/toolbox/name_generator.h
246 Header + lib/toolbox/path.h
247 Header + lib/toolbox/pretty_format.h
248 Header + lib/toolbox/protocols/protocol_dict.h
249 Header + lib/toolbox/pulse_protocols/pulse_glue.h
250 Header + lib/toolbox/saved_struct.h
251 Header + lib/toolbox/simple_array.h
252 Header + lib/toolbox/stream/buffered_file_stream.h
255 Header + lib/toolbox/stream/string_stream.h
256 Header + lib/toolbox/tar/tar_archive.h
257 Header + lib/toolbox/value_index.h
258 Header + lib/toolbox/varint.h
259 Header + lib/toolbox/version.h
260 Header + targets/f7/ble_glue/furi_ble/event_dispatcher.h
261 Header + targets/f7/ble_glue/furi_ble/gatt.h
784 Function - bt_close_rpc_connection void Bt*
785 Function + bt_disconnect void Bt*
786 Function + bt_forget_bonded_devices void Bt*
787 Function + bt_keys_storage_alloc BtKeysStorage* const char*
788 Function + bt_keys_storage_delete _Bool BtKeysStorage*
789 Function + bt_keys_storage_free void BtKeysStorage*
790 Function + bt_keys_storage_load _Bool BtKeysStorage*
791 Function + bt_keys_storage_set_default_path void Bt*
792 Function + bt_keys_storage_set_file_path void BtKeysStorage*, const char*
793 Function + bt_keys_storage_set_ram_params void BtKeysStorage*, uint8_t*, uint16_t
794 Function + bt_keys_storage_set_storage_path void Bt*, const char*
795 Function + bt_keys_storage_update _Bool BtKeysStorage*, uint8_t*, uint32_t
796 Function - bt_open_rpc_connection void Bt*
797 Function + bt_profile_restore_default _Bool Bt*
798 Function + bt_profile_start FuriHalBleProfileBase* Bt*, const FuriHalBleProfileTemplate*, FuriHalBleProfileParams
889 Function + compress_decode _Bool Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*
890 Function + compress_encode _Bool Compress*, uint8_t*, size_t, uint8_t*, size_t, size_t*
891 Function + compress_free void Compress*
892 Function + compress_icon_alloc CompressIcon* size_t
893 Function + compress_icon_decode void CompressIcon*, const uint8_t*, uint8_t**
894 Function + compress_icon_free void CompressIcon*
895 Function - copysign double double, double
1801 Function + furi_mutex_get_owner FuriThreadId FuriMutex*
1802 Function + furi_mutex_release FuriStatus FuriMutex*
1803 Function + furi_pubsub_alloc FuriPubSub*
1804 Function - + furi_pubsub_free void FuriPubSub*
1805 Function + furi_pubsub_publish void FuriPubSub*, void*
1806 Function + furi_pubsub_subscribe FuriPubSubSubscription* FuriPubSub*, FuriPubSubCallback, void*
1807 Function + furi_pubsub_unsubscribe void FuriPubSub*, FuriPubSubSubscription*
2030 Function + icon_animation_start void IconAnimation*
2031 Function + icon_animation_stop void IconAnimation*
2032 Function + icon_get_data const uint8_t* const Icon*
2033 Function + icon_get_height icon_get_frame_count uint8_t uint32_t const Icon*
2034 Function + icon_get_width icon_get_frame_data uint8_t const uint8_t* const Icon* const Icon*, uint32_t
2035 Function + icon_get_height uint16_t const Icon*
2036 Function + icon_get_width uint16_t const Icon*
2037 Function - ilogb int double
2038 Function - ilogbf int float
2039 Function - ilogbl int long double
2505 Function - mblen int const char*, size_t
2506 Function - mbstowcs size_t wchar_t*, const char*, size_t
2507 Function - mbtowc int wchar_t*, const char*, size_t
2508 Function + md5_calc_file _Bool File*, const char*, unsigned char[16], FS_Error*
2509 Function + md5_string_calc_file _Bool File*, const char*, FuriString*, FS_Error*
2510 Function - memccpy void* void*, const void*, int, size_t
2511 Function + memchr void* const void*, int, size_t
2512 Function + memcmp int const void*, const void*, size_t
2982 Function + protocol_dict_render_data void ProtocolDict*, FuriString*, size_t
2983 Function + protocol_dict_render_uid void ProtocolDict*, FuriString*, size_t
2984 Function + protocol_dict_set_data void ProtocolDict*, size_t, const uint8_t*, size_t
2985 Function + pulse_glue_alloc PulseGlue*
2986 Function + pulse_glue_free void PulseGlue*
2987 Function + pulse_glue_pop void PulseGlue*, uint32_t*, uint32_t*
2988 Function + pulse_glue_push _Bool PulseGlue*, _Bool, uint32_t
2989 Function + pulse_glue_reset void PulseGlue*
2990 Function - pulse_reader_alloc PulseReader* const GpioPin*, uint32_t
2991 Function - pulse_reader_free void PulseReader*
2992 Function - pulse_reader_receive uint32_t PulseReader*, int
3146 Function + slix_is_equal _Bool const SlixData*, const SlixData*
3147 Function + slix_is_privacy_mode _Bool const SlixData*
3148 Function + slix_load _Bool SlixData*, FlipperFormat*, uint32_t
3149 Function + slix_poller_get_nxp_system_info SlixError SlixPoller*, SlixSystemInfo*
3150 Function + slix_poller_get_random_number SlixError SlixPoller*, SlixRandomNumber*
3151 Function + slix_poller_read_signature SlixError SlixPoller*, SlixSignature*
3152 Function + slix_poller_send_frame SlixError SlixPoller*, const BitBuffer*, BitBuffer*, uint32_t
3153 Function + slix_poller_set_password SlixError SlixPoller*, SlixPasswordType, SlixPassword, SlixRandomNumber
3154 Function + slix_reset void SlixData*
3155 Function + slix_save _Bool const SlixData*, FlipperFormat*
3156 Function + slix_set_uid _Bool SlixData*, const uint8_t*, size_t
3648 Function + variable_item_set_item_label void VariableItem*, const char*
3649 Function + variable_item_set_locked void VariableItem*, _Bool, const char*
3650 Function + variable_item_set_values_count void VariableItem*, uint8_t
3651 Function + varint_int32_length size_t int32_t
3652 Function + varint_int32_pack size_t int32_t, uint8_t*
3653 Function + varint_int32_unpack size_t int32_t*, const uint8_t*, size_t
3654 Function + varint_uint32_length size_t uint32_t
3655 Function + varint_uint32_pack size_t uint32_t, uint8_t*
3656 Function + varint_uint32_unpack size_t uint32_t*, const uint8_t*, size_t
3657 Function - vasiprintf int char**, const char*, __gnuc_va_list
3658 Function - vasniprintf char* char*, size_t*, const char*, __gnuc_va_list
3659 Function - vasnprintf char* char*, size_t*, const char*, __gnuc_va_list

View File

@@ -133,7 +133,7 @@ void furi_hal_clock_switch_hse2hsi(void) {
;
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
furi_assert(LL_RCC_GetSMPSClockSelection() == LL_RCC_SMPS_CLKSOURCE_HSI);
furi_check(LL_RCC_GetSMPSClockSelection() == LL_RCC_SMPS_CLKSOURCE_HSI);
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
;
@@ -170,7 +170,7 @@ void furi_hal_clock_switch_hsi2hse(void) {
}
bool furi_hal_clock_switch_hse2pll(void) {
furi_assert(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
furi_check(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
LL_RCC_PLL_Enable();
LL_RCC_PLLSAI1_Enable();
@@ -180,12 +180,13 @@ bool furi_hal_clock_switch_hse2pll(void) {
while(!LL_RCC_PLLSAI1_IsReady())
;
if(SHCI_C2_SetSystemClock(SET_SYSTEM_CLOCK_HSE_TO_PLL) != SHCI_Success) {
// This API returns garbage if stack version < 1.20.0
SHCI_C2_SetSystemClock(SET_SYSTEM_CLOCK_HSE_TO_PLL);
// So we'll check results by asking hardware directly
if(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
return false;
}
furi_check(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL);
LL_SetSystemCoreClock(CPU_CLOCK_PLL_HZ);
SysTick->LOAD = (uint32_t)((SystemCoreClock / 1000) - 1UL);
@@ -193,18 +194,19 @@ bool furi_hal_clock_switch_hse2pll(void) {
}
bool furi_hal_clock_switch_pll2hse(void) {
furi_assert(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL);
furi_check(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL);
LL_RCC_HSE_Enable();
while(!LL_RCC_HSE_IsReady())
;
if(SHCI_C2_SetSystemClock(SET_SYSTEM_CLOCK_PLL_ON_TO_HSE) != SHCI_Success) {
// This API returns garbage if stack version < 1.20.0
SHCI_C2_SetSystemClock(SET_SYSTEM_CLOCK_PLL_ON_TO_HSE);
// So we'll check results by asking hardware directly
if(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE) {
return false;
}
furi_check(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
LL_SetSystemCoreClock(CPU_CLOCK_HSE_HZ);
SysTick->LOAD = (uint32_t)((SystemCoreClock / 1000) - 1UL);

View File

@@ -16,6 +16,12 @@
#define TAG "FuriHalFlash"
#ifdef FLASH_OP_DEBUG
#undef FURI_LOG_T
#define FURI_LOG_T(...)
#else
#endif
#define FURI_HAL_CRITICAL_MSG "Critical flash operation fail"
#define FURI_HAL_FLASH_READ_BLOCK (8U)
#define FURI_HAL_FLASH_WRITE_BLOCK (8U)
@@ -295,6 +301,7 @@ bool furi_hal_flash_wait_last_operation(uint32_t timeout) {
}
void furi_hal_flash_erase(uint8_t page) {
uint32_t op_stat = DWT->CYCCNT;
furi_hal_flash_begin(true);
/* Ensure that controller state is valid */
@@ -317,6 +324,12 @@ void furi_hal_flash_erase(uint8_t page) {
furi_hal_flush_cache();
furi_hal_flash_end(true);
op_stat = DWT->CYCCNT - op_stat;
FURI_LOG_T(
TAG,
"erase took %lu clocks or %fus",
op_stat,
(double)((float)op_stat / (float)furi_hal_cortex_instructions_per_microsecond()));
}
static inline void furi_hal_flash_write_dword_internal_nowait(size_t address, uint64_t* data) {
@@ -339,6 +352,7 @@ static inline void furi_hal_flash_write_dword_internal(size_t address, uint64_t*
}
void furi_hal_flash_write_dword(size_t address, uint64_t data) {
uint32_t op_stat = DWT->CYCCNT;
furi_hal_flash_begin(false);
/* Ensure that controller state is valid */
@@ -361,6 +375,12 @@ void furi_hal_flash_write_dword(size_t address, uint64_t data) {
/* Wait for last operation to be completed */
furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
op_stat = DWT->CYCCNT - op_stat;
FURI_LOG_T(
TAG,
"write_dword took %lu clocks or %fus",
op_stat,
(double)((float)op_stat / (float)furi_hal_cortex_instructions_per_microsecond()));
}
static size_t furi_hal_flash_get_page_address(uint8_t page) {
@@ -373,6 +393,7 @@ void furi_hal_flash_program_page(const uint8_t page, const uint8_t* data, uint16
furi_hal_flash_erase(page);
uint32_t op_stat = DWT->CYCCNT;
furi_hal_flash_begin(false);
furi_check(furi_hal_flash_wait_last_operation(FURI_HAL_FLASH_TIMEOUT));
@@ -432,6 +453,12 @@ void furi_hal_flash_program_page(const uint8_t page, const uint8_t* data, uint16
CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
furi_hal_flash_end(false);
op_stat = DWT->CYCCNT - op_stat;
FURI_LOG_T(
TAG,
"program_page took %lu clocks or %fus",
op_stat,
(double)((float)op_stat / (float)furi_hal_cortex_instructions_per_microsecond()));
}
int16_t furi_hal_flash_get_page_number(size_t address) {

View File

@@ -47,7 +47,6 @@
"mbedtls",
"lfrfid",
"flipper_application",
"toolbox",
"u8g2",
"nanopb",
"update_util",
@@ -56,6 +55,7 @@
"flipperformat",
"flipper7",
"bit_lib",
"toolbox",
"datetime"
]
}