mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-10 06:54:19 +00:00
Merge branch 'dev' into astra/3746-mfp-detect
This commit is contained in:
commit
8cdb8aafac
83 changed files with 1232 additions and 393 deletions
2
.vscode/example/tasks.json
vendored
2
.vscode/example/tasks.json
vendored
|
@ -79,7 +79,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)",
|
||||
|
|
|
@ -18,6 +18,33 @@ static const TextBoxViewTestContent text_box_view_test_content_arr[] = {
|
|||
.focus = TextBoxFocusStart,
|
||||
.text = "Hello, let's test text box. Press Right and Left to switch content",
|
||||
},
|
||||
{
|
||||
.font = TextBoxFontText,
|
||||
.focus = TextBoxFocusEnd,
|
||||
.text = "First test to add dynamically lines with EndFocus set\nLine 0",
|
||||
},
|
||||
{
|
||||
.font = TextBoxFontText,
|
||||
.focus = TextBoxFocusEnd,
|
||||
.text = "First test to add dynamically lines with EndFocus set\nLine 0\nLine 1",
|
||||
},
|
||||
{
|
||||
.font = TextBoxFontText,
|
||||
.focus = TextBoxFocusEnd,
|
||||
.text = "First test to add dynamically lines with EndFocus set\nLine 0\nLine 1\nLine 2",
|
||||
},
|
||||
{
|
||||
.font = TextBoxFontText,
|
||||
.focus = TextBoxFocusEnd,
|
||||
.text =
|
||||
"First test to add dynamically lines with EndFocus set\nLine 0\nLine 1\nLine 2\nLine 3",
|
||||
},
|
||||
{
|
||||
.font = TextBoxFontText,
|
||||
.focus = TextBoxFocusEnd,
|
||||
.text =
|
||||
"First test to add dynamically lines with EndFocus set\nLine 0\nLine 1\nLine 2\nLine 3\nLine 4",
|
||||
},
|
||||
{
|
||||
.font = TextBoxFontText,
|
||||
.focus = TextBoxFocusStart,
|
||||
|
@ -57,7 +84,8 @@ typedef struct {
|
|||
} TextBoxViewTest;
|
||||
|
||||
static void text_box_update_view(TextBoxViewTest* instance) {
|
||||
text_box_reset(instance->text_box);
|
||||
// Intentional incorrect way to reset text box to verify that state resets if text changes
|
||||
text_box_set_text(instance->text_box, "");
|
||||
|
||||
const TextBoxViewTestContent* content =
|
||||
&text_box_view_test_content_arr[instance->current_content_i];
|
||||
|
|
|
@ -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"],
|
||||
)
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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
|
||||
}
|
216
applications/debug/unit_tests/test_runner.c
Normal file
216
applications/debug/unit_tests/test_runner.c
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
applications/debug/unit_tests/test_runner.h
Normal file
12
applications/debug/unit_tests/test_runner.h
Normal 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);
|
|
@ -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) {
|
||||
|
@ -737,4 +737,6 @@ MU_TEST_SUITE(test_bit_lib) {
|
|||
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)
|
|
@ -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)
|
42
applications/debug/unit_tests/tests/common/common.c
Normal file
42
applications/debug/unit_tests/tests/common/common.c
Normal 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;
|
||||
}
|
159
applications/debug/unit_tests/tests/compress/compress_test.c
Normal file
159
applications/debug/unit_tests/tests/compress/compress_test.c
Normal 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)
|
|
@ -1,5 +1,5 @@
|
|||
#include <furi.h>
|
||||
#include "../minunit.h"
|
||||
#include "../test.h"
|
||||
|
||||
#include <datetime/datetime.h>
|
||||
|
||||
|
@ -188,4 +188,6 @@ int run_minunit_test_datetime(void) {
|
|||
MU_RUN_SUITE(test_datetime_validate_datetime);
|
||||
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_datetime)
|
|
@ -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)
|
|
@ -1,4 +1,4 @@
|
|||
#include "../minunit.h"
|
||||
#include "../test.h"
|
||||
#include <furi.h>
|
||||
#include <m-dict.h>
|
||||
#include <toolbox/dir_walk.h>
|
||||
|
@ -269,4 +269,6 @@ MU_TEST_SUITE(test_dirwalk_suite) {
|
|||
int run_minunit_test_dirwalk(void) {
|
||||
MU_RUN_SUITE(test_dirwalk_suite);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_dirwalk)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -1,4 +1,4 @@
|
|||
#include "../minunit.h"
|
||||
#include "../test.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
|
@ -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;
|
|
@ -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"
|
||||
|
|
@ -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);
|
||||
|
@ -55,3 +55,5 @@ int run_minunit_test_furi(void) {
|
|||
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_furi)
|
|
@ -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)
|
|
@ -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)
|
|
@ -1,5 +1,5 @@
|
|||
#include <furi.h>
|
||||
#include "../minunit.h"
|
||||
#include "../test.h"
|
||||
|
||||
static void test_setup(void) {
|
||||
}
|
||||
|
@ -466,4 +466,6 @@ int run_minunit_test_furi_string(void) {
|
|||
MU_RUN_SUITE(test_suite);
|
||||
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_furi_string)
|
|
@ -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)
|
|
@ -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>
|
||||
|
@ -550,4 +550,6 @@ MU_TEST_SUITE(test_lfrfid_protocols_suite) {
|
|||
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)
|
|
@ -1,5 +1,5 @@
|
|||
#include <furi.c>
|
||||
#include "../minunit.h"
|
||||
#include "../test.h"
|
||||
#include <update_util/resources/manifest.h>
|
||||
|
||||
#define TAG "Manifest"
|
||||
|
@ -72,4 +72,6 @@ MU_TEST_SUITE(manifest_suite) {
|
|||
int run_minunit_test_manifest(void) {
|
||||
MU_RUN_SUITE(manifest_suite);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_manifest)
|
|
@ -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)
|
|
@ -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)
|
|
@ -1,5 +1,5 @@
|
|||
#include <furi.h>
|
||||
#include "../minunit.h"
|
||||
#include "../test.h"
|
||||
#include <toolbox/protocols/protocol_dict.h>
|
||||
|
||||
typedef enum {
|
||||
|
@ -219,4 +219,6 @@ MU_TEST_SUITE(test_protocol_dict_suite) {
|
|||
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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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>
|
||||
|
@ -908,3 +908,5 @@ int run_minunit_test_subghz(void) {
|
|||
MU_RUN_SUITE(subghz);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_subghz)
|
12
applications/debug/unit_tests/tests/test.h
Normal file
12
applications/debug/unit_tests/tests/test.h
Normal 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);
|
29
applications/debug/unit_tests/tests/test_api.h
Normal file
29
applications/debug/unit_tests/tests/test_api.h
Normal 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; \
|
||||
}
|
|
@ -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>
|
||||
|
||||
|
@ -85,4 +87,6 @@ MU_TEST_SUITE(test_varint_suite) {
|
|||
int run_minunit_test_varint(void) {
|
||||
MU_RUN_SUITE(test_varint_suite);
|
||||
return MU_EXIT_CODE;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_API_DEFINE(run_minunit_test_varint)
|
19
applications/debug/unit_tests/unit_test_api_table.cpp
Normal file
19
applications/debug/unit_tests/unit_test_api_table.cpp
Normal 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;
|
29
applications/debug/unit_tests/unit_test_api_table_i.h
Normal file
29
applications/debug/unit_tests/unit_test_api_table_i.h
Normal 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)));
|
21
applications/debug/unit_tests/unit_tests.c
Normal file
21
applications/debug/unit_tests/unit_tests.c
Normal 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
|
||||
}
|
|
@ -16,6 +16,7 @@ ArchiveApp* archive_alloc(void) {
|
|||
ArchiveApp* archive = malloc(sizeof(ArchiveApp));
|
||||
|
||||
archive->gui = furi_record_open(RECORD_GUI);
|
||||
archive->loader = furi_record_open(RECORD_LOADER);
|
||||
archive->text_input = text_input_alloc();
|
||||
archive->fav_move_str = furi_string_alloc();
|
||||
|
||||
|
@ -61,6 +62,8 @@ void archive_free(ArchiveApp* archive) {
|
|||
|
||||
text_input_free(archive->text_input);
|
||||
|
||||
furi_record_close(RECORD_LOADER);
|
||||
archive->loader = NULL;
|
||||
furi_record_close(RECORD_GUI);
|
||||
archive->gui = NULL;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ typedef enum {
|
|||
|
||||
struct ArchiveApp {
|
||||
Gui* gui;
|
||||
Loader* loader;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
ArchiveBrowserView* browser;
|
||||
|
|
|
@ -86,10 +86,8 @@ void archive_scene_browser_on_enter(void* context) {
|
|||
archive_update_focus(browser, archive->text_store);
|
||||
view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewBrowser);
|
||||
|
||||
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||
archive->loader_stop_subscription =
|
||||
furi_pubsub_subscribe(loader_get_pubsub(loader), archive_loader_callback, archive);
|
||||
furi_record_close(RECORD_LOADER);
|
||||
archive->loader_stop_subscription = furi_pubsub_subscribe(
|
||||
loader_get_pubsub(archive->loader), archive_loader_callback, archive);
|
||||
|
||||
uint32_t state = scene_manager_get_scene_state(archive->scene_manager, ArchiveAppSceneBrowser);
|
||||
|
||||
|
@ -213,10 +211,11 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
|||
if(!archive_is_home(browser)) {
|
||||
archive_leave_dir(browser);
|
||||
} else {
|
||||
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||
furi_pubsub_unsubscribe(
|
||||
loader_get_pubsub(loader), archive->loader_stop_subscription);
|
||||
furi_record_close(RECORD_LOADER);
|
||||
if(archive->loader_stop_subscription) {
|
||||
furi_pubsub_unsubscribe(
|
||||
loader_get_pubsub(archive->loader), archive->loader_stop_subscription);
|
||||
archive->loader_stop_subscription = NULL;
|
||||
}
|
||||
|
||||
view_dispatcher_stop(archive->view_dispatcher);
|
||||
}
|
||||
|
@ -232,8 +231,9 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
|||
|
||||
void archive_scene_browser_on_exit(void* context) {
|
||||
ArchiveApp* archive = (ArchiveApp*)context;
|
||||
|
||||
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||
furi_pubsub_unsubscribe(loader_get_pubsub(loader), archive->loader_stop_subscription);
|
||||
furi_record_close(RECORD_LOADER);
|
||||
if(archive->loader_stop_subscription) {
|
||||
furi_pubsub_unsubscribe(
|
||||
loader_get_pubsub(archive->loader), archive->loader_stop_subscription);
|
||||
archive->loader_stop_subscription = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,22 +2,12 @@
|
|||
|
||||
#include "../helpers/protocol_support/nfc_protocol_support_gui_common.h"
|
||||
|
||||
static void nfc_scene_set_uid_byte_input_changed_callback(void* context) {
|
||||
NfcApp* instance = context;
|
||||
// Retrieve previously saved UID length
|
||||
const size_t uid_len = scene_manager_get_scene_state(instance->scene_manager, NfcSceneSetUid);
|
||||
nfc_device_set_uid(instance->nfc_device, instance->byte_input_store, uid_len);
|
||||
}
|
||||
|
||||
void nfc_scene_set_uid_on_enter(void* context) {
|
||||
NfcApp* instance = context;
|
||||
|
||||
size_t uid_len;
|
||||
const uint8_t* uid = nfc_device_get_uid(instance->nfc_device, &uid_len);
|
||||
|
||||
memcpy(instance->byte_input_store, uid, uid_len);
|
||||
// Save UID length for use in callback
|
||||
scene_manager_set_scene_state(instance->scene_manager, NfcSceneSetUid, uid_len);
|
||||
|
||||
// Setup view
|
||||
ByteInput* byte_input = instance->byte_input;
|
||||
|
@ -25,7 +15,7 @@ void nfc_scene_set_uid_on_enter(void* context) {
|
|||
byte_input_set_result_callback(
|
||||
byte_input,
|
||||
nfc_protocol_support_common_byte_input_done_callback,
|
||||
nfc_scene_set_uid_byte_input_changed_callback,
|
||||
NULL,
|
||||
instance,
|
||||
instance->byte_input_store,
|
||||
uid_len);
|
||||
|
@ -39,6 +29,9 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
|
|||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == NfcCustomEventByteInputDone) {
|
||||
size_t uid_len = 0;
|
||||
nfc_device_get_uid(instance->nfc_device, &uid_len);
|
||||
nfc_device_set_uid(instance->nfc_device, instance->byte_input_store, uid_len);
|
||||
if(scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSavedMenu)) {
|
||||
if(nfc_save(instance)) {
|
||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess);
|
||||
|
|
|
@ -14,7 +14,7 @@ App(
|
|||
],
|
||||
stack_size=1 * 1024,
|
||||
order=20,
|
||||
sdk_headers=["bt_service/bt.h"],
|
||||
sdk_headers=["bt_service/bt.h", "bt_service/bt_keys_storage.h"],
|
||||
)
|
||||
|
||||
App(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "slideshow.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <storage/storage.h>
|
||||
#include <gui/icon.h>
|
||||
#include <gui/icon_i.h>
|
||||
|
|
|
@ -15,7 +15,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);
|
||||
|
@ -390,7 +390,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);
|
||||
}
|
||||
|
@ -402,7 +402,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);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <m-algo.h>
|
||||
#include <furi.h>
|
||||
|
||||
#define ICON_DECOMPRESSOR_BUFFER_SIZE (128u * 64 / 8)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -227,14 +227,13 @@ static void text_box_prepare_model(Canvas* canvas, TextBoxModel* model) {
|
|||
text_box_seek_next_line(canvas, model);
|
||||
lines_num++;
|
||||
} while(!text_box_end_of_text_reached(model));
|
||||
model->text_offset = 0;
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -353,6 +353,12 @@ static LoaderStatus loader_start_external_app(
|
|||
|
||||
FURI_LOG_I(TAG, "Loaded in %zums", (size_t)(furi_get_tick() - start));
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -80,6 +80,7 @@ void desktop_settings_scene_favorite_on_enter(void* context) {
|
|||
furi_assert(favorite_id < DummyAppNumber);
|
||||
curr_favorite_app = &app->settings.dummy_apps[favorite_id];
|
||||
default_passport = true;
|
||||
favorite_id |= SCENE_STATE_SET_DUMMY_APP;
|
||||
}
|
||||
|
||||
// Special case: Application browser
|
||||
|
@ -141,28 +142,24 @@ void desktop_settings_scene_favorite_on_enter(void* context) {
|
|||
|
||||
switch(favorite_id) {
|
||||
case SCENE_STATE_SET_FAVORITE_APP | FavoriteAppLeftShort:
|
||||
submenu_set_header(submenu, "Left - Short");
|
||||
case SCENE_STATE_SET_DUMMY_APP | DummyAppLeft:
|
||||
submenu_set_header(submenu, "Left - Press");
|
||||
break;
|
||||
case SCENE_STATE_SET_FAVORITE_APP | FavoriteAppLeftLong:
|
||||
submenu_set_header(submenu, "Left - Long");
|
||||
submenu_set_header(submenu, "Left - Hold");
|
||||
break;
|
||||
case SCENE_STATE_SET_FAVORITE_APP | FavoriteAppRightShort:
|
||||
submenu_set_header(submenu, "Right - Short");
|
||||
case SCENE_STATE_SET_DUMMY_APP | DummyAppRight:
|
||||
submenu_set_header(submenu, "Right - Press");
|
||||
break;
|
||||
case SCENE_STATE_SET_FAVORITE_APP | FavoriteAppRightLong:
|
||||
submenu_set_header(submenu, "Right - Long");
|
||||
break;
|
||||
case SCENE_STATE_SET_DUMMY_APP | DummyAppLeft:
|
||||
submenu_set_header(submenu, "Left");
|
||||
break;
|
||||
case SCENE_STATE_SET_DUMMY_APP | DummyAppRight:
|
||||
submenu_set_header(submenu, "Right");
|
||||
submenu_set_header(submenu, "Right - Hold");
|
||||
break;
|
||||
case SCENE_STATE_SET_DUMMY_APP | DummyAppDown:
|
||||
submenu_set_header(submenu, "Down");
|
||||
submenu_set_header(submenu, "Down - Press");
|
||||
break;
|
||||
case SCENE_STATE_SET_DUMMY_APP | DummyAppOk:
|
||||
submenu_set_header(submenu, "Middle");
|
||||
submenu_set_header(submenu, "Middle - Press");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -34,14 +34,14 @@ void desktop_settings_scene_quick_apps_direction_menu_on_enter(void* context) {
|
|||
if(favorite_id == SCENE_STATE_SET_FAVORITE_APP) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Left - Click",
|
||||
"Left - Press",
|
||||
QuickAppsSubmenuIndexFavoriteLeftClick,
|
||||
desktop_settings_scene_quick_apps_direction_menu_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Right - Click",
|
||||
"Right - Press",
|
||||
QuickAppsSubmenuIndexFavoriteRightClick,
|
||||
desktop_settings_scene_quick_apps_direction_menu_submenu_callback,
|
||||
app);
|
||||
|
@ -64,28 +64,28 @@ void desktop_settings_scene_quick_apps_direction_menu_on_enter(void* context) {
|
|||
} else {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Left - Click",
|
||||
"Left - Press",
|
||||
QuickAppsSubmenuIndexDummyLeftClick,
|
||||
desktop_settings_scene_quick_apps_direction_menu_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Right - Click",
|
||||
"Right - Press",
|
||||
QuickAppsSubmenuIndexDummyRightClick,
|
||||
desktop_settings_scene_quick_apps_direction_menu_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Down - Click",
|
||||
"Down - Press",
|
||||
QuickAppsSubmenuIndexDummyDownClick,
|
||||
desktop_settings_scene_quick_apps_direction_menu_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Middle - Click",
|
||||
"Middle - Press",
|
||||
QuickAppsSubmenuIndexDummyMiddleClick,
|
||||
desktop_settings_scene_quick_apps_direction_menu_submenu_callback,
|
||||
app);
|
||||
|
|
|
@ -411,6 +411,7 @@ bool protocol_electra_write_data(ProtocolElectra* protocol, void* data) {
|
|||
};
|
||||
|
||||
void protocol_electra_render_data(ProtocolElectra* protocol, FuriString* result) {
|
||||
protocol_electra_encoder_start(protocol);
|
||||
furi_string_printf(result, "Epilogue: %016llX", protocol->encoded_epilogue);
|
||||
};
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ env.Append(
|
|||
File("protocols/mf_classic/mf_classic_poller.h"),
|
||||
File("protocols/mf_plus/mf_plus_poller.h"),
|
||||
File("protocols/mf_desfire/mf_desfire_poller.h"),
|
||||
File("protocols/slix/slix_poller.h"),
|
||||
File("protocols/st25tb/st25tb_poller.h"),
|
||||
File("protocols/felica/felica_poller.h"),
|
||||
# Listeners
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -25,6 +25,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"),
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
#include <furi_hal.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*SubGhzFileEncoderWorkerCallbackEnd)(void* context);
|
||||
|
||||
typedef struct SubGhzFileEncoderWorker SubGhzFileEncoderWorker;
|
||||
|
@ -59,3 +63,7 @@ void subghz_file_encoder_worker_stop(SubGhzFileEncoderWorker* instance);
|
|||
* @return bool - true if running
|
||||
*/
|
||||
bool subghz_file_encoder_worker_is_running(SubGhzFileEncoderWorker* instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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"),
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 instance The Compress Icon instance
|
||||
* @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;
|
||||
|
|
|
@ -24,8 +24,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 = "const 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):
|
||||
|
|
|
@ -351,10 +351,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 = []
|
||||
|
@ -399,14 +399,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()
|
||||
|
@ -432,9 +448,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),
|
||||
(
|
||||
self.appmgr.known_apps.values()
|
||||
if all_known
|
||||
else map(self.appmgr.get, self.appnames)
|
||||
),
|
||||
),
|
||||
key=lambda app: app.order,
|
||||
)
|
||||
|
|
|
@ -461,7 +461,8 @@ def _gather_app_components(env, appname) -> AppDeploymentComponents:
|
|||
else:
|
||||
# host app is a built-in app
|
||||
components.add_app(artifacts_app_to_run)
|
||||
components.extra_launch_args = f"-a {host_app.name}"
|
||||
if host_app.name:
|
||||
components.extra_launch_args = f"-a {host_app.name}"
|
||||
else:
|
||||
raise UserError("Host app is unknown")
|
||||
else:
|
||||
|
|
|
@ -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()};")
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
entry,status,name,type,params
|
||||
Version,+,61.4,,
|
||||
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,,
|
||||
|
@ -680,8 +684,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*"
|
||||
|
@ -773,7 +784,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"
|
||||
|
@ -1490,7 +1501,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*"
|
||||
|
@ -1675,8 +1686,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
|
||||
|
@ -1980,6 +1993,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"
|
||||
|
@ -2254,6 +2269,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"
|
||||
|
@ -2642,6 +2662,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"
|
||||
|
|
|
|
@ -30,7 +30,6 @@
|
|||
"mjs",
|
||||
"mbedtls",
|
||||
"flipper_application",
|
||||
"toolbox",
|
||||
"u8g2",
|
||||
"nanopb",
|
||||
"update_util",
|
||||
|
@ -38,6 +37,7 @@
|
|||
"flipperformat",
|
||||
"flipper18",
|
||||
"bit_lib",
|
||||
"toolbox",
|
||||
"datetime"
|
||||
],
|
||||
"excluded_sources": [
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
entry,status,name,type,params
|
||||
Version,+,61.4,,
|
||||
Version,+,62.3,,
|
||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
Header,+,applications/services/dialogs/dialogs.h,,
|
||||
|
@ -160,6 +161,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,,
|
||||
|
@ -208,6 +210,7 @@ Header,+,lib/subghz/protocols/public_api.h,,
|
|||
Header,+,lib/subghz/protocols/raw.h,,
|
||||
Header,+,lib/subghz/receiver.h,,
|
||||
Header,+,lib/subghz/registry.h,,
|
||||
Header,+,lib/subghz/subghz_file_encoder_worker.h,,
|
||||
Header,+,lib/subghz/subghz_protocol_registry.h,,
|
||||
Header,+,lib/subghz/subghz_setting.h,,
|
||||
Header,+,lib/subghz/subghz_tx_rx_worker.h,,
|
||||
|
@ -224,10 +227,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,,
|
||||
|
@ -236,6 +241,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,,
|
||||
|
@ -753,8 +759,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*"
|
||||
|
@ -846,7 +859,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"
|
||||
|
@ -1698,7 +1711,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*"
|
||||
|
@ -1922,8 +1935,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
|
||||
|
@ -2392,6 +2407,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"
|
||||
|
@ -2867,6 +2884,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"
|
||||
|
@ -3007,6 +3029,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"
|
||||
|
@ -3259,6 +3286,13 @@ Function,+,subghz_environment_set_alutech_at_4n_rainbow_table_file_name,void,"Su
|
|||
Function,+,subghz_environment_set_came_atomo_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*"
|
||||
Function,+,subghz_environment_set_nice_flor_s_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*"
|
||||
Function,+,subghz_environment_set_protocol_registry,void,"SubGhzEnvironment*, const SubGhzProtocolRegistry*"
|
||||
Function,+,subghz_file_encoder_worker_alloc,SubGhzFileEncoderWorker*,
|
||||
Function,+,subghz_file_encoder_worker_callback_end,void,"SubGhzFileEncoderWorker*, SubGhzFileEncoderWorkerCallbackEnd, void*"
|
||||
Function,+,subghz_file_encoder_worker_free,void,SubGhzFileEncoderWorker*
|
||||
Function,+,subghz_file_encoder_worker_get_level_duration,LevelDuration,void*
|
||||
Function,+,subghz_file_encoder_worker_is_running,_Bool,SubGhzFileEncoderWorker*
|
||||
Function,+,subghz_file_encoder_worker_start,_Bool,"SubGhzFileEncoderWorker*, const char*, const char*"
|
||||
Function,+,subghz_file_encoder_worker_stop,void,SubGhzFileEncoderWorker*
|
||||
Function,-,subghz_keystore_alloc,SubGhzKeystore*,
|
||||
Function,-,subghz_keystore_free,void,SubGhzKeystore*
|
||||
Function,-,subghz_keystore_get_data,SubGhzKeyArray_t*,SubGhzKeystore*
|
||||
|
@ -3457,6 +3491,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"
|
||||
|
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
|
||||
#define TAG "FuriHalFlash"
|
||||
|
||||
#ifdef FLASH_OP_DEBUG
|
||||
#undef FURI_LOG_T
|
||||
#define FURI_LOG_T(...)
|
||||
#endif
|
||||
|
||||
#define FURI_HAL_CRITICAL_MSG "Critical flash operation fail"
|
||||
#define FURI_HAL_FLASH_READ_BLOCK (8U)
|
||||
#define FURI_HAL_FLASH_WRITE_BLOCK (8U)
|
||||
|
@ -144,9 +149,8 @@ static void furi_hal_flash_begin_with_core2(bool erase_flag) {
|
|||
/* Erase activity notification */
|
||||
if(erase_flag) SHCI_C2_FLASH_EraseActivity(ERASE_ACTIVITY_ON);
|
||||
|
||||
/* 64mHz 5us core2 flag protection */
|
||||
for(volatile uint32_t i = 0; i < 35; i++)
|
||||
;
|
||||
/* 5us core2 flag protection */
|
||||
furi_delay_us(5);
|
||||
|
||||
FuriHalCortexTimer timer = furi_hal_cortex_timer_get(FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS * 1000);
|
||||
while(true) {
|
||||
|
@ -291,6 +295,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 */
|
||||
|
@ -313,6 +318,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) {
|
||||
|
@ -335,6 +346,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 */
|
||||
|
@ -357,6 +369,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) {
|
||||
|
@ -369,6 +387,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));
|
||||
|
@ -428,6 +447,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) {
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
"mbedtls",
|
||||
"lfrfid",
|
||||
"flipper_application",
|
||||
"toolbox",
|
||||
"u8g2",
|
||||
"nanopb",
|
||||
"update_util",
|
||||
|
@ -53,6 +52,7 @@
|
|||
"flipperformat",
|
||||
"flipper7",
|
||||
"bit_lib",
|
||||
"toolbox",
|
||||
"datetime"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue