From 844e0f10e59ef53a6be2b71106b9d143fafeab01 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Sat, 28 Oct 2023 16:56:49 +0300 Subject: [PATCH 01/40] [FL-3639] Fix MF DESFire record file handling (#3167) --- .../nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c | 1 + lib/nfc/protocols/mf_desfire/mf_desfire.h | 1 + lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c index 883ea720b0..b5ca0d1383 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c @@ -197,6 +197,7 @@ void nfc_render_mf_desfire_file_settings_data( furi_string_cat_printf(str, "size %lu\n", record_size); break; case MfDesfireFileTypeValue: + record_size = MF_DESFIRE_VALUE_SIZE; furi_string_cat_printf( str, "lo %lu hi %lu\n", settings->value.lo_limit, settings->value.hi_limit); furi_string_cat_printf( diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire.h b/lib/nfc/protocols/mf_desfire/mf_desfire.h index 4d09dc8510..8505b792aa 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire.h @@ -29,6 +29,7 @@ extern "C" { #define MF_DESFIRE_UID_SIZE (7) #define MF_DESFIRE_BATCH_SIZE (5) #define MF_DESFIRE_APP_ID_SIZE (3) +#define MF_DESFIRE_VALUE_SIZE (4) typedef struct { uint8_t hw_vendor; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index e86cb4c68c..17377d66e3 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -353,7 +353,7 @@ MfDesfireError mf_desfire_poller_async_read_file_records( furi_assert(instance); bit_buffer_reset(instance->input_buffer); - bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_READ_DATA); + bit_buffer_append_byte(instance->input_buffer, MF_DESFIRE_CMD_READ_RECORDS); bit_buffer_append_byte(instance->input_buffer, id); bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&offset, 3); bit_buffer_append_bytes(instance->input_buffer, (const uint8_t*)&size, 3); From 3d872cf37a2c4ec616021e1a6da4115610a6637a Mon Sep 17 00:00:00 2001 From: gornekich Date: Sat, 28 Oct 2023 18:22:07 +0400 Subject: [PATCH 02/40] [FL-3637] NFC RC fixes (#3165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * firmware: remove nfc lib build settings section * furi hal nfc: fix nfc irq gpio deinit * lib nfc: remove deprecated exception from sources * nfc: use ASK demodulator in transparent mode * mf ultralight: add upper page bound for NTAGI2C1K * furi hal nfc: set event if nfc event was started * nfc: fix PVS warnings * lib signal reader: remove gpio pull setting in alloc * furi: added math.h include for compatibility with existing apps * nfc: remove resolved TODO in mf desfire poller * bump api symbol version Co-authored-by: hedger Co-authored-by: あく --- firmware.scons | 9 --------- firmware/targets/f18/api_symbols.csv | 2 +- firmware/targets/f7/api_symbols.csv | 2 +- firmware/targets/f7/furi_hal/furi_hal_nfc_event.c | 5 +++-- firmware/targets/f7/furi_hal/furi_hal_nfc_irq.c | 2 +- firmware/targets/f7/furi_hal/furi_hal_nfc_iso15693.c | 2 +- furi/furi.h | 3 +++ lib/nfc/SConscript | 2 +- lib/nfc/protocols/mf_ultralight/mf_ultralight.c | 2 +- .../protocols/mf_ultralight/mf_ultralight_listener_i.c | 2 ++ lib/signal_reader/parsers/iso15693/iso15693_parser.c | 2 +- 11 files changed, 15 insertions(+), 18 deletions(-) diff --git a/firmware.scons b/firmware.scons index d8e96ad7d0..82f775d719 100644 --- a/firmware.scons +++ b/firmware.scons @@ -71,15 +71,6 @@ env = ENV.Clone( "FURI_DEBUG" if ENV["DEBUG"] else "FURI_NDEBUG", ], }, - "nfc": { - "CCFLAGS": [ - "-Og", - ], - "CPPDEFINES": [ - "NDEBUG", - "FURI_DEBUG", - ], - }, }, FW_API_TABLE=None, _APP_ICONS=None, diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index 8e15030a94..4789d316d6 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,40.0,, +Version,+,40.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 3ae099b5f1..038a22eae4 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,40.0,, +Version,+,40.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_event.c b/firmware/targets/f7/furi_hal/furi_hal_nfc_event.c index cce16c5dc9..266b606fd1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc_event.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc_event.c @@ -25,9 +25,10 @@ FuriHalNfcError furi_hal_nfc_event_stop() { void furi_hal_nfc_event_set(FuriHalNfcEventInternalType event) { furi_assert(furi_hal_nfc_event); - furi_assert(furi_hal_nfc_event->thread); - furi_thread_flags_set(furi_hal_nfc_event->thread, event); + if(furi_hal_nfc_event->thread) { + furi_thread_flags_set(furi_hal_nfc_event->thread, event); + } } FuriHalNfcError furi_hal_nfc_abort() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_irq.c b/firmware/targets/f7/furi_hal/furi_hal_nfc_irq.c index 63dc354155..170d8dee61 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc_irq.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc_irq.c @@ -23,6 +23,6 @@ void furi_hal_nfc_init_gpio_isr() { } void furi_hal_nfc_deinit_gpio_isr() { - furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); furi_hal_gpio_remove_int_callback(&gpio_nfc_irq_rfid_pull); + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_iso15693.c b/firmware/targets/f7/furi_hal/furi_hal_nfc_iso15693.c index 19ac6dc034..cc936644b4 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc_iso15693.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc_iso15693.c @@ -48,7 +48,7 @@ static FuriHalNfcIso15693Listener* furi_hal_nfc_iso15693_listener_alloc() { instance->signal = iso15693_signal_alloc(&gpio_spi_r_mosi); instance->parser = - iso15693_parser_alloc(&gpio_spi_r_miso, FURI_HAL_NFC_ISO15693_MAX_FRAME_SIZE); + iso15693_parser_alloc(&gpio_nfc_irq_rfid_pull, FURI_HAL_NFC_ISO15693_MAX_FRAME_SIZE); return instance; } diff --git a/furi/furi.h b/furi/furi.h index cfdeb2c0f4..b1299c9a95 100644 --- a/furi/furi.h +++ b/furi/furi.h @@ -24,6 +24,9 @@ // FreeRTOS timer, REMOVE AFTER REFACTORING #include +// Workaround for math.h leaking through HAL in older versions +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 0e09b69392..6c55cf5d2b 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -51,7 +51,7 @@ env.Append( libenv = env.Clone(FW_LIB_NAME="nfc") libenv.ApplyLibFlags() -sources = libenv.GlobRecursive("*.c*", exclude="deprecated/*c") +sources = libenv.GlobRecursive("*.c*") lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c index 40d9976863..fd845f3c08 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.c @@ -297,7 +297,7 @@ bool mf_ultralight_load(MfUltralightData* data, FlipperFormat* ff, uint32_t vers uint32_t pages_total = 0; if(!flipper_format_read_uint32(ff, MF_ULTRALIGHT_PAGES_TOTAL_KEY, &pages_total, 1)) break; uint32_t pages_read = 0; - if(data_format_version < mf_ultralight_data_format_version) { + if(data_format_version < mf_ultralight_data_format_version) { //-V547 pages_read = pages_total; } else { if(!flipper_format_read_uint32(ff, MF_ULTRALIGHT_PAGES_READ_KEY, &pages_read, 1)) diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c index 3d6b9a94fd..64647492de 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener_i.c @@ -518,6 +518,8 @@ static uint16_t mf_ultralight_get_upper_page_bound(MfUltralightType type) { upper_page_bound = 511; else if(type == MfUltralightTypeNTAGI2C2K) upper_page_bound = 479; + else if(type == MfUltralightTypeNTAGI2C1K) + upper_page_bound = 225; else { upper_page_bound = mf_ultralight_get_config_page_num(type) - 2; } diff --git a/lib/signal_reader/parsers/iso15693/iso15693_parser.c b/lib/signal_reader/parsers/iso15693/iso15693_parser.c index a398516c92..c5326a354d 100644 --- a/lib/signal_reader/parsers/iso15693/iso15693_parser.c +++ b/lib/signal_reader/parsers/iso15693/iso15693_parser.c @@ -68,7 +68,7 @@ Iso15693Parser* iso15693_parser_alloc(const GpioPin* pin, size_t max_frame_size) signal_reader_set_sample_rate( instance->signal_reader, SignalReaderTimeUnit64Mhz, ISO15693_PARSER_BITRATE_F64MHZ); signal_reader_set_pull(instance->signal_reader, GpioPullDown); - signal_reader_set_polarity(instance->signal_reader, SignalReaderPolarityInverted); + signal_reader_set_polarity(instance->signal_reader, SignalReaderPolarityNormal); signal_reader_set_trigger(instance->signal_reader, SignalReaderTriggerRisingFallingEdge); return instance; From cfaf7455232db493f81ce5c036100029fd18bad2 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Sat, 28 Oct 2023 17:29:14 +0300 Subject: [PATCH 03/40] [FL-3643] Fix crash when reading files > 64B (#3166) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Increase MF DESFire result buffer * Ignore chunks that do not fit into the result buffer and show warning * Display information about partial files Co-authored-by: あく --- .../mf_desfire/mf_desfire_render.c | 18 +++++++++++++++++- .../protocols/mf_desfire/mf_desfire_poller.c | 11 ++++++----- .../protocols/mf_desfire/mf_desfire_poller_i.c | 10 +++++++++- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c index b5ca0d1383..94b333f552 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c +++ b/applications/main/nfc/helpers/protocol_support/mf_desfire/mf_desfire_render.c @@ -190,6 +190,8 @@ void nfc_render_mf_desfire_file_settings_data( uint32_t record_count = 1; uint32_t record_size = 0; + const uint32_t total_size = simple_array_get_count(data->data); + switch(settings->type) { case MfDesfireFileTypeStandard: case MfDesfireFileTypeBackup: @@ -220,9 +222,20 @@ void nfc_render_mf_desfire_file_settings_data( } for(uint32_t rec = 0; rec < record_count; rec++) { - furi_string_cat_printf(str, "record %lu\n", rec); + const uint32_t size_offset = rec * record_size; + const uint32_t size_remaining = total_size > size_offset ? total_size - size_offset : 0; + + if(size_remaining < record_size) { + furi_string_cat_printf( + str, "record %lu (partial %lu of %lu)\n", rec, size_remaining, record_size); + record_size = size_remaining; + } else { + furi_string_cat_printf(str, "record %lu\n", rec); + } + for(uint32_t ch = 0; ch < record_size; ch += 4) { furi_string_cat_printf(str, "%03lx|", ch); + for(uint32_t i = 0; i < 4; i++) { if(ch + i < record_size) { const uint32_t data_index = rec * record_size + ch + i; @@ -233,6 +246,7 @@ void nfc_render_mf_desfire_file_settings_data( furi_string_cat_printf(str, " "); } } + for(uint32_t i = 0; i < 4 && ch + i < record_size; i++) { const uint32_t data_index = rec * record_size + ch + i; const uint8_t data_byte = @@ -243,8 +257,10 @@ void nfc_render_mf_desfire_file_settings_data( furi_string_cat_printf(str, "."); } } + furi_string_push_back(str, '\n'); } + furi_string_push_back(str, '\n'); } } diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index c74bbc89da..11db021d57 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -6,7 +6,8 @@ #define TAG "MfDesfirePoller" -#define MF_DESFIRE_BUF_SIZE_MAX (64U) +#define MF_DESFIRE_BUF_SIZE (64U) +#define MF_DESFIRE_RESULT_BUF_SIZE (512U) typedef NfcCommand (*MfDesfirePollerReadHandler)(MfDesfirePoller* instance); @@ -20,10 +21,10 @@ static MfDesfirePoller* mf_desfire_poller_alloc(Iso14443_4aPoller* iso14443_4a_p MfDesfirePoller* instance = malloc(sizeof(MfDesfirePoller)); instance->iso14443_4a_poller = iso14443_4a_poller; instance->data = mf_desfire_alloc(); - instance->tx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); - instance->rx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); - instance->input_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); - instance->result_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE_MAX); + instance->tx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE); + instance->rx_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE); + instance->input_buffer = bit_buffer_alloc(MF_DESFIRE_BUF_SIZE); + instance->result_buffer = bit_buffer_alloc(MF_DESFIRE_RESULT_BUF_SIZE); instance->mf_desfire_event.data = &instance->mf_desfire_event_data; diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 17377d66e3..38ae2f466d 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -59,7 +59,15 @@ MfDesfireError mf_desfire_send_chunks( break; } - bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t)); + const size_t rx_size = bit_buffer_get_size_bytes(instance->rx_buffer); + const size_t rx_capacity_remaining = + bit_buffer_get_capacity_bytes(rx_buffer) - bit_buffer_get_size_bytes(rx_buffer); + + if(rx_size <= rx_capacity_remaining) { + bit_buffer_append_right(rx_buffer, instance->rx_buffer, sizeof(uint8_t)); + } else { + FURI_LOG_W(TAG, "RX buffer overflow: ignoring %zu bytes", rx_size); + } } } while(false); From 0fe93fcfa48ea08479b72c6650fbf4ccf95d445d Mon Sep 17 00:00:00 2001 From: Augusto Zanellato Date: Sat, 28 Oct 2023 16:45:08 +0200 Subject: [PATCH 04/40] fix crash after st25tb save (#3170) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../main/nfc/helpers/protocol_support/st25tb/st25tb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c index eef723fed3..32b2f47757 100644 --- a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c +++ b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c @@ -95,6 +95,11 @@ const NfcProtocolSupportBase nfc_protocol_support_st25tb = { .on_enter = nfc_protocol_support_common_on_enter_empty, .on_event = nfc_scene_saved_menu_on_event_st25tb, }, + .scene_save_name = + { + .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_event = nfc_protocol_support_common_on_event_empty, + }, .scene_emulate = { .on_enter = nfc_protocol_support_common_on_enter_empty, From 176fb21f5fee9cb41dee6e1d54dba42c526256f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 30 Oct 2023 23:51:51 +0900 Subject: [PATCH 05/40] Storage: speedup write_chunk cli command (#3173) * Storage: speedup write_chunk cli command * Storage: handle disconnect on write_chunk correctly --- applications/services/storage/storage_cli.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index 74bcf2d92a..59489d459c 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -333,11 +333,9 @@ static void storage_cli_write_chunk(Cli* cli, FuriString* path, FuriString* args if(buffer_size) { uint8_t* buffer = malloc(buffer_size); - for(uint32_t i = 0; i < buffer_size; i++) { - buffer[i] = cli_getc(cli); - } + size_t read_bytes = cli_read(cli, buffer, buffer_size); - uint16_t written_size = storage_file_write(file, buffer, buffer_size); + uint16_t written_size = storage_file_write(file, buffer, read_bytes); if(written_size != buffer_size) { storage_cli_print_error(storage_file_get_error(file)); From 917410a0a84fbfc0064cb51757972bce743b3980 Mon Sep 17 00:00:00 2001 From: hedger Date: Mon, 30 Oct 2023 19:17:30 +0400 Subject: [PATCH 06/40] [FL-3629] fbt: reworked assets & resources handling (#3160) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fbt: reworking targets & assets handling WIP * fbt: dist fixes * fbt: moved SD card resources to owning apps * unit_tests: moved resources to app folder * github: updated unit_tests paths * github: packaging fixes * unit_tests: fixes * fbt: assets: internal cleanup * fbt: reworked assets handling * github: unit_tests: reintroducing fixes * minor cleanup * fbt: naming changes to reflect private nature of scons tools * fbt: resources: fixed dist archive paths * docs: updated paths * docs: updated more paths * docs: included "resources" parameter in app manifest docs; updated assets readme * updated gitignore for assets * github: updated action versions * unit_tests: restored timeout; scripts: assets: logging changes * gh: don't upload desktop animations for unit test run Co-authored-by: あく --- .github/CODEOWNERS | 4 +- .github/workflows/build.yml | 8 +- .github/workflows/build_compact.yml | 4 +- .../workflows/lint_and_submodule_check.yml | 2 +- .github/workflows/merge_report.yml | 2 +- .github/workflows/pvs_studio.yml | 2 +- .github/workflows/unit_tests.yml | 8 +- .github/workflows/updater_test.yml | 4 +- SConstruct | 34 +++--- applications/debug/unit_tests/application.fam | 1 + .../debug/unit_tests/manifest/manifest.c | 2 +- .../resources/unit_tests/Manifest_test | 0 .../unit_tests/infrared/test_kaseikyo.irtest | 0 .../unit_tests/infrared/test_nec.irtest | 0 .../unit_tests/infrared/test_nec42.irtest | 0 .../unit_tests/infrared/test_nec42ext.irtest | 0 .../unit_tests/infrared/test_necext.irtest | 0 .../unit_tests/infrared/test_rc5.irtest | 0 .../unit_tests/infrared/test_rc5x.irtest | 0 .../unit_tests/infrared/test_rc6.irtest | 0 .../unit_tests/infrared/test_rca.irtest | 0 .../unit_tests/infrared/test_samsung32.irtest | 0 .../unit_tests/infrared/test_sirc.irtest | 0 .../unit_tests/nfc/Ntag213_locked.nfc | 0 .../resources}/unit_tests/nfc/Ntag215.nfc | 0 .../resources}/unit_tests/nfc/Ntag216.nfc | 0 .../unit_tests/nfc/Ultralight_11.nfc | 0 .../unit_tests/nfc/Ultralight_21.nfc | 0 .../unit_tests/nfc/nfc_nfca_signal_long.nfc | 0 .../unit_tests/nfc/nfc_nfca_signal_short.nfc | 0 .../resources}/unit_tests/storage/md5.txt | 0 .../unit_tests/subghz/alutech_at_4n_raw.sub | 0 .../resources}/unit_tests/subghz/ansonic.sub | 0 .../unit_tests/subghz/ansonic_raw.sub | 0 .../resources}/unit_tests/subghz/bett.sub | 0 .../resources}/unit_tests/subghz/bett_raw.sub | 0 .../resources}/unit_tests/subghz/came.sub | 0 .../unit_tests/subghz/came_atomo_raw.sub | 0 .../resources}/unit_tests/subghz/came_raw.sub | 0 .../unit_tests/subghz/came_twee.sub | 0 .../unit_tests/subghz/came_twee_raw.sub | 0 .../unit_tests/subghz/cenmax_raw.sub | 0 .../resources}/unit_tests/subghz/clemsa.sub | 0 .../unit_tests/subghz/clemsa_raw.sub | 0 .../resources}/unit_tests/subghz/doitrand.sub | 0 .../unit_tests/subghz/doitrand_raw.sub | 0 .../resources}/unit_tests/subghz/doorhan.sub | 0 .../unit_tests/subghz/doorhan_raw.sub | 0 .../resources}/unit_tests/subghz/dooya.sub | 0 .../unit_tests/subghz/dooya_raw.sub | 0 .../unit_tests/subghz/faac_slh_raw.sub | 0 .../resources}/unit_tests/subghz/gate_tx.sub | 0 .../unit_tests/subghz/gate_tx_raw.sub | 0 .../resources}/unit_tests/subghz/holtek.sub | 0 .../unit_tests/subghz/holtek_ht12x.sub | 0 .../unit_tests/subghz/holtek_ht12x_raw.sub | 0 .../unit_tests/subghz/holtek_raw.sub | 0 .../unit_tests/subghz/honeywell_wdb.sub | 0 .../unit_tests/subghz/honeywell_wdb_raw.sub | 0 .../unit_tests/subghz/hormann_hsm_raw.sub | 0 .../unit_tests/subghz/ido_117_111_raw.sub | 0 .../unit_tests/subghz/intertechno_v3.sub | 0 .../unit_tests/subghz/intertechno_v3_raw.sub | 0 .../unit_tests/subghz/kia_seed_raw.sub | 0 .../subghz/kinggates_stylo4k_raw.sub | 0 .../resources}/unit_tests/subghz/linear.sub | 0 .../unit_tests/subghz/linear_delta3.sub | 0 .../unit_tests/subghz/linear_delta3_raw.sub | 0 .../unit_tests/subghz/linear_raw.sub | 0 .../resources}/unit_tests/subghz/magellan.sub | 0 .../unit_tests/subghz/magellan_raw.sub | 0 .../resources}/unit_tests/subghz/marantec.sub | 0 .../unit_tests/subghz/marantec_raw.sub | 0 .../resources}/unit_tests/subghz/megacode.sub | 0 .../unit_tests/subghz/megacode_raw.sub | 0 .../unit_tests/subghz/nero_radio_raw.sub | 0 .../unit_tests/subghz/nero_sketch_raw.sub | 0 .../resources}/unit_tests/subghz/nice_flo.sub | 0 .../unit_tests/subghz/nice_flo_raw.sub | 0 .../unit_tests/subghz/nice_flor_s_raw.sub | 0 .../unit_tests/subghz/nice_one_raw.sub | 0 .../unit_tests/subghz/phoenix_v2.sub | 0 .../unit_tests/subghz/phoenix_v2_raw.sub | 0 .../unit_tests/subghz/power_smart.sub | 0 .../unit_tests/subghz/power_smart_raw.sub | 0 .../unit_tests/subghz/princeton.sub | 0 .../unit_tests/subghz/princeton_raw.sub | 0 .../subghz/scher_khan_magic_code.sub | 0 .../unit_tests/subghz/security_pls_1_0.sub | 0 .../subghz/security_pls_1_0_raw.sub | 0 .../unit_tests/subghz/security_pls_2_0.sub | 0 .../subghz/security_pls_2_0_raw.sub | 0 .../resources}/unit_tests/subghz/smc5326.sub | 0 .../unit_tests/subghz/smc5326_raw.sub | 0 .../unit_tests/subghz/somfy_keytis_raw.sub | 0 .../unit_tests/subghz/somfy_telis_raw.sub | 0 .../unit_tests/subghz/test_random_raw.sub | 0 applications/main/bad_usb/application.fam | 1 + .../badusb/Install_qFlipper_macOS.txt | 0 .../badusb/Install_qFlipper_windows.txt | 0 .../resources/badusb/assets/layouts/ba-BA.kl | Bin .../resources/badusb/assets/layouts/cz_CS.kl | Bin .../resources/badusb/assets/layouts/da-DA.kl | Bin .../resources/badusb/assets/layouts/de-CH.kl | Bin .../resources/badusb/assets/layouts/de-DE.kl | Bin .../resources/badusb/assets/layouts/dvorak.kl | Bin .../resources/badusb/assets/layouts/en-UK.kl | Bin .../resources/badusb/assets/layouts/en-US.kl | Bin .../resources/badusb/assets/layouts/es-ES.kl | Bin .../resources/badusb/assets/layouts/fr-BE.kl | Bin .../resources/badusb/assets/layouts/fr-CA.kl | Bin .../resources/badusb/assets/layouts/fr-CH.kl | Bin .../badusb/assets/layouts/fr-FR-mac.kl | Bin .../resources/badusb/assets/layouts/fr-FR.kl | Bin .../resources/badusb/assets/layouts/hr-HR.kl | Bin .../resources/badusb/assets/layouts/hu-HU.kl | Bin .../resources/badusb/assets/layouts/it-IT.kl | Bin .../resources/badusb/assets/layouts/nb-NO.kl | Bin .../resources/badusb/assets/layouts/nl-NL.kl | Bin .../resources/badusb/assets/layouts/pt-BR.kl | Bin .../resources/badusb/assets/layouts/pt-PT.kl | Bin .../resources/badusb/assets/layouts/si-SI.kl | Bin .../resources/badusb/assets/layouts/sk-SK.kl | Bin .../resources/badusb/assets/layouts/sv-SE.kl | Bin .../resources/badusb/assets/layouts/tr-TR.kl | Bin .../bad_usb}/resources/badusb/demo_macos.txt | 0 .../resources/badusb/demo_windows.txt | 0 applications/main/infrared/application.fam | 1 + .../infrared}/resources/infrared/assets/ac.ir | 0 .../resources/infrared/assets/audio.ir | 0 .../resources/infrared/assets/projector.ir | 0 .../infrared}/resources/infrared/assets/tv.ir | 0 applications/main/nfc/application.fam | 1 + .../main/nfc}/resources/nfc/assets/aid.nfc | 0 .../resources/nfc/assets/country_code.nfc | 0 .../resources/nfc/assets/currency_code.nfc | 0 .../resources/nfc/assets/mf_classic_dict.nfc | 0 applications/main/subghz/application.fam | 1 + .../resources/subghz/assets/alutech_at_4n | 0 .../resources/subghz/assets/came_atomo | 0 .../resources/subghz/assets/keeloq_mfcodes | 0 .../subghz/assets/keeloq_mfcodes_user.example | 0 .../resources/subghz/assets/nice_flor_s | 0 .../subghz/assets/setting_user.example | 0 applications/main/u2f/application.fam | 1 + .../main/u2f}/resources/u2f/assets/cert.der | Bin .../u2f}/resources/u2f/assets/cert_key.u2f | 0 applications/services/loader/loader.c | 2 +- applications/services/loader/loader.h | 4 +- .../system/snake_game/application.fam | 1 - assets/.gitignore | 4 - assets/ReadMe.md | 3 - assets/SConscript | 54 +++------- documentation/AppManifests.md | 1 + documentation/AppsOnSDCard.md | 2 +- documentation/HardwareTargets.md | 2 +- documentation/UnitTests.md | 13 ++- documentation/UniversalRemotes.md | 6 +- .../file_formats/InfraredFileFormats.md | 8 +- firmware.scons | 38 ++++--- scripts/ReadMe.md | 4 +- scripts/assets.py | 10 +- scripts/fbt/appmanifest.py | 15 ++- scripts/fbt_tools/fbt_assets.py | 90 +++++++++++----- scripts/fbt_tools/fbt_dist.py | 21 +++- scripts/fbt_tools/fbt_extapps.py | 93 +++++++--------- scripts/fbt_tools/fbt_hwtarget.py | 23 ++-- scripts/fbt_tools/fbt_resources.py | 98 +++++++++++++++++ scripts/fbt_tools/fbt_sdk.py | 24 ++--- scripts/fbt_tools/fbt_version.py | 4 +- scripts/fbt_tools/pvsstudio.py | 4 +- scripts/flipper/assets/dolphin.py | 2 +- scripts/meta.py | 60 ----------- .../app_template/.github/workflows/build.yml | 4 +- site_scons/extapps.scons | 4 - {firmware => targets}/ReadMe.md | 0 {firmware => targets}/SConscript | 0 .../targets => targets}/f18/api_symbols.csv | 90 ++++++++-------- .../f18/furi_hal/furi_hal.c | 0 .../f18/furi_hal/furi_hal_power_config.c | 0 .../f18/furi_hal/furi_hal_resources.c | 0 .../f18/furi_hal/furi_hal_resources.h | 0 .../f18/furi_hal/furi_hal_spi_config.c | 0 .../f18/furi_hal/furi_hal_spi_config.h | 0 .../f18/furi_hal/furi_hal_target_hw.h | 0 .../f18/furi_hal/furi_hal_version_device.c | 0 {firmware/targets => targets}/f18/target.json | 0 .../targets => targets}/f7/api_symbols.csv | 100 +++++++++--------- .../targets => targets}/f7/application_ext.ld | 0 .../f7/ble_glue/app_common.h | 0 .../f7/ble_glue/app_conf.h | 0 .../f7/ble_glue/app_debug.c | 0 .../f7/ble_glue/app_debug.h | 0 .../targets => targets}/f7/ble_glue/ble_app.c | 0 .../targets => targets}/f7/ble_glue/ble_app.h | 0 .../f7/ble_glue/ble_conf.h | 0 .../f7/ble_glue/ble_const.h | 0 .../f7/ble_glue/ble_dbg_conf.h | 0 .../f7/ble_glue/ble_glue.c | 0 .../f7/ble_glue/ble_glue.h | 0 .../f7/ble_glue/compiler.h | 0 .../targets => targets}/f7/ble_glue/gap.c | 0 .../targets => targets}/f7/ble_glue/gap.h | 0 .../f7/ble_glue/hsem_map.h | 0 .../targets => targets}/f7/ble_glue/hw_ipcc.c | 0 .../targets => targets}/f7/ble_glue/osal.h | 0 .../f7/ble_glue/services/battery_service.c | 0 .../f7/ble_glue/services/battery_service.h | 0 .../f7/ble_glue/services/dev_info_service.c | 0 .../f7/ble_glue/services/dev_info_service.h | 0 .../services/dev_info_service_uuid.inc | 0 .../f7/ble_glue/services/gatt_char.c | 0 .../f7/ble_glue/services/gatt_char.h | 0 .../f7/ble_glue/services/hid_service.c | 0 .../f7/ble_glue/services/hid_service.h | 0 .../f7/ble_glue/services/serial_service.c | 0 .../f7/ble_glue/services/serial_service.h | 0 .../ble_glue/services/serial_service_uuid.inc | 0 .../f7/ble_glue/tl_dbg_conf.h | 0 .../targets => targets}/f7/fatfs/fatfs.c | 0 .../targets => targets}/f7/fatfs/fatfs.h | 0 .../targets => targets}/f7/fatfs/ffconf.h | 0 .../f7/fatfs/sector_cache.c | 0 .../f7/fatfs/sector_cache.h | 0 .../f7/fatfs/user_diskio.c | 0 .../f7/fatfs/user_diskio.h | 0 .../f7/furi_hal/furi_hal.c | 0 .../f7/furi_hal/furi_hal_bt.c | 0 .../f7/furi_hal/furi_hal_bt_hid.c | 0 .../f7/furi_hal/furi_hal_bt_serial.c | 0 .../f7/furi_hal/furi_hal_bus.c | 0 .../f7/furi_hal/furi_hal_bus.h | 0 .../f7/furi_hal/furi_hal_clock.c | 0 .../f7/furi_hal/furi_hal_clock.h | 0 .../f7/furi_hal/furi_hal_console.c | 0 .../f7/furi_hal/furi_hal_console.h | 0 .../f7/furi_hal/furi_hal_cortex.c | 0 .../f7/furi_hal/furi_hal_crypto.c | 0 .../f7/furi_hal/furi_hal_debug.c | 0 .../f7/furi_hal/furi_hal_dma.c | 0 .../f7/furi_hal/furi_hal_dma.h | 0 .../f7/furi_hal/furi_hal_flash.c | 0 .../f7/furi_hal/furi_hal_flash.h | 0 .../f7/furi_hal/furi_hal_gpio.c | 0 .../f7/furi_hal/furi_hal_gpio.h | 0 .../f7/furi_hal/furi_hal_i2c.c | 0 .../f7/furi_hal/furi_hal_i2c_config.c | 0 .../f7/furi_hal/furi_hal_i2c_config.h | 0 .../f7/furi_hal/furi_hal_i2c_types.h | 0 .../f7/furi_hal/furi_hal_ibutton.c | 0 .../f7/furi_hal/furi_hal_ibutton.h | 0 .../f7/furi_hal/furi_hal_idle_timer.h | 0 .../f7/furi_hal/furi_hal_info.c | 0 .../f7/furi_hal/furi_hal_infrared.c | 0 .../f7/furi_hal/furi_hal_interrupt.c | 0 .../f7/furi_hal/furi_hal_interrupt.h | 0 .../f7/furi_hal/furi_hal_light.c | 0 .../f7/furi_hal/furi_hal_memory.c | 0 .../f7/furi_hal/furi_hal_mpu.c | 0 .../f7/furi_hal/furi_hal_nfc.c | 0 .../f7/furi_hal/furi_hal_nfc_event.c | 0 .../f7/furi_hal/furi_hal_nfc_felica.c | 0 .../f7/furi_hal/furi_hal_nfc_i.h | 0 .../f7/furi_hal/furi_hal_nfc_irq.c | 0 .../f7/furi_hal/furi_hal_nfc_iso14443a.c | 0 .../f7/furi_hal/furi_hal_nfc_iso14443b.c | 0 .../f7/furi_hal/furi_hal_nfc_iso15693.c | 0 .../f7/furi_hal/furi_hal_nfc_tech_i.h | 0 .../f7/furi_hal/furi_hal_nfc_timer.c | 0 .../f7/furi_hal/furi_hal_os.c | 0 .../f7/furi_hal/furi_hal_os.h | 0 .../f7/furi_hal/furi_hal_power.c | 0 .../f7/furi_hal/furi_hal_power_config.c | 0 .../f7/furi_hal/furi_hal_pwm.c | 0 .../f7/furi_hal/furi_hal_pwm.h | 0 .../f7/furi_hal/furi_hal_random.c | 0 .../f7/furi_hal/furi_hal_region.c | 0 .../f7/furi_hal/furi_hal_resources.c | 0 .../f7/furi_hal/furi_hal_resources.h | 0 .../f7/furi_hal/furi_hal_rfid.c | 0 .../f7/furi_hal/furi_hal_rfid.h | 0 .../f7/furi_hal/furi_hal_rtc.c | 0 .../f7/furi_hal/furi_hal_sd.c | 0 .../f7/furi_hal/furi_hal_speaker.c | 0 .../f7/furi_hal/furi_hal_spi.c | 0 .../f7/furi_hal/furi_hal_spi_config.c | 0 .../f7/furi_hal/furi_hal_spi_config.h | 0 .../f7/furi_hal/furi_hal_spi_types.h | 0 .../f7/furi_hal/furi_hal_subghz.c | 0 .../f7/furi_hal/furi_hal_subghz.h | 0 .../f7/furi_hal/furi_hal_target_hw.h | 0 .../f7/furi_hal/furi_hal_uart.c | 0 .../f7/furi_hal/furi_hal_uart.h | 0 .../f7/furi_hal/furi_hal_usb.c | 0 .../f7/furi_hal/furi_hal_usb_ccid.c | 0 .../f7/furi_hal/furi_hal_usb_cdc.c | 0 .../f7/furi_hal/furi_hal_usb_cdc.h | 0 .../f7/furi_hal/furi_hal_usb_hid.c | 0 .../f7/furi_hal/furi_hal_usb_i.h | 0 .../f7/furi_hal/furi_hal_usb_u2f.c | 0 .../f7/furi_hal/furi_hal_version.c | 0 .../f7/furi_hal/furi_hal_version_device.c | 0 .../f7/furi_hal/furi_hal_vibro.c | 0 .../f7/inc/FreeRTOSConfig.h | 0 .../targets => targets}/f7/inc/alt_boot.h | 0 {firmware/targets => targets}/f7/inc/stm32.h | 0 .../targets => targets}/f7/inc/stm32_assert.h | 0 .../f7/platform_specific/intrinsic_export.h | 0 .../f7/platform_specific/math_wrapper.h | 0 {firmware/targets => targets}/f7/src/dfu.c | 0 {firmware/targets => targets}/f7/src/main.c | 0 .../targets => targets}/f7/src/recovery.c | 0 .../f7/src/system_stm32wbxx.c | 0 {firmware/targets => targets}/f7/src/update.c | 0 .../f7/startup_stm32wb55xx_cm4.s | 0 .../f7/stm32wb55xx_flash.ld | 0 .../f7/stm32wb55xx_ram_fw.ld | 0 {firmware/targets => targets}/f7/target.json | 0 .../furi_hal_include/furi_hal.h | 0 .../furi_hal_include/furi_hal_bt.h | 0 .../furi_hal_include/furi_hal_bt_hid.h | 0 .../furi_hal_include/furi_hal_bt_serial.h | 0 .../furi_hal_include/furi_hal_cortex.h | 0 .../furi_hal_include/furi_hal_crypto.h | 0 .../furi_hal_include/furi_hal_debug.h | 0 .../furi_hal_include/furi_hal_i2c.h | 0 .../furi_hal_include/furi_hal_info.h | 0 .../furi_hal_include/furi_hal_infrared.h | 0 .../furi_hal_include/furi_hal_light.h | 0 .../furi_hal_include/furi_hal_memory.h | 0 .../furi_hal_include/furi_hal_mpu.h | 0 .../furi_hal_include/furi_hal_nfc.h | 0 .../furi_hal_include/furi_hal_power.h | 0 .../furi_hal_include/furi_hal_random.h | 0 .../furi_hal_include/furi_hal_region.h | 0 .../furi_hal_include/furi_hal_rtc.h | 0 .../furi_hal_include/furi_hal_sd.h | 0 .../furi_hal_include/furi_hal_speaker.h | 0 .../furi_hal_include/furi_hal_spi.h | 0 .../furi_hal_include/furi_hal_usb.h | 0 .../furi_hal_include/furi_hal_usb_ccid.h | 0 .../furi_hal_include/furi_hal_usb_hid.h | 0 .../furi_hal_include/furi_hal_usb_hid_u2f.h | 0 .../furi_hal_include/furi_hal_version.h | 0 .../furi_hal_include/furi_hal_vibro.h | 0 345 files changed, 466 insertions(+), 394 deletions(-) rename assets/unit_tests/Manifest => applications/debug/unit_tests/resources/unit_tests/Manifest_test (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_kaseikyo.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_nec.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_nec42.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_nec42ext.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_necext.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_rc5.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_rc5x.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_rc6.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_rca.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_samsung32.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/infrared/test_sirc.irtest (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/nfc/Ntag213_locked.nfc (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/nfc/Ntag215.nfc (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/nfc/Ntag216.nfc (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/nfc/Ultralight_11.nfc (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/nfc/Ultralight_21.nfc (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/nfc/nfc_nfca_signal_long.nfc (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/nfc/nfc_nfca_signal_short.nfc (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/storage/md5.txt (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/alutech_at_4n_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/ansonic.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/ansonic_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/bett.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/bett_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/came.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/came_atomo_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/came_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/came_twee.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/came_twee_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/cenmax_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/clemsa.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/clemsa_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/doitrand.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/doitrand_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/doorhan.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/doorhan_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/dooya.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/dooya_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/faac_slh_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/gate_tx.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/gate_tx_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/holtek.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/holtek_ht12x.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/holtek_ht12x_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/holtek_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/honeywell_wdb.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/honeywell_wdb_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/hormann_hsm_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/ido_117_111_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/intertechno_v3.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/intertechno_v3_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/kia_seed_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/kinggates_stylo4k_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/linear.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/linear_delta3.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/linear_delta3_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/linear_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/magellan.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/magellan_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/marantec.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/marantec_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/megacode.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/megacode_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/nero_radio_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/nero_sketch_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/nice_flo.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/nice_flo_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/nice_flor_s_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/nice_one_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/phoenix_v2.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/phoenix_v2_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/power_smart.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/power_smart_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/princeton.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/princeton_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/scher_khan_magic_code.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/security_pls_1_0.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/security_pls_1_0_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/security_pls_2_0.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/security_pls_2_0_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/smc5326.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/smc5326_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/somfy_keytis_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/somfy_telis_raw.sub (100%) rename {assets => applications/debug/unit_tests/resources}/unit_tests/subghz/test_random_raw.sub (100%) rename {assets => applications/main/bad_usb}/resources/badusb/Install_qFlipper_macOS.txt (100%) rename {assets => applications/main/bad_usb}/resources/badusb/Install_qFlipper_windows.txt (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/ba-BA.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/cz_CS.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/da-DA.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/de-CH.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/de-DE.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/dvorak.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/en-UK.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/en-US.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/es-ES.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/fr-BE.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/fr-CA.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/fr-CH.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/fr-FR-mac.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/fr-FR.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/hr-HR.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/hu-HU.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/it-IT.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/nb-NO.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/nl-NL.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/pt-BR.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/pt-PT.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/si-SI.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/sk-SK.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/sv-SE.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/assets/layouts/tr-TR.kl (100%) rename {assets => applications/main/bad_usb}/resources/badusb/demo_macos.txt (100%) rename {assets => applications/main/bad_usb}/resources/badusb/demo_windows.txt (100%) rename {assets => applications/main/infrared}/resources/infrared/assets/ac.ir (100%) rename {assets => applications/main/infrared}/resources/infrared/assets/audio.ir (100%) rename {assets => applications/main/infrared}/resources/infrared/assets/projector.ir (100%) rename {assets => applications/main/infrared}/resources/infrared/assets/tv.ir (100%) rename {assets => applications/main/nfc}/resources/nfc/assets/aid.nfc (100%) rename {assets => applications/main/nfc}/resources/nfc/assets/country_code.nfc (100%) rename {assets => applications/main/nfc}/resources/nfc/assets/currency_code.nfc (100%) rename {assets => applications/main/nfc}/resources/nfc/assets/mf_classic_dict.nfc (100%) rename {assets => applications/main/subghz}/resources/subghz/assets/alutech_at_4n (100%) rename {assets => applications/main/subghz}/resources/subghz/assets/came_atomo (100%) rename {assets => applications/main/subghz}/resources/subghz/assets/keeloq_mfcodes (100%) rename {assets => applications/main/subghz}/resources/subghz/assets/keeloq_mfcodes_user.example (100%) rename {assets => applications/main/subghz}/resources/subghz/assets/nice_flor_s (100%) rename {assets => applications/main/subghz}/resources/subghz/assets/setting_user.example (100%) rename {assets => applications/main/u2f}/resources/u2f/assets/cert.der (100%) rename {assets => applications/main/u2f}/resources/u2f/assets/cert_key.u2f (100%) create mode 100644 scripts/fbt_tools/fbt_resources.py delete mode 100755 scripts/meta.py rename {firmware => targets}/ReadMe.md (100%) rename {firmware => targets}/SConscript (100%) rename {firmware/targets => targets}/f18/api_symbols.csv (98%) rename {firmware/targets => targets}/f18/furi_hal/furi_hal.c (100%) rename {firmware/targets => targets}/f18/furi_hal/furi_hal_power_config.c (100%) rename {firmware/targets => targets}/f18/furi_hal/furi_hal_resources.c (100%) rename {firmware/targets => targets}/f18/furi_hal/furi_hal_resources.h (100%) rename {firmware/targets => targets}/f18/furi_hal/furi_hal_spi_config.c (100%) rename {firmware/targets => targets}/f18/furi_hal/furi_hal_spi_config.h (100%) rename {firmware/targets => targets}/f18/furi_hal/furi_hal_target_hw.h (100%) rename {firmware/targets => targets}/f18/furi_hal/furi_hal_version_device.c (100%) rename {firmware/targets => targets}/f18/target.json (100%) rename {firmware/targets => targets}/f7/api_symbols.csv (98%) rename {firmware/targets => targets}/f7/application_ext.ld (100%) rename {firmware/targets => targets}/f7/ble_glue/app_common.h (100%) rename {firmware/targets => targets}/f7/ble_glue/app_conf.h (100%) rename {firmware/targets => targets}/f7/ble_glue/app_debug.c (100%) rename {firmware/targets => targets}/f7/ble_glue/app_debug.h (100%) rename {firmware/targets => targets}/f7/ble_glue/ble_app.c (100%) rename {firmware/targets => targets}/f7/ble_glue/ble_app.h (100%) rename {firmware/targets => targets}/f7/ble_glue/ble_conf.h (100%) rename {firmware/targets => targets}/f7/ble_glue/ble_const.h (100%) rename {firmware/targets => targets}/f7/ble_glue/ble_dbg_conf.h (100%) rename {firmware/targets => targets}/f7/ble_glue/ble_glue.c (100%) rename {firmware/targets => targets}/f7/ble_glue/ble_glue.h (100%) rename {firmware/targets => targets}/f7/ble_glue/compiler.h (100%) rename {firmware/targets => targets}/f7/ble_glue/gap.c (100%) rename {firmware/targets => targets}/f7/ble_glue/gap.h (100%) rename {firmware/targets => targets}/f7/ble_glue/hsem_map.h (100%) rename {firmware/targets => targets}/f7/ble_glue/hw_ipcc.c (100%) rename {firmware/targets => targets}/f7/ble_glue/osal.h (100%) rename {firmware/targets => targets}/f7/ble_glue/services/battery_service.c (100%) rename {firmware/targets => targets}/f7/ble_glue/services/battery_service.h (100%) rename {firmware/targets => targets}/f7/ble_glue/services/dev_info_service.c (100%) rename {firmware/targets => targets}/f7/ble_glue/services/dev_info_service.h (100%) rename {firmware/targets => targets}/f7/ble_glue/services/dev_info_service_uuid.inc (100%) rename {firmware/targets => targets}/f7/ble_glue/services/gatt_char.c (100%) rename {firmware/targets => targets}/f7/ble_glue/services/gatt_char.h (100%) rename {firmware/targets => targets}/f7/ble_glue/services/hid_service.c (100%) rename {firmware/targets => targets}/f7/ble_glue/services/hid_service.h (100%) rename {firmware/targets => targets}/f7/ble_glue/services/serial_service.c (100%) rename {firmware/targets => targets}/f7/ble_glue/services/serial_service.h (100%) rename {firmware/targets => targets}/f7/ble_glue/services/serial_service_uuid.inc (100%) rename {firmware/targets => targets}/f7/ble_glue/tl_dbg_conf.h (100%) rename {firmware/targets => targets}/f7/fatfs/fatfs.c (100%) rename {firmware/targets => targets}/f7/fatfs/fatfs.h (100%) rename {firmware/targets => targets}/f7/fatfs/ffconf.h (100%) rename {firmware/targets => targets}/f7/fatfs/sector_cache.c (100%) rename {firmware/targets => targets}/f7/fatfs/sector_cache.h (100%) rename {firmware/targets => targets}/f7/fatfs/user_diskio.c (100%) rename {firmware/targets => targets}/f7/fatfs/user_diskio.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_bt.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_bt_hid.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_bt_serial.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_bus.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_bus.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_clock.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_clock.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_console.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_console.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_cortex.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_crypto.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_debug.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_dma.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_dma.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_flash.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_flash.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_gpio.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_gpio.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_i2c.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_i2c_config.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_i2c_config.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_i2c_types.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_ibutton.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_ibutton.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_idle_timer.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_info.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_infrared.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_interrupt.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_interrupt.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_light.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_memory.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_mpu.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc_event.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc_felica.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc_i.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc_irq.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc_iso14443a.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc_iso14443b.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc_iso15693.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc_tech_i.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_nfc_timer.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_os.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_os.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_power.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_power_config.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_pwm.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_pwm.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_random.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_region.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_resources.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_resources.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_rfid.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_rfid.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_rtc.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_sd.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_speaker.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_spi.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_spi_config.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_spi_config.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_spi_types.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_subghz.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_subghz.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_target_hw.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_uart.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_uart.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_usb.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_usb_ccid.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_usb_cdc.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_usb_cdc.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_usb_hid.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_usb_i.h (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_usb_u2f.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_version.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_version_device.c (100%) rename {firmware/targets => targets}/f7/furi_hal/furi_hal_vibro.c (100%) rename {firmware/targets => targets}/f7/inc/FreeRTOSConfig.h (100%) rename {firmware/targets => targets}/f7/inc/alt_boot.h (100%) rename {firmware/targets => targets}/f7/inc/stm32.h (100%) rename {firmware/targets => targets}/f7/inc/stm32_assert.h (100%) rename {firmware/targets => targets}/f7/platform_specific/intrinsic_export.h (100%) rename {firmware/targets => targets}/f7/platform_specific/math_wrapper.h (100%) rename {firmware/targets => targets}/f7/src/dfu.c (100%) rename {firmware/targets => targets}/f7/src/main.c (100%) rename {firmware/targets => targets}/f7/src/recovery.c (100%) rename {firmware/targets => targets}/f7/src/system_stm32wbxx.c (100%) rename {firmware/targets => targets}/f7/src/update.c (100%) rename {firmware/targets => targets}/f7/startup_stm32wb55xx_cm4.s (100%) rename {firmware/targets => targets}/f7/stm32wb55xx_flash.ld (100%) rename {firmware/targets => targets}/f7/stm32wb55xx_ram_fw.ld (100%) rename {firmware/targets => targets}/f7/target.json (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_bt.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_bt_hid.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_bt_serial.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_cortex.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_crypto.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_debug.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_i2c.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_info.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_infrared.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_light.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_memory.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_mpu.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_nfc.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_power.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_random.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_region.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_rtc.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_sd.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_speaker.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_spi.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_usb.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_usb_ccid.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_usb_hid.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_usb_hid_u2f.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_version.h (100%) rename {firmware/targets => targets}/furi_hal_include/furi_hal_vibro.h (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e02c931af9..b72d9ea613 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -42,10 +42,10 @@ /applications/examples/example_thermo/ @skotopes @DrZlo13 @hedger @gsurkov # Firmware targets -/firmware/ @skotopes @DrZlo13 @hedger @nminaylov +/targets/ @skotopes @DrZlo13 @hedger @nminaylov # Assets -/assets/resources/infrared/ @skotopes @DrZlo13 @hedger @gsurkov +/applications/main/infrared/resources/ @skotopes @DrZlo13 @hedger @gsurkov # Documentation /documentation/ @skotopes @DrZlo13 @hedger @drunkbatya diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c55350665..38b1d7b688 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,7 +25,7 @@ jobs: run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 ref: ${{ github.event.pull_request.head.sha }} @@ -51,11 +51,11 @@ jobs: - name: 'Check API versions for consistency between targets' run: | set -e - N_API_HEADER_SIGNATURES=`ls -1 firmware/targets/f*/api_symbols.csv | xargs -I {} sh -c "head -n2 {} | md5sum" | sort -u | wc -l` + N_API_HEADER_SIGNATURES=`ls -1 targets/f*/api_symbols.csv | xargs -I {} sh -c "head -n2 {} | md5sum" | sort -u | wc -l` if [ $N_API_HEADER_SIGNATURES != 1 ] ; then echo API versions aren\'t matching for available targets. Please update! echo API versions are: - head -n2 firmware/targets/f*/api_symbols.csv + head -n2 targets/f*/api_symbols.csv exit 1 fi @@ -76,7 +76,7 @@ jobs: mkdir artifacts map_analyser_files cp dist/${TARGET}-*/* artifacts/ || true tar czpf "artifacts/flipper-z-${TARGET}-resources-${SUFFIX}.tgz" \ - -C assets resources + -C build/latest resources tar czpf "artifacts/flipper-z-${TARGET}-debugapps-${SUFFIX}.tgz" \ -C dist/${TARGET}-*/apps/Debug . tar czpf "artifacts/flipper-z-${TARGET}-appsymbols-${SUFFIX}.tgz" \ diff --git a/.github/workflows/build_compact.yml b/.github/workflows/build_compact.yml index c63be24a47..f45275204a 100644 --- a/.github/workflows/build_compact.yml +++ b/.github/workflows/build_compact.yml @@ -19,7 +19,7 @@ jobs: run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 submodules: false @@ -46,7 +46,7 @@ jobs: echo "hw-target-code=$TARGET" >> $GITHUB_OUTPUT - name: Deploy uFBT with SDK - uses: flipperdevices/flipperzero-ufbt-action@v0.1.0 + uses: flipperdevices/flipperzero-ufbt-action@v0.1 with: task: setup sdk-file: ${{ steps.build-fw.outputs.sdk-file }} diff --git a/.github/workflows/lint_and_submodule_check.yml b/.github/workflows/lint_and_submodule_check.yml index d24422b7cb..51e2593ecc 100644 --- a/.github/workflows/lint_and_submodule_check.yml +++ b/.github/workflows/lint_and_submodule_check.yml @@ -16,7 +16,7 @@ jobs: run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 2 ref: ${{ github.sha }} diff --git a/.github/workflows/merge_report.yml b/.github/workflows/merge_report.yml index fedc4b87fb..90302ce1aa 100644 --- a/.github/workflows/merge_report.yml +++ b/.github/workflows/merge_report.yml @@ -16,7 +16,7 @@ jobs: run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/pvs_studio.yml b/.github/workflows/pvs_studio.yml index 4f650f1b7c..4527e29207 100644 --- a/.github/workflows/pvs_studio.yml +++ b/.github/workflows/pvs_studio.yml @@ -21,7 +21,7 @@ jobs: run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout code' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 2680f520c1..40f72bd0ba 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -17,7 +17,7 @@ jobs: run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 ref: ${{ github.event.pull_request.head.sha }} @@ -32,7 +32,7 @@ jobs: if: success() timeout-minutes: 10 run: | - ./fbt flash SWD_TRANSPORT_SERIAL=2A0906016415303030303032 LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 + ./fbt resources firmware_latest flash SWD_TRANSPORT_SERIAL=2A0906016415303030303032 LIB_DEBUG=1 FIRMWARE_APP_SET=unit_tests FORCE=1 - name: 'Wait for flipper and format ext' id: format_ext @@ -50,8 +50,8 @@ jobs: run: | source scripts/toolchain/fbtenv.sh python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} - python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/resources /ext - python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/unit_tests /ext/unit_tests + rm -rf build/latest/resources/dolphin + python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send build/latest/resources /ext python3 scripts/power.py -p ${{steps.device.outputs.flipper}} reboot python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index 9987fdd324..b14b618a6e 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -17,7 +17,7 @@ jobs: run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 submodules: false @@ -56,7 +56,7 @@ jobs: run: find ./ -mount -maxdepth 1 -exec rm -rf {} \; - name: 'Checkout latest release' - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: failure() with: fetch-depth: 1 diff --git a/SConstruct b/SConstruct index 36e0600235..faccdfa5b3 100644 --- a/SConstruct +++ b/SConstruct @@ -67,22 +67,22 @@ if GetOption("fullenv") or any( # Target for self-update package dist_basic_arguments = [ "--bundlever", - '"${UPDATE_VERSION_STRING}"', + "${UPDATE_VERSION_STRING}", ] dist_radio_arguments = [ "--radio", - '"${ROOT_DIR.abspath}/${COPRO_STACK_BIN_DIR}/${COPRO_STACK_BIN}"', + "${ROOT_DIR.abspath}/${COPRO_STACK_BIN_DIR}/${COPRO_STACK_BIN}", "--radiotype", "${COPRO_STACK_TYPE}", "${COPRO_DISCLAIMER}", "--obdata", - '"${ROOT_DIR.abspath}/${COPRO_OB_DATA}"', + "${ROOT_DIR.abspath}/${COPRO_OB_DATA}", "--stackversion", "${COPRO_CUBE_VERSION}", ] dist_resource_arguments = [ "-r", - '"${ROOT_DIR.abspath}/assets/resources"', + firmware_env.subst("${RESOURCES_ROOT}"), ] dist_splash_arguments = ( [ @@ -95,7 +95,7 @@ if GetOption("fullenv") or any( selfupdate_dist = distenv.DistCommand( "updater_package", - (distenv["DIST_DEPENDS"], firmware_env["FW_RESOURCES"]), + (distenv["DIST_DEPENDS"], firmware_env["FW_RESOURCES_MANIFEST"]), DIST_EXTRA=[ *dist_basic_arguments, *dist_radio_arguments, @@ -128,7 +128,8 @@ if GetOption("fullenv") or any( # Installation over USB & CLI usb_update_package = distenv.AddUsbFlashTarget( - "#build/usbinstall.flag", (firmware_env["FW_RESOURCES"], selfupdate_dist) + "#build/usbinstall.flag", + (firmware_env["FW_RESOURCES_MANIFEST"], selfupdate_dist), ) distenv.Alias("flash_usb_full", usb_update_package) @@ -166,16 +167,23 @@ Depends( list(app_artifact.validator for app_artifact in external_app_list), ) Alias("fap_dist", fap_dist) -# distenv.Default(fap_dist) - -distenv.Depends(firmware_env["FW_RESOURCES"], external_apps_artifacts.resources_dist) # Copy all faps to device fap_deploy = distenv.PhonyTarget( "fap_deploy", - "${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py -p ${FLIP_PORT} send ${SOURCE} /ext/apps", - source=Dir("#/assets/resources/apps"), + [ + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/storage.py", + "-p", + "${FLIP_PORT}", + "send", + "${SOURCE}", + "/ext/apps", + ] + ], + source=firmware_env.Dir(("${RESOURCES_ROOT}/apps")), ) @@ -314,9 +322,7 @@ distenv.PhonyTarget( ) # Start Flipper CLI via PySerial's miniterm -distenv.PhonyTarget( - "cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}" -) +distenv.PhonyTarget("cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}") # Update WiFi devboard firmware distenv.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py") diff --git a/applications/debug/unit_tests/application.fam b/applications/debug/unit_tests/application.fam index ad9a278f38..aa25dab279 100644 --- a/applications/debug/unit_tests/application.fam +++ b/applications/debug/unit_tests/application.fam @@ -5,6 +5,7 @@ App( cdefines=["APP_UNIT_TESTS"], requires=["system_settings"], provides=["delay_test"], + resources="resources", order=100, ) diff --git a/applications/debug/unit_tests/manifest/manifest.c b/applications/debug/unit_tests/manifest/manifest.c index 0b24ad1ed6..19370b0e13 100644 --- a/applications/debug/unit_tests/manifest/manifest.c +++ b/applications/debug/unit_tests/manifest/manifest.c @@ -22,7 +22,7 @@ MU_TEST(manifest_iteration_test) { ResourceManifestReader* manifest_reader = resource_manifest_reader_alloc(storage); do { // Open manifest file - if(!resource_manifest_reader_open(manifest_reader, EXT_PATH("unit_tests/Manifest"))) { + if(!resource_manifest_reader_open(manifest_reader, EXT_PATH("unit_tests/Manifest_test"))) { result = false; break; } diff --git a/assets/unit_tests/Manifest b/applications/debug/unit_tests/resources/unit_tests/Manifest_test similarity index 100% rename from assets/unit_tests/Manifest rename to applications/debug/unit_tests/resources/unit_tests/Manifest_test diff --git a/assets/unit_tests/infrared/test_kaseikyo.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_kaseikyo.irtest similarity index 100% rename from assets/unit_tests/infrared/test_kaseikyo.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_kaseikyo.irtest diff --git a/assets/unit_tests/infrared/test_nec.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_nec.irtest similarity index 100% rename from assets/unit_tests/infrared/test_nec.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_nec.irtest diff --git a/assets/unit_tests/infrared/test_nec42.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_nec42.irtest similarity index 100% rename from assets/unit_tests/infrared/test_nec42.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_nec42.irtest diff --git a/assets/unit_tests/infrared/test_nec42ext.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_nec42ext.irtest similarity index 100% rename from assets/unit_tests/infrared/test_nec42ext.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_nec42ext.irtest diff --git a/assets/unit_tests/infrared/test_necext.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_necext.irtest similarity index 100% rename from assets/unit_tests/infrared/test_necext.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_necext.irtest diff --git a/assets/unit_tests/infrared/test_rc5.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_rc5.irtest similarity index 100% rename from assets/unit_tests/infrared/test_rc5.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_rc5.irtest diff --git a/assets/unit_tests/infrared/test_rc5x.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_rc5x.irtest similarity index 100% rename from assets/unit_tests/infrared/test_rc5x.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_rc5x.irtest diff --git a/assets/unit_tests/infrared/test_rc6.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_rc6.irtest similarity index 100% rename from assets/unit_tests/infrared/test_rc6.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_rc6.irtest diff --git a/assets/unit_tests/infrared/test_rca.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_rca.irtest similarity index 100% rename from assets/unit_tests/infrared/test_rca.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_rca.irtest diff --git a/assets/unit_tests/infrared/test_samsung32.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_samsung32.irtest similarity index 100% rename from assets/unit_tests/infrared/test_samsung32.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_samsung32.irtest diff --git a/assets/unit_tests/infrared/test_sirc.irtest b/applications/debug/unit_tests/resources/unit_tests/infrared/test_sirc.irtest similarity index 100% rename from assets/unit_tests/infrared/test_sirc.irtest rename to applications/debug/unit_tests/resources/unit_tests/infrared/test_sirc.irtest diff --git a/assets/unit_tests/nfc/Ntag213_locked.nfc b/applications/debug/unit_tests/resources/unit_tests/nfc/Ntag213_locked.nfc similarity index 100% rename from assets/unit_tests/nfc/Ntag213_locked.nfc rename to applications/debug/unit_tests/resources/unit_tests/nfc/Ntag213_locked.nfc diff --git a/assets/unit_tests/nfc/Ntag215.nfc b/applications/debug/unit_tests/resources/unit_tests/nfc/Ntag215.nfc similarity index 100% rename from assets/unit_tests/nfc/Ntag215.nfc rename to applications/debug/unit_tests/resources/unit_tests/nfc/Ntag215.nfc diff --git a/assets/unit_tests/nfc/Ntag216.nfc b/applications/debug/unit_tests/resources/unit_tests/nfc/Ntag216.nfc similarity index 100% rename from assets/unit_tests/nfc/Ntag216.nfc rename to applications/debug/unit_tests/resources/unit_tests/nfc/Ntag216.nfc diff --git a/assets/unit_tests/nfc/Ultralight_11.nfc b/applications/debug/unit_tests/resources/unit_tests/nfc/Ultralight_11.nfc similarity index 100% rename from assets/unit_tests/nfc/Ultralight_11.nfc rename to applications/debug/unit_tests/resources/unit_tests/nfc/Ultralight_11.nfc diff --git a/assets/unit_tests/nfc/Ultralight_21.nfc b/applications/debug/unit_tests/resources/unit_tests/nfc/Ultralight_21.nfc similarity index 100% rename from assets/unit_tests/nfc/Ultralight_21.nfc rename to applications/debug/unit_tests/resources/unit_tests/nfc/Ultralight_21.nfc diff --git a/assets/unit_tests/nfc/nfc_nfca_signal_long.nfc b/applications/debug/unit_tests/resources/unit_tests/nfc/nfc_nfca_signal_long.nfc similarity index 100% rename from assets/unit_tests/nfc/nfc_nfca_signal_long.nfc rename to applications/debug/unit_tests/resources/unit_tests/nfc/nfc_nfca_signal_long.nfc diff --git a/assets/unit_tests/nfc/nfc_nfca_signal_short.nfc b/applications/debug/unit_tests/resources/unit_tests/nfc/nfc_nfca_signal_short.nfc similarity index 100% rename from assets/unit_tests/nfc/nfc_nfca_signal_short.nfc rename to applications/debug/unit_tests/resources/unit_tests/nfc/nfc_nfca_signal_short.nfc diff --git a/assets/unit_tests/storage/md5.txt b/applications/debug/unit_tests/resources/unit_tests/storage/md5.txt similarity index 100% rename from assets/unit_tests/storage/md5.txt rename to applications/debug/unit_tests/resources/unit_tests/storage/md5.txt diff --git a/assets/unit_tests/subghz/alutech_at_4n_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/alutech_at_4n_raw.sub similarity index 100% rename from assets/unit_tests/subghz/alutech_at_4n_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/alutech_at_4n_raw.sub diff --git a/assets/unit_tests/subghz/ansonic.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/ansonic.sub similarity index 100% rename from assets/unit_tests/subghz/ansonic.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/ansonic.sub diff --git a/assets/unit_tests/subghz/ansonic_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/ansonic_raw.sub similarity index 100% rename from assets/unit_tests/subghz/ansonic_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/ansonic_raw.sub diff --git a/assets/unit_tests/subghz/bett.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/bett.sub similarity index 100% rename from assets/unit_tests/subghz/bett.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/bett.sub diff --git a/assets/unit_tests/subghz/bett_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/bett_raw.sub similarity index 100% rename from assets/unit_tests/subghz/bett_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/bett_raw.sub diff --git a/assets/unit_tests/subghz/came.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/came.sub similarity index 100% rename from assets/unit_tests/subghz/came.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/came.sub diff --git a/assets/unit_tests/subghz/came_atomo_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/came_atomo_raw.sub similarity index 100% rename from assets/unit_tests/subghz/came_atomo_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/came_atomo_raw.sub diff --git a/assets/unit_tests/subghz/came_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/came_raw.sub similarity index 100% rename from assets/unit_tests/subghz/came_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/came_raw.sub diff --git a/assets/unit_tests/subghz/came_twee.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/came_twee.sub similarity index 100% rename from assets/unit_tests/subghz/came_twee.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/came_twee.sub diff --git a/assets/unit_tests/subghz/came_twee_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/came_twee_raw.sub similarity index 100% rename from assets/unit_tests/subghz/came_twee_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/came_twee_raw.sub diff --git a/assets/unit_tests/subghz/cenmax_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/cenmax_raw.sub similarity index 100% rename from assets/unit_tests/subghz/cenmax_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/cenmax_raw.sub diff --git a/assets/unit_tests/subghz/clemsa.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/clemsa.sub similarity index 100% rename from assets/unit_tests/subghz/clemsa.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/clemsa.sub diff --git a/assets/unit_tests/subghz/clemsa_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/clemsa_raw.sub similarity index 100% rename from assets/unit_tests/subghz/clemsa_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/clemsa_raw.sub diff --git a/assets/unit_tests/subghz/doitrand.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/doitrand.sub similarity index 100% rename from assets/unit_tests/subghz/doitrand.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/doitrand.sub diff --git a/assets/unit_tests/subghz/doitrand_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/doitrand_raw.sub similarity index 100% rename from assets/unit_tests/subghz/doitrand_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/doitrand_raw.sub diff --git a/assets/unit_tests/subghz/doorhan.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/doorhan.sub similarity index 100% rename from assets/unit_tests/subghz/doorhan.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/doorhan.sub diff --git a/assets/unit_tests/subghz/doorhan_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/doorhan_raw.sub similarity index 100% rename from assets/unit_tests/subghz/doorhan_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/doorhan_raw.sub diff --git a/assets/unit_tests/subghz/dooya.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/dooya.sub similarity index 100% rename from assets/unit_tests/subghz/dooya.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/dooya.sub diff --git a/assets/unit_tests/subghz/dooya_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/dooya_raw.sub similarity index 100% rename from assets/unit_tests/subghz/dooya_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/dooya_raw.sub diff --git a/assets/unit_tests/subghz/faac_slh_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/faac_slh_raw.sub similarity index 100% rename from assets/unit_tests/subghz/faac_slh_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/faac_slh_raw.sub diff --git a/assets/unit_tests/subghz/gate_tx.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/gate_tx.sub similarity index 100% rename from assets/unit_tests/subghz/gate_tx.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/gate_tx.sub diff --git a/assets/unit_tests/subghz/gate_tx_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/gate_tx_raw.sub similarity index 100% rename from assets/unit_tests/subghz/gate_tx_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/gate_tx_raw.sub diff --git a/assets/unit_tests/subghz/holtek.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/holtek.sub similarity index 100% rename from assets/unit_tests/subghz/holtek.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/holtek.sub diff --git a/assets/unit_tests/subghz/holtek_ht12x.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/holtek_ht12x.sub similarity index 100% rename from assets/unit_tests/subghz/holtek_ht12x.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/holtek_ht12x.sub diff --git a/assets/unit_tests/subghz/holtek_ht12x_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/holtek_ht12x_raw.sub similarity index 100% rename from assets/unit_tests/subghz/holtek_ht12x_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/holtek_ht12x_raw.sub diff --git a/assets/unit_tests/subghz/holtek_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/holtek_raw.sub similarity index 100% rename from assets/unit_tests/subghz/holtek_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/holtek_raw.sub diff --git a/assets/unit_tests/subghz/honeywell_wdb.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/honeywell_wdb.sub similarity index 100% rename from assets/unit_tests/subghz/honeywell_wdb.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/honeywell_wdb.sub diff --git a/assets/unit_tests/subghz/honeywell_wdb_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/honeywell_wdb_raw.sub similarity index 100% rename from assets/unit_tests/subghz/honeywell_wdb_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/honeywell_wdb_raw.sub diff --git a/assets/unit_tests/subghz/hormann_hsm_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/hormann_hsm_raw.sub similarity index 100% rename from assets/unit_tests/subghz/hormann_hsm_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/hormann_hsm_raw.sub diff --git a/assets/unit_tests/subghz/ido_117_111_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/ido_117_111_raw.sub similarity index 100% rename from assets/unit_tests/subghz/ido_117_111_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/ido_117_111_raw.sub diff --git a/assets/unit_tests/subghz/intertechno_v3.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/intertechno_v3.sub similarity index 100% rename from assets/unit_tests/subghz/intertechno_v3.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/intertechno_v3.sub diff --git a/assets/unit_tests/subghz/intertechno_v3_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/intertechno_v3_raw.sub similarity index 100% rename from assets/unit_tests/subghz/intertechno_v3_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/intertechno_v3_raw.sub diff --git a/assets/unit_tests/subghz/kia_seed_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/kia_seed_raw.sub similarity index 100% rename from assets/unit_tests/subghz/kia_seed_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/kia_seed_raw.sub diff --git a/assets/unit_tests/subghz/kinggates_stylo4k_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/kinggates_stylo4k_raw.sub similarity index 100% rename from assets/unit_tests/subghz/kinggates_stylo4k_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/kinggates_stylo4k_raw.sub diff --git a/assets/unit_tests/subghz/linear.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/linear.sub similarity index 100% rename from assets/unit_tests/subghz/linear.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/linear.sub diff --git a/assets/unit_tests/subghz/linear_delta3.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/linear_delta3.sub similarity index 100% rename from assets/unit_tests/subghz/linear_delta3.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/linear_delta3.sub diff --git a/assets/unit_tests/subghz/linear_delta3_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/linear_delta3_raw.sub similarity index 100% rename from assets/unit_tests/subghz/linear_delta3_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/linear_delta3_raw.sub diff --git a/assets/unit_tests/subghz/linear_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/linear_raw.sub similarity index 100% rename from assets/unit_tests/subghz/linear_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/linear_raw.sub diff --git a/assets/unit_tests/subghz/magellan.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/magellan.sub similarity index 100% rename from assets/unit_tests/subghz/magellan.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/magellan.sub diff --git a/assets/unit_tests/subghz/magellan_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/magellan_raw.sub similarity index 100% rename from assets/unit_tests/subghz/magellan_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/magellan_raw.sub diff --git a/assets/unit_tests/subghz/marantec.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/marantec.sub similarity index 100% rename from assets/unit_tests/subghz/marantec.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/marantec.sub diff --git a/assets/unit_tests/subghz/marantec_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/marantec_raw.sub similarity index 100% rename from assets/unit_tests/subghz/marantec_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/marantec_raw.sub diff --git a/assets/unit_tests/subghz/megacode.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/megacode.sub similarity index 100% rename from assets/unit_tests/subghz/megacode.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/megacode.sub diff --git a/assets/unit_tests/subghz/megacode_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/megacode_raw.sub similarity index 100% rename from assets/unit_tests/subghz/megacode_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/megacode_raw.sub diff --git a/assets/unit_tests/subghz/nero_radio_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/nero_radio_raw.sub similarity index 100% rename from assets/unit_tests/subghz/nero_radio_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/nero_radio_raw.sub diff --git a/assets/unit_tests/subghz/nero_sketch_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/nero_sketch_raw.sub similarity index 100% rename from assets/unit_tests/subghz/nero_sketch_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/nero_sketch_raw.sub diff --git a/assets/unit_tests/subghz/nice_flo.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/nice_flo.sub similarity index 100% rename from assets/unit_tests/subghz/nice_flo.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/nice_flo.sub diff --git a/assets/unit_tests/subghz/nice_flo_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/nice_flo_raw.sub similarity index 100% rename from assets/unit_tests/subghz/nice_flo_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/nice_flo_raw.sub diff --git a/assets/unit_tests/subghz/nice_flor_s_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/nice_flor_s_raw.sub similarity index 100% rename from assets/unit_tests/subghz/nice_flor_s_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/nice_flor_s_raw.sub diff --git a/assets/unit_tests/subghz/nice_one_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/nice_one_raw.sub similarity index 100% rename from assets/unit_tests/subghz/nice_one_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/nice_one_raw.sub diff --git a/assets/unit_tests/subghz/phoenix_v2.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/phoenix_v2.sub similarity index 100% rename from assets/unit_tests/subghz/phoenix_v2.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/phoenix_v2.sub diff --git a/assets/unit_tests/subghz/phoenix_v2_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/phoenix_v2_raw.sub similarity index 100% rename from assets/unit_tests/subghz/phoenix_v2_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/phoenix_v2_raw.sub diff --git a/assets/unit_tests/subghz/power_smart.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/power_smart.sub similarity index 100% rename from assets/unit_tests/subghz/power_smart.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/power_smart.sub diff --git a/assets/unit_tests/subghz/power_smart_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/power_smart_raw.sub similarity index 100% rename from assets/unit_tests/subghz/power_smart_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/power_smart_raw.sub diff --git a/assets/unit_tests/subghz/princeton.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/princeton.sub similarity index 100% rename from assets/unit_tests/subghz/princeton.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/princeton.sub diff --git a/assets/unit_tests/subghz/princeton_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/princeton_raw.sub similarity index 100% rename from assets/unit_tests/subghz/princeton_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/princeton_raw.sub diff --git a/assets/unit_tests/subghz/scher_khan_magic_code.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/scher_khan_magic_code.sub similarity index 100% rename from assets/unit_tests/subghz/scher_khan_magic_code.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/scher_khan_magic_code.sub diff --git a/assets/unit_tests/subghz/security_pls_1_0.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/security_pls_1_0.sub similarity index 100% rename from assets/unit_tests/subghz/security_pls_1_0.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/security_pls_1_0.sub diff --git a/assets/unit_tests/subghz/security_pls_1_0_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/security_pls_1_0_raw.sub similarity index 100% rename from assets/unit_tests/subghz/security_pls_1_0_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/security_pls_1_0_raw.sub diff --git a/assets/unit_tests/subghz/security_pls_2_0.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/security_pls_2_0.sub similarity index 100% rename from assets/unit_tests/subghz/security_pls_2_0.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/security_pls_2_0.sub diff --git a/assets/unit_tests/subghz/security_pls_2_0_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/security_pls_2_0_raw.sub similarity index 100% rename from assets/unit_tests/subghz/security_pls_2_0_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/security_pls_2_0_raw.sub diff --git a/assets/unit_tests/subghz/smc5326.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/smc5326.sub similarity index 100% rename from assets/unit_tests/subghz/smc5326.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/smc5326.sub diff --git a/assets/unit_tests/subghz/smc5326_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/smc5326_raw.sub similarity index 100% rename from assets/unit_tests/subghz/smc5326_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/smc5326_raw.sub diff --git a/assets/unit_tests/subghz/somfy_keytis_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/somfy_keytis_raw.sub similarity index 100% rename from assets/unit_tests/subghz/somfy_keytis_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/somfy_keytis_raw.sub diff --git a/assets/unit_tests/subghz/somfy_telis_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/somfy_telis_raw.sub similarity index 100% rename from assets/unit_tests/subghz/somfy_telis_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/somfy_telis_raw.sub diff --git a/assets/unit_tests/subghz/test_random_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/test_random_raw.sub similarity index 100% rename from assets/unit_tests/subghz/test_random_raw.sub rename to applications/debug/unit_tests/resources/unit_tests/subghz/test_random_raw.sub diff --git a/applications/main/bad_usb/application.fam b/applications/main/bad_usb/application.fam index 5c42c9fa3f..9844e248df 100644 --- a/applications/main/bad_usb/application.fam +++ b/applications/main/bad_usb/application.fam @@ -6,6 +6,7 @@ App( stack_size=2 * 1024, icon="A_BadUsb_14", order=70, + resources="resources", fap_libs=["assets"], fap_icon="icon.png", fap_category="USB", diff --git a/assets/resources/badusb/Install_qFlipper_macOS.txt b/applications/main/bad_usb/resources/badusb/Install_qFlipper_macOS.txt similarity index 100% rename from assets/resources/badusb/Install_qFlipper_macOS.txt rename to applications/main/bad_usb/resources/badusb/Install_qFlipper_macOS.txt diff --git a/assets/resources/badusb/Install_qFlipper_windows.txt b/applications/main/bad_usb/resources/badusb/Install_qFlipper_windows.txt similarity index 100% rename from assets/resources/badusb/Install_qFlipper_windows.txt rename to applications/main/bad_usb/resources/badusb/Install_qFlipper_windows.txt diff --git a/assets/resources/badusb/assets/layouts/ba-BA.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/ba-BA.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/ba-BA.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/ba-BA.kl diff --git a/assets/resources/badusb/assets/layouts/cz_CS.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/cz_CS.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/cz_CS.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/cz_CS.kl diff --git a/assets/resources/badusb/assets/layouts/da-DA.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/da-DA.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/da-DA.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/da-DA.kl diff --git a/assets/resources/badusb/assets/layouts/de-CH.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/de-CH.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/de-CH.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/de-CH.kl diff --git a/assets/resources/badusb/assets/layouts/de-DE.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/de-DE.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/de-DE.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/de-DE.kl diff --git a/assets/resources/badusb/assets/layouts/dvorak.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/dvorak.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/dvorak.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/dvorak.kl diff --git a/assets/resources/badusb/assets/layouts/en-UK.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/en-UK.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/en-UK.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/en-UK.kl diff --git a/assets/resources/badusb/assets/layouts/en-US.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/en-US.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/en-US.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/en-US.kl diff --git a/assets/resources/badusb/assets/layouts/es-ES.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/es-ES.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/es-ES.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/es-ES.kl diff --git a/assets/resources/badusb/assets/layouts/fr-BE.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/fr-BE.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/fr-BE.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/fr-BE.kl diff --git a/assets/resources/badusb/assets/layouts/fr-CA.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/fr-CA.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/fr-CA.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/fr-CA.kl diff --git a/assets/resources/badusb/assets/layouts/fr-CH.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/fr-CH.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/fr-CH.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/fr-CH.kl diff --git a/assets/resources/badusb/assets/layouts/fr-FR-mac.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/fr-FR-mac.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/fr-FR-mac.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/fr-FR-mac.kl diff --git a/assets/resources/badusb/assets/layouts/fr-FR.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/fr-FR.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/fr-FR.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/fr-FR.kl diff --git a/assets/resources/badusb/assets/layouts/hr-HR.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/hr-HR.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/hr-HR.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/hr-HR.kl diff --git a/assets/resources/badusb/assets/layouts/hu-HU.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/hu-HU.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/hu-HU.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/hu-HU.kl diff --git a/assets/resources/badusb/assets/layouts/it-IT.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/it-IT.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/it-IT.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/it-IT.kl diff --git a/assets/resources/badusb/assets/layouts/nb-NO.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/nb-NO.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/nb-NO.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/nb-NO.kl diff --git a/assets/resources/badusb/assets/layouts/nl-NL.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/nl-NL.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/nl-NL.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/nl-NL.kl diff --git a/assets/resources/badusb/assets/layouts/pt-BR.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/pt-BR.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/pt-BR.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/pt-BR.kl diff --git a/assets/resources/badusb/assets/layouts/pt-PT.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/pt-PT.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/pt-PT.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/pt-PT.kl diff --git a/assets/resources/badusb/assets/layouts/si-SI.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/si-SI.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/si-SI.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/si-SI.kl diff --git a/assets/resources/badusb/assets/layouts/sk-SK.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/sk-SK.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/sk-SK.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/sk-SK.kl diff --git a/assets/resources/badusb/assets/layouts/sv-SE.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/sv-SE.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/sv-SE.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/sv-SE.kl diff --git a/assets/resources/badusb/assets/layouts/tr-TR.kl b/applications/main/bad_usb/resources/badusb/assets/layouts/tr-TR.kl similarity index 100% rename from assets/resources/badusb/assets/layouts/tr-TR.kl rename to applications/main/bad_usb/resources/badusb/assets/layouts/tr-TR.kl diff --git a/assets/resources/badusb/demo_macos.txt b/applications/main/bad_usb/resources/badusb/demo_macos.txt similarity index 100% rename from assets/resources/badusb/demo_macos.txt rename to applications/main/bad_usb/resources/badusb/demo_macos.txt diff --git a/assets/resources/badusb/demo_windows.txt b/applications/main/bad_usb/resources/badusb/demo_windows.txt similarity index 100% rename from assets/resources/badusb/demo_windows.txt rename to applications/main/bad_usb/resources/badusb/demo_windows.txt diff --git a/applications/main/infrared/application.fam b/applications/main/infrared/application.fam index b78b088a72..055d6c3e29 100644 --- a/applications/main/infrared/application.fam +++ b/applications/main/infrared/application.fam @@ -7,6 +7,7 @@ App( icon="A_Infrared_14", stack_size=3 * 1024, order=40, + resources="resources", fap_libs=["assets"], fap_icon="icon.png", fap_category="Infrared", diff --git a/assets/resources/infrared/assets/ac.ir b/applications/main/infrared/resources/infrared/assets/ac.ir similarity index 100% rename from assets/resources/infrared/assets/ac.ir rename to applications/main/infrared/resources/infrared/assets/ac.ir diff --git a/assets/resources/infrared/assets/audio.ir b/applications/main/infrared/resources/infrared/assets/audio.ir similarity index 100% rename from assets/resources/infrared/assets/audio.ir rename to applications/main/infrared/resources/infrared/assets/audio.ir diff --git a/assets/resources/infrared/assets/projector.ir b/applications/main/infrared/resources/infrared/assets/projector.ir similarity index 100% rename from assets/resources/infrared/assets/projector.ir rename to applications/main/infrared/resources/infrared/assets/projector.ir diff --git a/assets/resources/infrared/assets/tv.ir b/applications/main/infrared/resources/infrared/assets/tv.ir similarity index 100% rename from assets/resources/infrared/assets/tv.ir rename to applications/main/infrared/resources/infrared/assets/tv.ir diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 20ebd4ca08..3c8dab2bf1 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -7,6 +7,7 @@ App( icon="A_NFC_14", stack_size=5 * 1024, order=30, + resources="resources", fap_libs=["assets"], fap_icon="icon.png", fap_category="NFC", diff --git a/assets/resources/nfc/assets/aid.nfc b/applications/main/nfc/resources/nfc/assets/aid.nfc similarity index 100% rename from assets/resources/nfc/assets/aid.nfc rename to applications/main/nfc/resources/nfc/assets/aid.nfc diff --git a/assets/resources/nfc/assets/country_code.nfc b/applications/main/nfc/resources/nfc/assets/country_code.nfc similarity index 100% rename from assets/resources/nfc/assets/country_code.nfc rename to applications/main/nfc/resources/nfc/assets/country_code.nfc diff --git a/assets/resources/nfc/assets/currency_code.nfc b/applications/main/nfc/resources/nfc/assets/currency_code.nfc similarity index 100% rename from assets/resources/nfc/assets/currency_code.nfc rename to applications/main/nfc/resources/nfc/assets/currency_code.nfc diff --git a/assets/resources/nfc/assets/mf_classic_dict.nfc b/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc similarity index 100% rename from assets/resources/nfc/assets/mf_classic_dict.nfc rename to applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc diff --git a/applications/main/subghz/application.fam b/applications/main/subghz/application.fam index 4f21cb6c4e..ba9b16abfd 100644 --- a/applications/main/subghz/application.fam +++ b/applications/main/subghz/application.fam @@ -7,6 +7,7 @@ App( icon="A_Sub1ghz_14", stack_size=3 * 1024, order=10, + resources="resources", fap_libs=["assets", "hwdrivers"], fap_icon="icon.png", fap_category="Sub-GHz", diff --git a/assets/resources/subghz/assets/alutech_at_4n b/applications/main/subghz/resources/subghz/assets/alutech_at_4n similarity index 100% rename from assets/resources/subghz/assets/alutech_at_4n rename to applications/main/subghz/resources/subghz/assets/alutech_at_4n diff --git a/assets/resources/subghz/assets/came_atomo b/applications/main/subghz/resources/subghz/assets/came_atomo similarity index 100% rename from assets/resources/subghz/assets/came_atomo rename to applications/main/subghz/resources/subghz/assets/came_atomo diff --git a/assets/resources/subghz/assets/keeloq_mfcodes b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes similarity index 100% rename from assets/resources/subghz/assets/keeloq_mfcodes rename to applications/main/subghz/resources/subghz/assets/keeloq_mfcodes diff --git a/assets/resources/subghz/assets/keeloq_mfcodes_user.example b/applications/main/subghz/resources/subghz/assets/keeloq_mfcodes_user.example similarity index 100% rename from assets/resources/subghz/assets/keeloq_mfcodes_user.example rename to applications/main/subghz/resources/subghz/assets/keeloq_mfcodes_user.example diff --git a/assets/resources/subghz/assets/nice_flor_s b/applications/main/subghz/resources/subghz/assets/nice_flor_s similarity index 100% rename from assets/resources/subghz/assets/nice_flor_s rename to applications/main/subghz/resources/subghz/assets/nice_flor_s diff --git a/assets/resources/subghz/assets/setting_user.example b/applications/main/subghz/resources/subghz/assets/setting_user.example similarity index 100% rename from assets/resources/subghz/assets/setting_user.example rename to applications/main/subghz/resources/subghz/assets/setting_user.example diff --git a/applications/main/u2f/application.fam b/applications/main/u2f/application.fam index 8167e6277b..bf41eb0f7a 100644 --- a/applications/main/u2f/application.fam +++ b/applications/main/u2f/application.fam @@ -6,6 +6,7 @@ App( stack_size=2 * 1024, icon="A_U2F_14", order=80, + resources="resources", fap_libs=["assets"], fap_category="USB", fap_icon="icon.png", diff --git a/assets/resources/u2f/assets/cert.der b/applications/main/u2f/resources/u2f/assets/cert.der similarity index 100% rename from assets/resources/u2f/assets/cert.der rename to applications/main/u2f/resources/u2f/assets/cert.der diff --git a/assets/resources/u2f/assets/cert_key.u2f b/applications/main/u2f/resources/u2f/assets/cert_key.u2f similarity index 100% rename from assets/resources/u2f/assets/cert_key.u2f rename to applications/main/u2f/resources/u2f/assets/cert_key.u2f diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 53f70a1ec6..29ec86ac66 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -179,7 +179,7 @@ static FlipperInternalApplication const* loader_find_application_by_name_in_list const FlipperInternalApplication* list, const uint32_t n_apps) { for(size_t i = 0; i < n_apps; i++) { - if(strcmp(name, list[i].name) == 0) { + if((strcmp(name, list[i].name) == 0) || (strcmp(name, list[i].appid) == 0)) { return &list[i]; } } diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index 3da676e651..cca65628f8 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -29,7 +29,7 @@ typedef struct { /** * @brief Start application * @param[in] instance loader instance - * @param[in] name application name + * @param[in] name application name or id * @param[in] args application arguments * @param[out] error_message detailed error message, can be NULL * @return LoaderStatus @@ -40,7 +40,7 @@ LoaderStatus /** * @brief Start application with GUI error message * @param[in] instance loader instance - * @param[in] name application name + * @param[in] name application name or id * @param[in] args application arguments * @return LoaderStatus */ diff --git a/applications/system/snake_game/application.fam b/applications/system/snake_game/application.fam index 9a99ebac84..9e803f65db 100644 --- a/applications/system/snake_game/application.fam +++ b/applications/system/snake_game/application.fam @@ -5,7 +5,6 @@ App( entry_point="snake_game_app", requires=["gui"], stack_size=1 * 1024, - targets=["f7"], fap_version="1.0", fap_description="Classic Snake Game", fap_icon="snake_10px.png", diff --git a/assets/.gitignore b/assets/.gitignore index a66a6eed4c..ca338d6333 100644 --- a/assets/.gitignore +++ b/assets/.gitignore @@ -1,5 +1 @@ /core2_firmware -/resources/Manifest -/resources/apps/* -/resources/dolphin/* -/resources/apps_data/**/*.fal diff --git a/assets/ReadMe.md b/assets/ReadMe.md index 2d493b4fec..84310e731f 100644 --- a/assets/ReadMe.md +++ b/assets/ReadMe.md @@ -32,10 +32,7 @@ Good starting point: https://docs.unrealengine.com/4.27/en-US/ProductionPipeline Don't include assets that you are not using, compiler is not going to strip unused assets. # Structure -- `compiled` - Output folder made for compiled assets, after building project, in `build` directory. - `dolphin` - Dolphin game assets sources. Goes to `compiled` and `resources` folders in `build` directory. - `icons` - Icons sources. Goes to `compiled` folder in `build` directory. - `protobuf` - Protobuf sources. Goes to `compiled` folder in `build` directory. -- `resources` - Assets that is going to be provisioned to SD card. - `slideshow` - One-time slideshows for desktop -- `unit_tests` - Some pre-defined signals for testing purposes. diff --git a/assets/SConscript b/assets/SConscript index 9bd273626d..c10de78af7 100644 --- a/assets/SConscript +++ b/assets/SConscript @@ -1,16 +1,16 @@ -from fbt.version import get_git_commit_unix_timestamp - Import("env") assetsenv = env.Clone( tools=["fbt_assets"], FW_LIB_NAME="assets", - GIT_UNIX_TIMESTAMP=get_git_commit_unix_timestamp(), + ASSETS_WORK_DIR=env.Dir("compiled"), + ASSETS_SRC_DIR=env.Dir("#/assets"), ) assetsenv.ApplyLibFlags() icons = assetsenv.CompileIcons( - assetsenv.Dir("compiled"), assetsenv.Dir("#/assets/icons") + assetsenv["ASSETS_WORK_DIR"], + assetsenv["ASSETS_SRC_DIR"].Dir("icons"), ) assetsenv.Alias("icons", icons) @@ -18,7 +18,7 @@ assetsenv.Alias("icons", icons) # Protobuf .proto -> .c + .h proto_src = assetsenv.Glob("protobuf/*.proto", source=True) proto_options = assetsenv.Glob("protobuf/*.options", source=True) -proto = assetsenv.ProtoBuilder(assetsenv.Dir("compiled"), proto_src) +proto = assetsenv.ProtoBuilder(assetsenv["ASSETS_WORK_DIR"], proto_src) assetsenv.Depends(proto, proto_options) # Precious(proto) assetsenv.Alias("proto", proto) @@ -27,8 +27,8 @@ assetsenv.Alias("proto", proto) # Internal animations dolphin_internal = assetsenv.DolphinSymBuilder( - assetsenv.Dir("compiled"), - assetsenv.Dir("#/assets/dolphin"), + assetsenv["ASSETS_WORK_DIR"], + assetsenv["ASSETS_SRC_DIR"].Dir("dolphin"), DOLPHIN_RES_TYPE="internal", ) assetsenv.Alias("dolphin_internal", dolphin_internal) @@ -37,8 +37,8 @@ assetsenv.Alias("dolphin_internal", dolphin_internal) # Blocking animations dolphin_blocking = assetsenv.DolphinSymBuilder( - assetsenv.Dir("compiled"), - assetsenv.Dir("#/assets/dolphin"), + assetsenv["ASSETS_WORK_DIR"], + assetsenv["ASSETS_SRC_DIR"].Dir("dolphin"), DOLPHIN_RES_TYPE="blocking", ) assetsenv.Alias("dolphin_blocking", dolphin_blocking) @@ -46,8 +46,8 @@ assetsenv.Alias("dolphin_blocking", dolphin_blocking) # Protobuf version meta proto_ver = assetsenv.ProtoVerBuilder( - "compiled/protobuf_version.h", - "#/assets/protobuf/Changelog", + "${ASSETS_WORK_DIR}/protobuf_version.h", + assetsenv["ASSETS_SRC_DIR"].File("protobuf/Changelog"), ) assetsenv.Depends(proto_ver, proto) assetsenv.Alias("proto_ver", proto_ver) @@ -61,41 +61,19 @@ assetsenv.Install("${LIB_DIST_DIR}", assetslib) # Resources for SD card -env.SetDefault(FW_RESOURCES=None) if assetsenv["IS_BASE_FIRMWARE"]: + dolphin_external_out_dir = assetsenv["ASSETS_WORK_DIR"].Dir("dolphin") # External dolphin animations dolphin_external = assetsenv.DolphinExtBuilder( - assetsenv.Dir("#/assets/resources/dolphin"), - assetsenv.Dir("#/assets/dolphin"), + dolphin_external_out_dir, + assetsenv["ASSETS_SRC_DIR"].Dir("dolphin"), DOLPHIN_RES_TYPE="external", ) if assetsenv["FORCE"]: assetsenv.AlwaysBuild(dolphin_external) assetsenv.Alias("dolphin_ext", dolphin_external) - assetsenv.Clean(dolphin_external, assetsenv.Dir("#/assets/resources/dolphin")) + assetsenv.Clean(dolphin_external, dolphin_external_out_dir) - # Resources manifest - resources = assetsenv.Command( - "#/assets/resources/Manifest", - assetsenv.GlobRecursive( - "*", - assetsenv.Dir("resources").srcnode(), - exclude=["Manifest"], - ), - action=Action( - '${PYTHON3} "${ASSETS_COMPILER}" manifest "${TARGET.dir.posix}" --timestamp=${GIT_UNIX_TIMESTAMP}', - "${RESMANIFESTCOMSTR}", - ), - ) - assetsenv.Precious(resources) - assetsenv.AlwaysBuild(resources) - assetsenv.Clean( - resources, - assetsenv.Dir("#/assets/resources/apps"), - ) - - # Exporting resources node to external environment - env.Replace(FW_RESOURCES=resources) - assetsenv.Alias("resources", resources) + env.Replace(DOLPHIN_EXTERNAL_OUT_DIR=dolphin_external_out_dir) Return("assetslib") diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index 72c15ad48f..0b3217c58c 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -41,6 +41,7 @@ Only two parameters are mandatory: **_appid_** and **_apptype_**. Others are opt - **order**: order of an application within its group when sorting entries in it. The lower the order is, the closer to the start of the list the item is placed. _Used for ordering startup hooks and menu entries._ - **sdk_headers**: list of C header files from this app's code to include in API definitions for external applications. - **targets**: list of strings and target names with which this application is compatible. If not specified, the application is built for all targets. The default value is `["all"]`. +- **resources**: name of a folder within the application's source folder to be used for packacking SD card resources for this application. They will only be used if application is included in build configuration. The default value is `""`, meaning no resources are packaged. #### Parameters for external applications diff --git a/documentation/AppsOnSDCard.md b/documentation/AppsOnSDCard.md index f04793b4f4..3f6d51acf0 100644 --- a/documentation/AppsOnSDCard.md +++ b/documentation/AppsOnSDCard.md @@ -61,7 +61,7 @@ The App Loader allocates memory for the application and copies it to RAM, proces ## API versioning -Not all parts of firmware are available for external applications. A subset of available functions and variables is defined in the "api_symbols.csv" file, which is a part of the firmware target definition in the `firmware/targets/` directory. +Not all parts of firmware are available for external applications. A subset of available functions and variables is defined in the "api_symbols.csv" file, which is a part of the firmware target definition in the `targets/` directory. **`fbt`** uses semantic versioning for the API. The major version is incremented when there are breaking changes in the API. The minor version is incremented when new features are added. diff --git a/documentation/HardwareTargets.md b/documentation/HardwareTargets.md index 0c3474839b..b3213d4f50 100644 --- a/documentation/HardwareTargets.md +++ b/documentation/HardwareTargets.md @@ -2,7 +2,7 @@ Flipper's firmware is modular and supports different hardware configurations in a common code base. It encapsulates hardware-specific differences in `furi_hal`, board initialization code, linker files, SDK data and other information in a _target definition_. -Target-specific files are placed in a single sub-folder in `firmware/targets`. It must contain a target definition file, `target.json`, and may contain other files if they are referenced by current target's definition. By default, `fbt` gathers all source files in target folder, unless they are explicitly excluded. +Target-specific files are placed in a single sub-folder in `targets`. It must contain a target definition file, `target.json`, and may contain other files if they are referenced by current target's definition. By default, `fbt` gathers all source files in target folder, unless they are explicitly excluded. Targets can inherit most code parts from other targets, to reduce common code duplication. diff --git a/documentation/UnitTests.md b/documentation/UnitTests.md index 4717daa8ca..9352917cdc 100644 --- a/documentation/UnitTests.md +++ b/documentation/UnitTests.md @@ -15,10 +15,9 @@ Running existing unit tests is useful to ensure that the new code doesn't introd To run the unit tests, follow these steps: -1. Compile the firmware with the tests enabled: `./fbt FIRMWARE_APP_SET=unit_tests`. -2. Flash the firmware using your preferred method. -3. Copy the [assets/unit_tests](/assets/unit_tests) folder to the root of your Flipper Zero's SD card. -4. Launch the CLI session and run the `unit_tests` command. +1. Compile the firmware with the tests enabled: `./fbt FIRMWARE_APP_SET=unit_tests updater_package`. +2. Flash the firmware using your preferred method, including SD card resources (`build/latest/resources`). +3. Launch the CLI session and run the `unit_tests` command. **NOTE:** To run a particular test (and skip all others), specify its name as the command argument. See [test_index.c](/applications/debug/unit_tests/test_index.c) for the complete list of test names. @@ -33,7 +32,7 @@ The common entry point for all tests is the [unit_tests](/applications/debug/uni #### Test assets -Some unit tests require external data in order to function. These files (commonly called assets) reside in the [assets/unit_tests](/assets/unit_tests) directory in their respective subdirectories. Asset files can be of any type (plain text, FlipperFormat (FFF), binary, etc.). +Some unit tests require external data in order to function. These files (commonly called assets) reside in the [unit_tests](/applications/debug/unit_tests/resources/unit_tests) directory in their respective subdirectories. Asset files can be of any type (plain text, FlipperFormat (FFF), binary, etc.). ### Application-specific @@ -42,10 +41,10 @@ Some unit tests require external data in order to function. These files (commonl Each infrared protocol has a corresponding set of unit tests, so it makes sense to implement one when adding support for a new protocol. To add unit tests for your protocol, follow these steps: -1. Create a file named `test_.irtest` in the [assets](/assets/unit_tests/infrared) directory. +1. Create a file named `test_.irtest` in the [assets](/applications/debug/unit_tests/resources/unit_tests/infrared) directory. 2. Fill it with the test data (more on it below). 3. Add the test code to [infrared_test.c](/applications/debug/unit_tests/infrared/infrared_test.c). -4. Update the [assets](/assets/unit_tests/infrared) on your Flipper Zero and run the tests to see if they pass. +4. Build and install firmware with resources, install it on your Flipper and run the tests to see if they pass. ##### Test data format diff --git a/documentation/UniversalRemotes.md b/documentation/UniversalRemotes.md index 325f640d7e..213709afbf 100644 --- a/documentation/UniversalRemotes.md +++ b/documentation/UniversalRemotes.md @@ -13,7 +13,7 @@ Each signal is recorded using the following algorithm: The signal names are self-explanatory. Remember to make sure that every recorded signal does what it's supposed to. -If everything checks out, append these signals **to the end** of the [TV universal remote file](/assets/resources/infrared/assets/tv.ir). +If everything checks out, append these signals **to the end** of the [TV universal remote file](/applications/main/infrared/resources/infrared/assets/tv.ir). ## Audio players @@ -23,7 +23,7 @@ The signal names are self-explanatory. On many remotes, the `Play` button doubles as `Pause`. In this case, record it as `Play` omitting the `Pause`. Make sure that every signal does what it's supposed to. -If everything checks out, append these signals **to the end** of the [audio player universal remote file](/assets/resources/infrared/assets/audio.ir). +If everything checks out, append these signals **to the end** of the [audio player universal remote file](/applications/main/infrared/resources/infrared/assets/audio.ir). ## Projectors @@ -67,7 +67,7 @@ Finally, record the `Off` signal: The resulting remote file should now contain 6 signals. You can omit any of them, but you then won't be able to use their functionality. Test the file against the actual device. Make sure that every signal does what it's supposed to. -If everything checks out, append these signals **to the end** of the [A/C universal remote file](/assets/resources/infrared/assets/ac.ir). +If everything checks out, append these signals **to the end** of the [A/C universal remote file](/applications/main/infrared/resources/infrared/assets/ac.ir). ## Final steps diff --git a/documentation/file_formats/InfraredFileFormats.md b/documentation/file_formats/InfraredFileFormats.md index c9b6a95365..4d43bd5b8e 100644 --- a/documentation/file_formats/InfraredFileFormats.md +++ b/documentation/file_formats/InfraredFileFormats.md @@ -72,9 +72,9 @@ Known protocols are represented in the `parsed` form, whereas non-recognized sig ### Examples -- [TV Universal Library](/assets/resources/infrared/assets/tv.ir) -- [A/C Universal Library](/assets/resources/infrared/assets/ac.ir) -- [Audio Universal Library](/assets/resources/infrared/assets/audio.ir) +- [TV Universal Library](/applications/main/infrared/resources/infrared/assets/tv.ir) +- [A/C Universal Library](/applications/main/infrared/resources/infrared/assets/ac.ir) +- [Audio Universal Library](/applications/main/infrared/resources/infrared/assets/audio.ir) ### Description @@ -92,7 +92,7 @@ See [Universal Remotes](/documentation/UniversalRemotes.md) for more information ### Examples -See [Infrared Unit Tests](/assets/unit_tests/infrared/) for various examples. +See [Infrared Unit Tests](/applications/debug/unit_tests/resources/unit_tests/infrared/) for various examples. ### Description diff --git a/firmware.scons b/firmware.scons index 82f775d719..e8e50022c7 100644 --- a/firmware.scons +++ b/firmware.scons @@ -1,15 +1,10 @@ -from SCons.Errors import UserError -from SCons.Node import FS - import itertools -from fbt_extra.util import ( - should_gen_cdb_and_link_dir, - link_elf_dir_as_latest, -) - from fbt.sdk.cache import LazySdkVersionLoader - +from fbt.version import get_git_commit_unix_timestamp +from fbt_extra.util import link_elf_dir_as_latest, should_gen_cdb_and_link_dir +from SCons.Errors import UserError +from SCons.Node import FS Import("ENV", "fw_build_meta") @@ -22,12 +17,15 @@ env = ENV.Clone( "pvsstudio", "fbt_hwtarget", "fbt_envhooks", + "fbt_resources", ], COMPILATIONDB_USE_ABSPATH=False, BUILD_DIR=fw_build_meta["build_dir"], IS_BASE_FIRMWARE=fw_build_meta["type"] == "firmware", FW_FLAVOR=fw_build_meta["flavor"], LIB_DIST_DIR=fw_build_meta["build_dir"].Dir("lib"), + RESOURCES_ROOT=fw_build_meta["build_dir"].Dir("resources"), + TARGETS_ROOT=Dir("#/targets"), LINT_SOURCES=[ Dir("applications"), ], @@ -37,7 +35,7 @@ env = ENV.Clone( CPPPATH=[ "#/furi", *(f"#/{app_dir[0]}" for app_dir in ENV["APPDIRS"] if app_dir[1]), - "#/firmware/targets/furi_hal_include", + "#/targets/furi_hal_include", ], # Specific flags for building libraries - always do optimized builds FW_LIB_OPTS={ @@ -104,7 +102,7 @@ lib_targets = env.BuildModules( [ "lib", "assets", - "firmware", + "targets", "furi", ], ) @@ -144,12 +142,26 @@ fwenv.PrepareApplicationsBuild() # Build external apps + configure SDK if env["IS_BASE_FIRMWARE"]: fwenv.SetDefault(FBT_FAP_DEBUG_ELF_ROOT=fwenv["BUILD_DIR"].Dir(".extapps")) - fwenv["FW_EXTAPPS"] = SConscript( + fw_extapps = fwenv["FW_EXTAPPS"] = SConscript( "site_scons/extapps.scons", exports={"ENV": fwenv}, ) - fw_artifacts.append(fwenv["FW_EXTAPPS"].sdk_tree) + fw_artifacts.append(fw_extapps.sdk_tree) + # Resources for SD card + resources = fwenv.ResourcesDist( + _EXTRA_DIST=[fwenv["DOLPHIN_EXTERNAL_OUT_DIR"]], + ) + + manifest = fwenv.ManifestBuilder( + "${RESOURCES_ROOT}/Manifest", + source=resources, + GIT_UNIX_TIMESTAMP=get_git_commit_unix_timestamp(), + ) + fwenv.Replace(FW_RESOURCES_MANIFEST=manifest) + fwenv.Alias("resources", manifest) + + # API getter fwenv.Append(FBT_API_VERSION=LazySdkVersionLoader(fwenv.subst("$SDK_DEFINITION"))) fwenv.PhonyTarget( "get_apiversion", diff --git a/scripts/ReadMe.md b/scripts/ReadMe.md index a9feba11b3..359ce472ae 100644 --- a/scripts/ReadMe.md +++ b/scripts/ReadMe.md @@ -52,10 +52,10 @@ ob.py set # Assets delivery -Run in the root folder of the repo: +Build the firmware and run in the root folder of the repo: ```bash -python scripts/storage.py -p send assets/resources /ext +python scripts/storage.py -p send build/latest/resources /ext ``` diff --git a/scripts/assets.py b/scripts/assets.py index bd8b38ae6d..1099f0c330 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os +import shutil from flipper.app import App from flipper.assets.icon import file2image @@ -220,6 +221,7 @@ class Main(App): if not os.path.isdir(directory_path): self.logger.error(f'"{directory_path}" is not a directory') exit(255) + manifest_file = os.path.join(directory_path, "Manifest") old_manifest = Manifest() if os.path.exists(manifest_file): @@ -234,13 +236,15 @@ class Main(App): self.logger.info("Comparing new manifest with existing") only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest) for record in only_in_old: - self.logger.info(f"Only in old: {record}") + self.logger.debug(f"Only in old: {record}") for record in changed: self.logger.info(f"Changed: {record}") for record in only_in_new: - self.logger.info(f"Only in new: {record}") + self.logger.debug(f"Only in new: {record}") if any((only_in_old, changed, only_in_new)): - self.logger.warning("Manifests are different, updating") + self.logger.info( + f"Manifest updated ({len(only_in_new)} new, {len(only_in_old)} removed, {len(changed)} changed)" + ) new_manifest.save(manifest_file) else: self.logger.info("Manifest is up-to-date!") diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 1a6cae9b17..3a3640d425 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -64,6 +64,7 @@ class FlipperApplication: order: int = 0 sdk_headers: List[str] = field(default_factory=list) targets: List[str] = field(default_factory=lambda: ["all"]) + resources: Optional[str] = None # .fap-specific sources: List[str] = field(default_factory=lambda: ["*.c*"]) @@ -272,11 +273,15 @@ class AppBuildset: self._check_unsatisfied() # unneeded? self._check_target_match() self._group_plugins() - self.apps = sorted( + self._apps = sorted( list(map(self.appmgr.get, self.appnames)), key=lambda app: app.appid, ) + @property + def apps(self): + return list(self._apps) + def _is_missing_dep(self, dep_name: str): return dep_name not in self.appnames @@ -385,13 +390,13 @@ class AppBuildset: def get_apps_cdefs(self): cdefs = set() - for app in self.apps: + for app in self._apps: cdefs.update(app.cdefines) return sorted(list(cdefs)) def get_sdk_headers(self): sdk_headers = [] - for app in self.apps: + for app in self._apps: sdk_headers.extend( [ src._appdir.File(header) @@ -405,14 +410,14 @@ class AppBuildset: return sorted( filter( lambda app: app.apptype == apptype, - self.appmgr.known_apps.values() if all_known else self.apps, + self.appmgr.known_apps.values() if all_known else self._apps, ), key=lambda app: app.order, ) def get_builtin_apps(self): return list( - filter(lambda app: app.apptype in self.BUILTIN_APP_TYPES, self.apps) + filter(lambda app: app.apptype in self.BUILTIN_APP_TYPES, self._apps) ) def get_builtin_app_folders(self): diff --git a/scripts/fbt_tools/fbt_assets.py b/scripts/fbt_tools/fbt_assets.py index d923c328f2..dcf391f2d2 100644 --- a/scripts/fbt_tools/fbt_assets.py +++ b/scripts/fbt_tools/fbt_assets.py @@ -5,9 +5,10 @@ from ansi.color import fg from SCons.Action import Action from SCons.Builder import Builder from SCons.Errors import StopError +from SCons.Node.FS import File -def icons_emitter(target, source, env): +def _icons_emitter(target, source, env): icons_src = env.GlobRecursive("*.png", env["ICON_SRC_DIR"]) icons_src += env.GlobRecursive("**/frame_rate", env["ICON_SRC_DIR"]) @@ -18,7 +19,7 @@ def icons_emitter(target, source, env): return target, icons_src -def proto_emitter(target, source, env): +def _proto_emitter(target, source, env): target = [] for src in source: basename = os.path.splitext(src.name)[0] @@ -27,7 +28,7 @@ def proto_emitter(target, source, env): return target, source -def dolphin_emitter(target, source, env): +def _dolphin_emitter(target, source, env): res_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) source = [res_root_dir] source.extend(env.GlobRecursive("*.*", res_root_dir.srcnode())) @@ -38,16 +39,15 @@ def dolphin_emitter(target, source, env): if env["DOLPHIN_RES_TYPE"] == "external": target = [target_base_dir.File("manifest.txt")] ## A detailed list of files to be generated - ## works better if we just leave target the folder - # target = [] - # target.extend( - # map( - # lambda node: target_base_dir.File( - # res_root_dir.rel_path(node).replace(".png", ".bm") - # ), - # filter(lambda node: isinstance(node, SCons.Node.FS.File), source), - # ) - # ) + # Preserve original paths, do .png -> .bm conversion + target.extend( + map( + lambda node: target_base_dir.File( + res_root_dir.rel_path(node).replace(".png", ".bm") + ), + filter(lambda node: isinstance(node, File), source), + ) + ) else: asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" target = [ @@ -65,7 +65,7 @@ def dolphin_emitter(target, source, env): return target, source -def _invoke_git(args, source_dir): +def __invoke_git(args, source_dir): cmd = ["git"] cmd.extend(args) return ( @@ -75,11 +75,11 @@ def _invoke_git(args, source_dir): ) -def proto_ver_generator(target, source, env): +def _proto_ver_generator(target, source, env): target_file = target[0] src_dir = source[0].dir.abspath try: - _invoke_git( + __invoke_git( ["fetch", "--tags"], source_dir=src_dir, ) @@ -88,7 +88,7 @@ def proto_ver_generator(target, source, env): print(fg.boldred("Git: fetch failed")) try: - git_describe = _invoke_git( + git_describe = __invoke_git( ["describe", "--tags", "--abbrev=0"], source_dir=src_dir, ) @@ -127,7 +127,6 @@ def generate(env): ICONSCOMSTR="\tICONS\t${TARGET}", PROTOCOMSTR="\tPROTO\t${SOURCE}", DOLPHINCOMSTR="\tDOLPHIN\t${DOLPHIN_RES_TYPE}", - RESMANIFESTCOMSTR="\tMANIFEST\t${TARGET}", PBVERCOMSTR="\tPBVER\t${TARGET}", ) @@ -135,37 +134,74 @@ def generate(env): BUILDERS={ "IconBuilder": Builder( action=Action( - '${PYTHON3} ${ASSETS_COMPILER} icons ${ICON_SRC_DIR} ${TARGET.dir} --filename "${ICON_FILE_NAME}"', + [ + [ + "${PYTHON3}", + "${ASSETS_COMPILER}", + "icons", + "${ICON_SRC_DIR}", + "${TARGET.dir}", + "--filename", + "${ICON_FILE_NAME}", + ], + ], "${ICONSCOMSTR}", ), - emitter=icons_emitter, + emitter=_icons_emitter, ), "ProtoBuilder": Builder( action=Action( - "${PYTHON3} ${NANOPB_COMPILER} -q -I${SOURCE.dir.posix} -D${TARGET.dir.posix} ${SOURCES.posix}", + [ + [ + "${PYTHON3}", + "${NANOPB_COMPILER}", + "-q", + "-I${SOURCE.dir.posix}", + "-D${TARGET.dir.posix}", + "${SOURCES.posix}", + ], + ], "${PROTOCOMSTR}", ), - emitter=proto_emitter, + emitter=_proto_emitter, suffix=".pb.c", src_suffix=".proto", ), "DolphinSymBuilder": Builder( action=Action( - "${PYTHON3} ${ASSETS_COMPILER} dolphin -s dolphin_${DOLPHIN_RES_TYPE} ${SOURCE} ${_DOLPHIN_OUT_DIR}", + [ + [ + "${PYTHON3}", + "${ASSETS_COMPILER}", + "dolphin", + "-s", + "dolphin_${DOLPHIN_RES_TYPE}", + "${SOURCE}", + "${_DOLPHIN_OUT_DIR}", + ], + ], "${DOLPHINCOMSTR}", ), - emitter=dolphin_emitter, + emitter=_dolphin_emitter, ), "DolphinExtBuilder": Builder( action=Action( - "${PYTHON3} ${ASSETS_COMPILER} dolphin ${SOURCE} ${_DOLPHIN_OUT_DIR}", + [ + [ + "${PYTHON3}", + "${ASSETS_COMPILER}", + "dolphin", + "${SOURCE}", + "${_DOLPHIN_OUT_DIR}", + ], + ], "${DOLPHINCOMSTR}", ), - emitter=dolphin_emitter, + emitter=_dolphin_emitter, ), "ProtoVerBuilder": Builder( action=Action( - proto_ver_generator, + _proto_ver_generator, "${PBVERCOMSTR}", ), ), diff --git a/scripts/fbt_tools/fbt_dist.py b/scripts/fbt_tools/fbt_dist.py index fdf66c0a71..bf586b8fbb 100644 --- a/scripts/fbt_tools/fbt_dist.py +++ b/scripts/fbt_tools/fbt_dist.py @@ -96,7 +96,21 @@ def DistCommand(env, name, source, **kw): command = env.Command( target, source, - '@${PYTHON3} "${DIST_SCRIPT}" copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}" ${DIST_EXTRA}', + action=Action( + [ + [ + "${PYTHON3}", + "${DIST_SCRIPT}", + "copy", + "-p", + "${DIST_PROJECTS}", + "-s", + "${DIST_SUFFIX}", + "${DIST_EXTRA}", + ] + ], + "${DISTCOMSTR}", + ), **kw, ) env.Pseudo(target) @@ -106,7 +120,10 @@ def DistCommand(env, name, source, **kw): def generate(env): if not env["VERBOSE"]: - env.SetDefault(COPROCOMSTR="\tCOPRO\t${TARGET}") + env.SetDefault( + COPROCOMSTR="\tCOPRO\t${TARGET}", + DISTCOMSTR="\tDIST\t${TARGET}", + ) env.AddMethod(AddFwProject) env.AddMethod(DistCommand) env.AddMethod(AddFwFlashTarget) diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 963429f245..94307539a7 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -1,7 +1,5 @@ import itertools -import os import pathlib -import shutil from dataclasses import dataclass, field from typing import Dict, List, Optional @@ -290,7 +288,7 @@ def prepare_app_metadata(target, source, env): ) -def validate_app_imports(target, source, env): +def _validate_app_imports(target, source, env): sdk_cache = SdkCache(env["SDK_DEFINITION"].path, load_version_only=False) app_syms = set() with open(target[0].path, "rt") as f: @@ -342,35 +340,7 @@ def GetExtAppByIdOrPath(env, app_dir): return app_artifacts -def resources_fap_dist_emitter(target, source, env): - # Initially we have a single target - target dir - # Here we inject pairs of (target, source) for each file - resources_root = target[0] - - target = [] - for app_artifacts in env["EXT_APPS"].values(): - for _, dist_path in filter( - lambda dist_entry: dist_entry[0], app_artifacts.dist_entries - ): - source.append(app_artifacts.compact) - target.append(resources_root.File(dist_path)) - - assert len(target) == len(source) - return (target, source) - - -def resources_fap_dist_action(target, source, env): - # FIXME: find a proper way to remove stale files - target_dir = env.Dir("${RESOURCES_ROOT}/apps") - shutil.rmtree(target_dir.path, ignore_errors=True) - - # Iterate over pairs generated in emitter - for src, target in zip(source, target): - os.makedirs(os.path.dirname(target.path), exist_ok=True) - shutil.copy(src.path, target.path) - - -def embed_app_metadata_emitter(target, source, env): +def _embed_app_metadata_emitter(target, source, env): app = env["APP"] # Hack: change extension for fap libs @@ -407,33 +377,52 @@ def generate_embed_app_metadata_actions(source, target, env, for_signature): Action(prepare_app_metadata, "$APPMETA_COMSTR"), ] - objcopy_str = ( - "${OBJCOPY} " - "--remove-section .ARM.attributes " - "--add-section ${_FAP_META_SECTION}=${APP._section_fapmeta} " - ) + objcopy_args = [ + "${OBJCOPY}", + "--remove-section", + ".ARM.attributes", + "--add-section", + "${_FAP_META_SECTION}=${APP._section_fapmeta}", + "--set-section-flags", + "${_FAP_META_SECTION}=contents,noload,readonly,data", + ] if app._section_fapfileassets: actions.append(Action(prepare_app_file_assets, "$APPFILE_COMSTR")) - objcopy_str += ( - "--add-section ${_FAP_FILEASSETS_SECTION}=${APP._section_fapfileassets} " + objcopy_args.extend( + ( + "--add-section", + "${_FAP_FILEASSETS_SECTION}=${APP._section_fapfileassets}", + "--set-section-flags", + "${_FAP_FILEASSETS_SECTION}=contents,noload,readonly,data", + ) ) - objcopy_str += ( - "--set-section-flags ${_FAP_META_SECTION}=contents,noload,readonly,data " - "--strip-debug --strip-unneeded " - "--add-gnu-debuglink=${SOURCE} " - "${SOURCES} ${TARGET}" + objcopy_args.extend( + ( + "--strip-debug", + "--strip-unneeded", + "--add-gnu-debuglink=${SOURCE}", + "${SOURCES}", + "${TARGET}", + ) ) actions.extend( ( Action( - objcopy_str, + [objcopy_args], "$APPMETAEMBED_COMSTR", ), Action( - "${PYTHON3} ${FBT_SCRIPT_DIR}/fastfap.py ${TARGET} ${OBJCOPY}", + [ + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/fastfap.py", + "${TARGET}", + "${OBJCOPY}", + ] + ], "$FASTFAP_COMSTR", ), ) @@ -511,7 +500,6 @@ def generate(env, **kw): ) if not env["VERBOSE"]: env.SetDefault( - FAPDISTCOMSTR="\tFAPDIST\t${TARGET}", APPMETA_COMSTR="\tAPPMETA\t${TARGET}", APPFILE_COMSTR="\tAPPFILE\t${TARGET}", APPMETAEMBED_COMSTR="\tFAP\t${TARGET}", @@ -534,18 +522,11 @@ def generate(env, **kw): env.Append( BUILDERS={ - "FapDist": Builder( - action=Action( - resources_fap_dist_action, - "$FAPDISTCOMSTR", - ), - emitter=resources_fap_dist_emitter, - ), "EmbedAppMetadata": Builder( generator=generate_embed_app_metadata_actions, suffix=".fap", src_suffix=".elf", - emitter=embed_app_metadata_emitter, + emitter=_embed_app_metadata_emitter, ), "ValidateAppImports": Builder( action=[ @@ -554,7 +535,7 @@ def generate(env, **kw): None, # "$APPDUMP_COMSTR", ), Action( - validate_app_imports, + _validate_app_imports, "$APPCHECK_COMSTR", ), ], diff --git a/scripts/fbt_tools/fbt_hwtarget.py b/scripts/fbt_tools/fbt_hwtarget.py index 1831a6984d..67975ed0f8 100644 --- a/scripts/fbt_tools/fbt_hwtarget.py +++ b/scripts/fbt_tools/fbt_hwtarget.py @@ -2,9 +2,9 @@ import json class HardwareTargetLoader: - def __init__(self, env, target_scons_dir, target_id): + def __init__(self, env, root_target_scons_dir, target_id): self.env = env - self.target_scons_dir = target_scons_dir + self.all_targets_root_dir = root_target_scons_dir self.target_dir = self._getTargetDir(target_id) # self.target_id = target_id self.layered_target_dirs = [] @@ -23,7 +23,7 @@ class HardwareTargetLoader: self._processTargetDefinitions(target_id) def _getTargetDir(self, target_id): - return self.target_scons_dir.Dir(f"f{target_id}") + return self.all_targets_root_dir.Dir(f"f{target_id}") def _loadDescription(self, target_id): target_json_file = self._getTargetDir(target_id).File("target.json") @@ -34,14 +34,14 @@ class HardwareTargetLoader: return vals def _processTargetDefinitions(self, target_id): - self.layered_target_dirs.append(f"targets/f{target_id}") + target_dir = self._getTargetDir(target_id) + self.layered_target_dirs.append(target_dir) config = self._loadDescription(target_id) for path_list in ("include_paths", "sdk_header_paths"): getattr(self, path_list).extend( - f"#/firmware/targets/f{target_id}/{p}" - for p in config.get(path_list, []) + target_dir.Dir(p) for p in config.get(path_list, []) ) self.excluded_sources.extend(config.get("excluded_sources", [])) @@ -50,7 +50,7 @@ class HardwareTargetLoader: file_attrs = ( # (name, use_src_node) - ("startup_script", False), + ("startup_script", True), ("linker_script_flash", True), ("linker_script_ram", True), ("linker_script_app", True), @@ -59,9 +59,10 @@ class HardwareTargetLoader: for attr_name, use_src_node in file_attrs: if (val := config.get(attr_name)) and not getattr(self, attr_name): - node = self.env.File(f"firmware/targets/f{target_id}/{val}") + node = target_dir.File(val) if use_src_node: node = node.srcnode() + # print(f"Got node {node}, {node.path} for {attr_name}") setattr(self, attr_name, node) for attr_name in ("linker_dependencies",): @@ -84,8 +85,8 @@ class HardwareTargetLoader: ) seen_filenames.update(f.name for f in accepted_sources) sources.extend(accepted_sources) - # print(f"Found {len(sources)} sources: {list(f.name for f in sources)}") - return sources + # print(f"Found {len(sources)} sources: {list(f.path for f in sources)}") + return list(f.get_path(self.all_targets_root_dir) for f in sources) def gatherSdkHeaders(self): sdk_headers = [] @@ -101,7 +102,7 @@ class HardwareTargetLoader: def ConfigureForTarget(env, target_id): - target_loader = HardwareTargetLoader(env, env.Dir("#/firmware/targets"), target_id) + target_loader = HardwareTargetLoader(env, env["TARGETS_ROOT"], target_id) env.Replace( TARGET_CFG=target_loader, SDK_DEFINITION=target_loader.sdk_symbols, diff --git a/scripts/fbt_tools/fbt_resources.py b/scripts/fbt_tools/fbt_resources.py new file mode 100644 index 0000000000..47c624081f --- /dev/null +++ b/scripts/fbt_tools/fbt_resources.py @@ -0,0 +1,98 @@ +import os +import shutil + +from SCons.Action import Action +from SCons.Builder import Builder +from SCons.Errors import StopError +from SCons.Node.FS import Dir, File + + +def _resources_dist_emitter(target, source, env): + resources_root = env.Dir(env["RESOURCES_ROOT"]) + + target = [] + for app_artifacts in env["FW_EXTAPPS"].application_map.values(): + for _, dist_path in filter( + lambda dist_entry: dist_entry[0], app_artifacts.dist_entries + ): + source.append(app_artifacts.compact) + target.append(resources_root.File(dist_path)) + + # Deploy apps' resources too + for app in env["APPBUILD"].apps: + if not app.resources: + continue + apps_resource_dir = app._appdir.Dir(app.resources) + for res_file in env.GlobRecursive("*", apps_resource_dir): + if not isinstance(res_file, File): + continue + source.append(res_file) + target.append(resources_root.File(res_file.get_path(apps_resource_dir))) + + # Deploy other stuff from _EXTRA_DIST + for extra_dist in env["_EXTRA_DIST"]: + if isinstance(extra_dist, Dir): + for extra_file in env.GlobRecursive("*", extra_dist): + if not isinstance(extra_file, File): + continue + source.append(extra_file) + target.append( + # Preserve dir name from original node + resources_root.Dir(extra_dist.name).File( + extra_file.get_path(extra_dist) + ) + ) + else: + raise StopError(f"Unsupported extra dist type: {type(extra_dist)}") + + assert len(target) == len(source) + return (target, source) + + +def _resources_dist_action(target, source, env): + shutil.rmtree(env.Dir(env["RESOURCES_ROOT"]).abspath, ignore_errors=True) + for src, target in zip(source, target): + os.makedirs(os.path.dirname(target.path), exist_ok=True) + shutil.copy(src.path, target.path) + + +def generate(env, **kw): + env.SetDefault( + ASSETS_COMPILER="${FBT_SCRIPT_DIR}/assets.py", + ) + + if not env["VERBOSE"]: + env.SetDefault( + RESOURCEDISTCOMSTR="\tRESDIST\t${RESOURCES_ROOT}", + RESMANIFESTCOMSTR="\tMANIFST\t${TARGET}", + ) + + env.Append( + BUILDERS={ + "ResourcesDist": Builder( + action=Action( + _resources_dist_action, + "${RESOURCEDISTCOMSTR}", + ), + emitter=_resources_dist_emitter, + ), + "ManifestBuilder": Builder( + action=Action( + [ + [ + "${PYTHON3}", + "${ASSETS_COMPILER}", + "manifest", + "${TARGET.dir.posix}", + "--timestamp=${GIT_UNIX_TIMESTAMP}", + ] + ], + "${RESMANIFESTCOMSTR}", + ) + ), + } + ) + + +def exists(env): + return True diff --git a/scripts/fbt_tools/fbt_sdk.py b/scripts/fbt_tools/fbt_sdk.py index 2f7d62388d..6350f14b8b 100644 --- a/scripts/fbt_tools/fbt_sdk.py +++ b/scripts/fbt_tools/fbt_sdk.py @@ -37,13 +37,13 @@ def ProcessSdkDepends(env, filename): return depends -def api_amalgam_emitter(target, source, env): +def _api_amalgam_emitter(target, source, env): target.append(env.ChangeFileExtension(target[0], ".d")) target.append(env.ChangeFileExtension(target[0], ".i.c")) return target, source -def api_amalgam_gen_origin_header(target, source, env): +def _api_amalgam_gen_origin_header(target, source, env): mega_file = env.subst("${TARGET}.c", target=target[0]) with open(mega_file, "wt") as sdk_c: sdk_c.write( @@ -183,12 +183,12 @@ class SdkTreeBuilder: self._generate_sdk_meta() -def deploy_sdk_header_tree_action(target, source, env): +def _deploy_sdk_header_tree_action(target, source, env): sdk_tree = SdkTreeBuilder(env, target, source) return sdk_tree.deploy_action() -def deploy_sdk_header_tree_emitter(target, source, env): +def _deploy_sdk_header_tree_emitter(target, source, env): sdk_tree = SdkTreeBuilder(env, target, source) return sdk_tree.emitter(target, source, env) @@ -227,7 +227,7 @@ def _check_sdk_is_up2date(sdk_cache: SdkCache): ) -def validate_api_cache(source, target, env): +def _validate_api_cache(source, target, env): # print(f"Generating SDK for {source[0]} to {target[0]}") current_sdk = SdkCollector() current_sdk.process_source_file_for_sdk(source[0].path) @@ -240,7 +240,7 @@ def validate_api_cache(source, target, env): _check_sdk_is_up2date(sdk_cache) -def generate_api_table(source, target, env): +def _generate_api_table(source, target, env): sdk_cache = SdkCache(source[0].path) _check_sdk_is_up2date(sdk_cache) @@ -278,10 +278,10 @@ def generate(env, **kw): env.Append( BUILDERS={ "ApiAmalgamator": Builder( - emitter=api_amalgam_emitter, + emitter=_api_amalgam_emitter, action=[ Action( - api_amalgam_gen_origin_header, + _api_amalgam_gen_origin_header, "$SDK_AMALGAMATE_HEADER_COMSTR", ), Action( @@ -293,15 +293,15 @@ def generate(env, **kw): ), "SDKHeaderTreeExtractor": Builder( action=Action( - deploy_sdk_header_tree_action, + _deploy_sdk_header_tree_action, "$SDKTREE_COMSTR", ), - emitter=deploy_sdk_header_tree_emitter, + emitter=_deploy_sdk_header_tree_emitter, src_suffix=".d", ), "ApiTableValidator": Builder( action=Action( - validate_api_cache, + _validate_api_cache, "$SDKSYM_UPDATER_COMSTR", ), suffix=".csv", @@ -309,7 +309,7 @@ def generate(env, **kw): ), "ApiSymbolTable": Builder( action=Action( - generate_api_table, + _generate_api_table, "$APITABLE_GENERATOR_COMSTR", ), suffix=".h", diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index aead13b29f..f1a782523f 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -2,7 +2,7 @@ from SCons.Action import Action from SCons.Builder import Builder -def version_emitter(target, source, env): +def _version_emitter(target, source, env): target_dir = target[0] target = [ target_dir.File("version.inc.h"), @@ -24,7 +24,7 @@ def generate(env): '-o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', "${VERSIONCOMSTR}", ), - emitter=version_emitter, + emitter=_version_emitter, ), } ) diff --git a/scripts/fbt_tools/pvsstudio.py b/scripts/fbt_tools/pvsstudio.py index 211f46aee8..f43db126e3 100644 --- a/scripts/fbt_tools/pvsstudio.py +++ b/scripts/fbt_tools/pvsstudio.py @@ -17,7 +17,7 @@ def _set_browser_action(target, source, env): __no_browser = True -def emit_pvsreport(target, source, env): +def _emit_pvsreport(target, source, env): target_dir = env["REPORT_DIR"] if env["PLATFORM"] == "win32": # Report generator on Windows emits to a subfolder of given output folder @@ -96,7 +96,7 @@ def generate(env): ], "${PVSCONVCOMSTR}", ), - emitter=emit_pvsreport, + emitter=_emit_pvsreport, src_suffix=".log", ), } diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index e9089a1b99..cf98c8253c 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -55,7 +55,7 @@ class DolphinBubbleAnimation: if not os.path.isfile(meta_filename): raise Exception(f"Animation meta file doesn't exist: { meta_filename }") - self.logger.info(f"Loading meta from {meta_filename}") + self.logger.debug(f"Loading meta from {meta_filename}") file = FlipperFormatFile() file.load(meta_filename) diff --git a/scripts/meta.py b/scripts/meta.py deleted file mode 100755 index f47ef65fb0..0000000000 --- a/scripts/meta.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 - -import json - -from flipper.app import App - - -class Main(App): - def init(self): - self.subparsers = self.parser.add_subparsers(help="sub-command help") - - # generate - self.parser_generate = self.subparsers.add_parser( - "generate", help="Generate JSON meta file" - ) - self.parser_generate.add_argument("-p", dest="project", required=True) - self.parser_generate.add_argument( - "-DBUILD_DATE", dest="build_date", required=True - ) - self.parser_generate.add_argument("-DGIT_COMMIT", dest="commit", required=True) - self.parser_generate.add_argument("-DGIT_BRANCH", dest="branch", required=True) - self.parser_generate.add_argument( - "-DTARGET", dest="target", type=int, required=True - ) - self.parser_generate.set_defaults(func=self.generate) - - # merge - self.parser_merge = self.subparsers.add_parser( - "merge", help="Merge JSON meta files" - ) - self.parser_merge.add_argument( - "-i", dest="input", action="append", nargs="+", required=True - ) - self.parser_merge.set_defaults(func=self.merge) - - def generate(self): - meta = {} - for k, v in vars(self.args).items(): - if k in ["project", "func", "debug"]: - continue - if isinstance(v, str): - v = v.strip('"') - meta[self.args.project + "_" + k] = v - - print(json.dumps(meta, indent=4)) - return 0 - - def merge(self): - full = {} - for path in self.args.input[0]: - with open(path, mode="r") as file: - dict = json.loads(file.read()) - full.update(dict) - - print(json.dumps(full, indent=4)) - return 0 - - -if __name__ == "__main__": - Main()() diff --git a/scripts/ufbt/project_template/app_template/.github/workflows/build.yml b/scripts/ufbt/project_template/app_template/.github/workflows/build.yml index c11ffc180f..143847c4a2 100644 --- a/scripts/ufbt/project_template/app_template/.github/workflows/build.yml +++ b/scripts/ufbt/project_template/app_template/.github/workflows/build.yml @@ -27,9 +27,9 @@ jobs: name: 'ufbt: Build for ${{ matrix.name }}' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build with ufbt - uses: flipperdevices/flipperzero-ufbt-action@v0.1.1 + uses: flipperdevices/flipperzero-ufbt-action@v0.1 id: build-app with: sdk-channel: ${{ matrix.sdk-channel }} diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons index f9227ed37b..769b3eb154 100644 --- a/site_scons/extapps.scons +++ b/site_scons/extapps.scons @@ -14,7 +14,6 @@ appenv = ENV["APPENV"] = ENV.Clone( "fbt_assets", "fbt_sdk", ], - RESOURCES_ROOT=ENV.Dir("#/assets/resources"), ) appenv.Replace( @@ -56,7 +55,6 @@ appenv.AppendUnique( @dataclass class FlipperExtAppBuildArtifacts: application_map: dict = field(default_factory=dict) - resources_dist: NodeList = field(default_factory=NodeList) sdk_tree: NodeList = field(default_factory=NodeList) @@ -78,8 +76,6 @@ Alias( list(app_artifact.validator for app_artifact in extapps.application_map.values()), ) -extapps.resources_dist = appenv.FapDist(appenv["RESOURCES_ROOT"], []) - if appsrc := appenv.subst("$APPSRC"): launch_target = appenv.AddAppLaunchTarget(appsrc, "launch") diff --git a/firmware/ReadMe.md b/targets/ReadMe.md similarity index 100% rename from firmware/ReadMe.md rename to targets/ReadMe.md diff --git a/firmware/SConscript b/targets/SConscript similarity index 100% rename from firmware/SConscript rename to targets/SConscript diff --git a/firmware/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv similarity index 98% rename from firmware/targets/f18/api_symbols.csv rename to targets/f18/api_symbols.csv index 4789d316d6..b4efd7911b 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -36,51 +36,6 @@ Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/storage/storage.h,, -Header,+,firmware/targets/f18/furi_hal/furi_hal_resources.h,, -Header,+,firmware/targets/f18/furi_hal/furi_hal_spi_config.h,, -Header,+,firmware/targets/f18/furi_hal/furi_hal_target_hw.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_bus.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_clock.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_console.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_dma.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_flash.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_gpio.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_config.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_types.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_types.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_uart.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h,, -Header,+,firmware/targets/f7/platform_specific/intrinsic_export.h,, -Header,+,firmware/targets/f7/platform_specific/math_wrapper.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_bt_hid.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_bt_serial.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_cortex.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_crypto.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_debug.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_i2c.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_info.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_light.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_memory.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_mpu.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_power.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_random.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_region.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_rtc.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_sd.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_speaker.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_spi.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_usb.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_usb_ccid.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_vibro.h,, Header,+,lib/digital_signal/digital_sequence.h,, Header,+,lib/digital_signal/digital_signal.h,, Header,+,lib/drivers/cc1101_regs.h,, @@ -194,6 +149,51 @@ Header,+,lib/toolbox/stream/string_stream.h,, Header,+,lib/toolbox/tar/tar_archive.h,, Header,+,lib/toolbox/value_index.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,, +Header,+,targets/f18/furi_hal/furi_hal_target_hw.h,, +Header,+,targets/f7/furi_hal/furi_hal_bus.h,, +Header,+,targets/f7/furi_hal/furi_hal_clock.h,, +Header,+,targets/f7/furi_hal/furi_hal_console.h,, +Header,+,targets/f7/furi_hal/furi_hal_dma.h,, +Header,+,targets/f7/furi_hal/furi_hal_flash.h,, +Header,+,targets/f7/furi_hal/furi_hal_gpio.h,, +Header,+,targets/f7/furi_hal/furi_hal_i2c_config.h,, +Header,+,targets/f7/furi_hal/furi_hal_i2c_types.h,, +Header,+,targets/f7/furi_hal/furi_hal_idle_timer.h,, +Header,+,targets/f7/furi_hal/furi_hal_interrupt.h,, +Header,+,targets/f7/furi_hal/furi_hal_os.h,, +Header,+,targets/f7/furi_hal/furi_hal_pwm.h,, +Header,+,targets/f7/furi_hal/furi_hal_spi_types.h,, +Header,+,targets/f7/furi_hal/furi_hal_uart.h,, +Header,+,targets/f7/furi_hal/furi_hal_usb_cdc.h,, +Header,+,targets/f7/platform_specific/intrinsic_export.h,, +Header,+,targets/f7/platform_specific/math_wrapper.h,, +Header,+,targets/furi_hal_include/furi_hal.h,, +Header,+,targets/furi_hal_include/furi_hal_bt.h,, +Header,+,targets/furi_hal_include/furi_hal_bt_hid.h,, +Header,+,targets/furi_hal_include/furi_hal_bt_serial.h,, +Header,+,targets/furi_hal_include/furi_hal_cortex.h,, +Header,+,targets/furi_hal_include/furi_hal_crypto.h,, +Header,+,targets/furi_hal_include/furi_hal_debug.h,, +Header,+,targets/furi_hal_include/furi_hal_i2c.h,, +Header,+,targets/furi_hal_include/furi_hal_info.h,, +Header,+,targets/furi_hal_include/furi_hal_light.h,, +Header,+,targets/furi_hal_include/furi_hal_memory.h,, +Header,+,targets/furi_hal_include/furi_hal_mpu.h,, +Header,+,targets/furi_hal_include/furi_hal_power.h,, +Header,+,targets/furi_hal_include/furi_hal_random.h,, +Header,+,targets/furi_hal_include/furi_hal_region.h,, +Header,+,targets/furi_hal_include/furi_hal_rtc.h,, +Header,+,targets/furi_hal_include/furi_hal_sd.h,, +Header,+,targets/furi_hal_include/furi_hal_speaker.h,, +Header,+,targets/furi_hal_include/furi_hal_spi.h,, +Header,+,targets/furi_hal_include/furi_hal_usb.h,, +Header,+,targets/furi_hal_include/furi_hal_usb_ccid.h,, +Header,+,targets/furi_hal_include/furi_hal_usb_hid.h,, +Header,+,targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, +Header,+,targets/furi_hal_include/furi_hal_version.h,, +Header,+,targets/furi_hal_include/furi_hal_vibro.h,, Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, const LL_ADC_CommonInitTypeDef*" Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* diff --git a/firmware/targets/f18/furi_hal/furi_hal.c b/targets/f18/furi_hal/furi_hal.c similarity index 100% rename from firmware/targets/f18/furi_hal/furi_hal.c rename to targets/f18/furi_hal/furi_hal.c diff --git a/firmware/targets/f18/furi_hal/furi_hal_power_config.c b/targets/f18/furi_hal/furi_hal_power_config.c similarity index 100% rename from firmware/targets/f18/furi_hal/furi_hal_power_config.c rename to targets/f18/furi_hal/furi_hal_power_config.c diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.c b/targets/f18/furi_hal/furi_hal_resources.c similarity index 100% rename from firmware/targets/f18/furi_hal/furi_hal_resources.c rename to targets/f18/furi_hal/furi_hal_resources.c diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.h b/targets/f18/furi_hal/furi_hal_resources.h similarity index 100% rename from firmware/targets/f18/furi_hal/furi_hal_resources.h rename to targets/f18/furi_hal/furi_hal_resources.h diff --git a/firmware/targets/f18/furi_hal/furi_hal_spi_config.c b/targets/f18/furi_hal/furi_hal_spi_config.c similarity index 100% rename from firmware/targets/f18/furi_hal/furi_hal_spi_config.c rename to targets/f18/furi_hal/furi_hal_spi_config.c diff --git a/firmware/targets/f18/furi_hal/furi_hal_spi_config.h b/targets/f18/furi_hal/furi_hal_spi_config.h similarity index 100% rename from firmware/targets/f18/furi_hal/furi_hal_spi_config.h rename to targets/f18/furi_hal/furi_hal_spi_config.h diff --git a/firmware/targets/f18/furi_hal/furi_hal_target_hw.h b/targets/f18/furi_hal/furi_hal_target_hw.h similarity index 100% rename from firmware/targets/f18/furi_hal/furi_hal_target_hw.h rename to targets/f18/furi_hal/furi_hal_target_hw.h diff --git a/firmware/targets/f18/furi_hal/furi_hal_version_device.c b/targets/f18/furi_hal/furi_hal_version_device.c similarity index 100% rename from firmware/targets/f18/furi_hal/furi_hal_version_device.c rename to targets/f18/furi_hal/furi_hal_version_device.c diff --git a/firmware/targets/f18/target.json b/targets/f18/target.json similarity index 100% rename from firmware/targets/f18/target.json rename to targets/f18/target.json diff --git a/firmware/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv similarity index 98% rename from firmware/targets/f7/api_symbols.csv rename to targets/f7/api_symbols.csv index 038a22eae4..7599230d72 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -37,56 +37,6 @@ Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/storage/storage.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_bus.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_clock.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_console.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_dma.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_flash.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_gpio.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_config.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_types.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_ibutton.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_idle_timer.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_interrupt.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_os.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_pwm.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_resources.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_rfid.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_config.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_spi_types.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_subghz.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_target_hw.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_uart.h,, -Header,+,firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h,, -Header,+,firmware/targets/f7/platform_specific/intrinsic_export.h,, -Header,+,firmware/targets/f7/platform_specific/math_wrapper.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_bt.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_bt_hid.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_bt_serial.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_cortex.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_crypto.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_debug.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_i2c.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_info.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_infrared.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_light.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_memory.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_mpu.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_nfc.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_power.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_random.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_region.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_rtc.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_sd.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_speaker.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_spi.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_usb.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_usb_ccid.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_version.h,, -Header,+,firmware/targets/furi_hal_include/furi_hal_vibro.h,, Header,+,lib/digital_signal/digital_sequence.h,, Header,+,lib/digital_signal/digital_signal.h,, Header,+,lib/drivers/cc1101_regs.h,, @@ -262,6 +212,56 @@ Header,+,lib/toolbox/stream/string_stream.h,, Header,+,lib/toolbox/tar/tar_archive.h,, Header,+,lib/toolbox/value_index.h,, Header,+,lib/toolbox/version.h,, +Header,+,targets/f7/furi_hal/furi_hal_bus.h,, +Header,+,targets/f7/furi_hal/furi_hal_clock.h,, +Header,+,targets/f7/furi_hal/furi_hal_console.h,, +Header,+,targets/f7/furi_hal/furi_hal_dma.h,, +Header,+,targets/f7/furi_hal/furi_hal_flash.h,, +Header,+,targets/f7/furi_hal/furi_hal_gpio.h,, +Header,+,targets/f7/furi_hal/furi_hal_i2c_config.h,, +Header,+,targets/f7/furi_hal/furi_hal_i2c_types.h,, +Header,+,targets/f7/furi_hal/furi_hal_ibutton.h,, +Header,+,targets/f7/furi_hal/furi_hal_idle_timer.h,, +Header,+,targets/f7/furi_hal/furi_hal_interrupt.h,, +Header,+,targets/f7/furi_hal/furi_hal_os.h,, +Header,+,targets/f7/furi_hal/furi_hal_pwm.h,, +Header,+,targets/f7/furi_hal/furi_hal_resources.h,, +Header,+,targets/f7/furi_hal/furi_hal_rfid.h,, +Header,+,targets/f7/furi_hal/furi_hal_spi_config.h,, +Header,+,targets/f7/furi_hal/furi_hal_spi_types.h,, +Header,+,targets/f7/furi_hal/furi_hal_subghz.h,, +Header,+,targets/f7/furi_hal/furi_hal_target_hw.h,, +Header,+,targets/f7/furi_hal/furi_hal_uart.h,, +Header,+,targets/f7/furi_hal/furi_hal_usb_cdc.h,, +Header,+,targets/f7/platform_specific/intrinsic_export.h,, +Header,+,targets/f7/platform_specific/math_wrapper.h,, +Header,+,targets/furi_hal_include/furi_hal.h,, +Header,+,targets/furi_hal_include/furi_hal_bt.h,, +Header,+,targets/furi_hal_include/furi_hal_bt_hid.h,, +Header,+,targets/furi_hal_include/furi_hal_bt_serial.h,, +Header,+,targets/furi_hal_include/furi_hal_cortex.h,, +Header,+,targets/furi_hal_include/furi_hal_crypto.h,, +Header,+,targets/furi_hal_include/furi_hal_debug.h,, +Header,+,targets/furi_hal_include/furi_hal_i2c.h,, +Header,+,targets/furi_hal_include/furi_hal_info.h,, +Header,+,targets/furi_hal_include/furi_hal_infrared.h,, +Header,+,targets/furi_hal_include/furi_hal_light.h,, +Header,+,targets/furi_hal_include/furi_hal_memory.h,, +Header,+,targets/furi_hal_include/furi_hal_mpu.h,, +Header,+,targets/furi_hal_include/furi_hal_nfc.h,, +Header,+,targets/furi_hal_include/furi_hal_power.h,, +Header,+,targets/furi_hal_include/furi_hal_random.h,, +Header,+,targets/furi_hal_include/furi_hal_region.h,, +Header,+,targets/furi_hal_include/furi_hal_rtc.h,, +Header,+,targets/furi_hal_include/furi_hal_sd.h,, +Header,+,targets/furi_hal_include/furi_hal_speaker.h,, +Header,+,targets/furi_hal_include/furi_hal_spi.h,, +Header,+,targets/furi_hal_include/furi_hal_usb.h,, +Header,+,targets/furi_hal_include/furi_hal_usb_ccid.h,, +Header,+,targets/furi_hal_include/furi_hal_usb_hid.h,, +Header,+,targets/furi_hal_include/furi_hal_usb_hid_u2f.h,, +Header,+,targets/furi_hal_include/furi_hal_version.h,, +Header,+,targets/furi_hal_include/furi_hal_vibro.h,, Function,-,LL_ADC_CommonDeInit,ErrorStatus,ADC_Common_TypeDef* Function,-,LL_ADC_CommonInit,ErrorStatus,"ADC_Common_TypeDef*, const LL_ADC_CommonInitTypeDef*" Function,-,LL_ADC_CommonStructInit,void,LL_ADC_CommonInitTypeDef* diff --git a/firmware/targets/f7/application_ext.ld b/targets/f7/application_ext.ld similarity index 100% rename from firmware/targets/f7/application_ext.ld rename to targets/f7/application_ext.ld diff --git a/firmware/targets/f7/ble_glue/app_common.h b/targets/f7/ble_glue/app_common.h similarity index 100% rename from firmware/targets/f7/ble_glue/app_common.h rename to targets/f7/ble_glue/app_common.h diff --git a/firmware/targets/f7/ble_glue/app_conf.h b/targets/f7/ble_glue/app_conf.h similarity index 100% rename from firmware/targets/f7/ble_glue/app_conf.h rename to targets/f7/ble_glue/app_conf.h diff --git a/firmware/targets/f7/ble_glue/app_debug.c b/targets/f7/ble_glue/app_debug.c similarity index 100% rename from firmware/targets/f7/ble_glue/app_debug.c rename to targets/f7/ble_glue/app_debug.c diff --git a/firmware/targets/f7/ble_glue/app_debug.h b/targets/f7/ble_glue/app_debug.h similarity index 100% rename from firmware/targets/f7/ble_glue/app_debug.h rename to targets/f7/ble_glue/app_debug.h diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/targets/f7/ble_glue/ble_app.c similarity index 100% rename from firmware/targets/f7/ble_glue/ble_app.c rename to targets/f7/ble_glue/ble_app.c diff --git a/firmware/targets/f7/ble_glue/ble_app.h b/targets/f7/ble_glue/ble_app.h similarity index 100% rename from firmware/targets/f7/ble_glue/ble_app.h rename to targets/f7/ble_glue/ble_app.h diff --git a/firmware/targets/f7/ble_glue/ble_conf.h b/targets/f7/ble_glue/ble_conf.h similarity index 100% rename from firmware/targets/f7/ble_glue/ble_conf.h rename to targets/f7/ble_glue/ble_conf.h diff --git a/firmware/targets/f7/ble_glue/ble_const.h b/targets/f7/ble_glue/ble_const.h similarity index 100% rename from firmware/targets/f7/ble_glue/ble_const.h rename to targets/f7/ble_glue/ble_const.h diff --git a/firmware/targets/f7/ble_glue/ble_dbg_conf.h b/targets/f7/ble_glue/ble_dbg_conf.h similarity index 100% rename from firmware/targets/f7/ble_glue/ble_dbg_conf.h rename to targets/f7/ble_glue/ble_dbg_conf.h diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/targets/f7/ble_glue/ble_glue.c similarity index 100% rename from firmware/targets/f7/ble_glue/ble_glue.c rename to targets/f7/ble_glue/ble_glue.c diff --git a/firmware/targets/f7/ble_glue/ble_glue.h b/targets/f7/ble_glue/ble_glue.h similarity index 100% rename from firmware/targets/f7/ble_glue/ble_glue.h rename to targets/f7/ble_glue/ble_glue.h diff --git a/firmware/targets/f7/ble_glue/compiler.h b/targets/f7/ble_glue/compiler.h similarity index 100% rename from firmware/targets/f7/ble_glue/compiler.h rename to targets/f7/ble_glue/compiler.h diff --git a/firmware/targets/f7/ble_glue/gap.c b/targets/f7/ble_glue/gap.c similarity index 100% rename from firmware/targets/f7/ble_glue/gap.c rename to targets/f7/ble_glue/gap.c diff --git a/firmware/targets/f7/ble_glue/gap.h b/targets/f7/ble_glue/gap.h similarity index 100% rename from firmware/targets/f7/ble_glue/gap.h rename to targets/f7/ble_glue/gap.h diff --git a/firmware/targets/f7/ble_glue/hsem_map.h b/targets/f7/ble_glue/hsem_map.h similarity index 100% rename from firmware/targets/f7/ble_glue/hsem_map.h rename to targets/f7/ble_glue/hsem_map.h diff --git a/firmware/targets/f7/ble_glue/hw_ipcc.c b/targets/f7/ble_glue/hw_ipcc.c similarity index 100% rename from firmware/targets/f7/ble_glue/hw_ipcc.c rename to targets/f7/ble_glue/hw_ipcc.c diff --git a/firmware/targets/f7/ble_glue/osal.h b/targets/f7/ble_glue/osal.h similarity index 100% rename from firmware/targets/f7/ble_glue/osal.h rename to targets/f7/ble_glue/osal.h diff --git a/firmware/targets/f7/ble_glue/services/battery_service.c b/targets/f7/ble_glue/services/battery_service.c similarity index 100% rename from firmware/targets/f7/ble_glue/services/battery_service.c rename to targets/f7/ble_glue/services/battery_service.c diff --git a/firmware/targets/f7/ble_glue/services/battery_service.h b/targets/f7/ble_glue/services/battery_service.h similarity index 100% rename from firmware/targets/f7/ble_glue/services/battery_service.h rename to targets/f7/ble_glue/services/battery_service.h diff --git a/firmware/targets/f7/ble_glue/services/dev_info_service.c b/targets/f7/ble_glue/services/dev_info_service.c similarity index 100% rename from firmware/targets/f7/ble_glue/services/dev_info_service.c rename to targets/f7/ble_glue/services/dev_info_service.c diff --git a/firmware/targets/f7/ble_glue/services/dev_info_service.h b/targets/f7/ble_glue/services/dev_info_service.h similarity index 100% rename from firmware/targets/f7/ble_glue/services/dev_info_service.h rename to targets/f7/ble_glue/services/dev_info_service.h diff --git a/firmware/targets/f7/ble_glue/services/dev_info_service_uuid.inc b/targets/f7/ble_glue/services/dev_info_service_uuid.inc similarity index 100% rename from firmware/targets/f7/ble_glue/services/dev_info_service_uuid.inc rename to targets/f7/ble_glue/services/dev_info_service_uuid.inc diff --git a/firmware/targets/f7/ble_glue/services/gatt_char.c b/targets/f7/ble_glue/services/gatt_char.c similarity index 100% rename from firmware/targets/f7/ble_glue/services/gatt_char.c rename to targets/f7/ble_glue/services/gatt_char.c diff --git a/firmware/targets/f7/ble_glue/services/gatt_char.h b/targets/f7/ble_glue/services/gatt_char.h similarity index 100% rename from firmware/targets/f7/ble_glue/services/gatt_char.h rename to targets/f7/ble_glue/services/gatt_char.h diff --git a/firmware/targets/f7/ble_glue/services/hid_service.c b/targets/f7/ble_glue/services/hid_service.c similarity index 100% rename from firmware/targets/f7/ble_glue/services/hid_service.c rename to targets/f7/ble_glue/services/hid_service.c diff --git a/firmware/targets/f7/ble_glue/services/hid_service.h b/targets/f7/ble_glue/services/hid_service.h similarity index 100% rename from firmware/targets/f7/ble_glue/services/hid_service.h rename to targets/f7/ble_glue/services/hid_service.h diff --git a/firmware/targets/f7/ble_glue/services/serial_service.c b/targets/f7/ble_glue/services/serial_service.c similarity index 100% rename from firmware/targets/f7/ble_glue/services/serial_service.c rename to targets/f7/ble_glue/services/serial_service.c diff --git a/firmware/targets/f7/ble_glue/services/serial_service.h b/targets/f7/ble_glue/services/serial_service.h similarity index 100% rename from firmware/targets/f7/ble_glue/services/serial_service.h rename to targets/f7/ble_glue/services/serial_service.h diff --git a/firmware/targets/f7/ble_glue/services/serial_service_uuid.inc b/targets/f7/ble_glue/services/serial_service_uuid.inc similarity index 100% rename from firmware/targets/f7/ble_glue/services/serial_service_uuid.inc rename to targets/f7/ble_glue/services/serial_service_uuid.inc diff --git a/firmware/targets/f7/ble_glue/tl_dbg_conf.h b/targets/f7/ble_glue/tl_dbg_conf.h similarity index 100% rename from firmware/targets/f7/ble_glue/tl_dbg_conf.h rename to targets/f7/ble_glue/tl_dbg_conf.h diff --git a/firmware/targets/f7/fatfs/fatfs.c b/targets/f7/fatfs/fatfs.c similarity index 100% rename from firmware/targets/f7/fatfs/fatfs.c rename to targets/f7/fatfs/fatfs.c diff --git a/firmware/targets/f7/fatfs/fatfs.h b/targets/f7/fatfs/fatfs.h similarity index 100% rename from firmware/targets/f7/fatfs/fatfs.h rename to targets/f7/fatfs/fatfs.h diff --git a/firmware/targets/f7/fatfs/ffconf.h b/targets/f7/fatfs/ffconf.h similarity index 100% rename from firmware/targets/f7/fatfs/ffconf.h rename to targets/f7/fatfs/ffconf.h diff --git a/firmware/targets/f7/fatfs/sector_cache.c b/targets/f7/fatfs/sector_cache.c similarity index 100% rename from firmware/targets/f7/fatfs/sector_cache.c rename to targets/f7/fatfs/sector_cache.c diff --git a/firmware/targets/f7/fatfs/sector_cache.h b/targets/f7/fatfs/sector_cache.h similarity index 100% rename from firmware/targets/f7/fatfs/sector_cache.h rename to targets/f7/fatfs/sector_cache.h diff --git a/firmware/targets/f7/fatfs/user_diskio.c b/targets/f7/fatfs/user_diskio.c similarity index 100% rename from firmware/targets/f7/fatfs/user_diskio.c rename to targets/f7/fatfs/user_diskio.c diff --git a/firmware/targets/f7/fatfs/user_diskio.h b/targets/f7/fatfs/user_diskio.h similarity index 100% rename from firmware/targets/f7/fatfs/user_diskio.h rename to targets/f7/fatfs/user_diskio.h diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/targets/f7/furi_hal/furi_hal.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal.c rename to targets/f7/furi_hal/furi_hal.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/targets/f7/furi_hal/furi_hal_bt.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_bt.c rename to targets/f7/furi_hal/furi_hal_bt.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/targets/f7/furi_hal/furi_hal_bt_hid.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_bt_hid.c rename to targets/f7/furi_hal/furi_hal_bt_hid.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_serial.c b/targets/f7/furi_hal/furi_hal_bt_serial.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_bt_serial.c rename to targets/f7/furi_hal/furi_hal_bt_serial.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_bus.c b/targets/f7/furi_hal/furi_hal_bus.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_bus.c rename to targets/f7/furi_hal/furi_hal_bus.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_bus.h b/targets/f7/furi_hal/furi_hal_bus.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_bus.h rename to targets/f7/furi_hal/furi_hal_bus.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.c b/targets/f7/furi_hal/furi_hal_clock.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_clock.c rename to targets/f7/furi_hal/furi_hal_clock.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.h b/targets/f7/furi_hal/furi_hal_clock.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_clock.h rename to targets/f7/furi_hal/furi_hal_clock.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_console.c b/targets/f7/furi_hal/furi_hal_console.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_console.c rename to targets/f7/furi_hal/furi_hal_console.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_console.h b/targets/f7/furi_hal/furi_hal_console.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_console.h rename to targets/f7/furi_hal/furi_hal_console.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_cortex.c b/targets/f7/furi_hal/furi_hal_cortex.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_cortex.c rename to targets/f7/furi_hal/furi_hal_cortex.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_crypto.c b/targets/f7/furi_hal/furi_hal_crypto.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_crypto.c rename to targets/f7/furi_hal/furi_hal_crypto.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_debug.c b/targets/f7/furi_hal/furi_hal_debug.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_debug.c rename to targets/f7/furi_hal/furi_hal_debug.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_dma.c b/targets/f7/furi_hal/furi_hal_dma.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_dma.c rename to targets/f7/furi_hal/furi_hal_dma.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_dma.h b/targets/f7/furi_hal/furi_hal_dma.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_dma.h rename to targets/f7/furi_hal/furi_hal_dma.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/targets/f7/furi_hal/furi_hal_flash.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_flash.c rename to targets/f7/furi_hal/furi_hal_flash.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.h b/targets/f7/furi_hal/furi_hal_flash.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_flash.h rename to targets/f7/furi_hal/furi_hal_flash.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_gpio.c b/targets/f7/furi_hal/furi_hal_gpio.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_gpio.c rename to targets/f7/furi_hal/furi_hal_gpio.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_gpio.h b/targets/f7/furi_hal/furi_hal_gpio.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_gpio.h rename to targets/f7/furi_hal/furi_hal_gpio.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_i2c.c b/targets/f7/furi_hal/furi_hal_i2c.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_i2c.c rename to targets/f7/furi_hal/furi_hal_i2c.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c b/targets/f7/furi_hal/furi_hal_i2c_config.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_i2c_config.c rename to targets/f7/furi_hal/furi_hal_i2c_config.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.h b/targets/f7/furi_hal/furi_hal_i2c_config.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_i2c_config.h rename to targets/f7/furi_hal/furi_hal_i2c_config.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_i2c_types.h b/targets/f7/furi_hal/furi_hal_i2c_types.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_i2c_types.h rename to targets/f7/furi_hal/furi_hal_i2c_types.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c b/targets/f7/furi_hal/furi_hal_ibutton.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_ibutton.c rename to targets/f7/furi_hal/furi_hal_ibutton.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_ibutton.h b/targets/f7/furi_hal/furi_hal_ibutton.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_ibutton.h rename to targets/f7/furi_hal/furi_hal_ibutton.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h b/targets/f7/furi_hal/furi_hal_idle_timer.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_idle_timer.h rename to targets/f7/furi_hal/furi_hal_idle_timer.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_info.c b/targets/f7/furi_hal/furi_hal_info.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_info.c rename to targets/f7/furi_hal/furi_hal_info.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/targets/f7/furi_hal/furi_hal_infrared.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_infrared.c rename to targets/f7/furi_hal/furi_hal_infrared.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_interrupt.c b/targets/f7/furi_hal/furi_hal_interrupt.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_interrupt.c rename to targets/f7/furi_hal/furi_hal_interrupt.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_interrupt.h b/targets/f7/furi_hal/furi_hal_interrupt.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_interrupt.h rename to targets/f7/furi_hal/furi_hal_interrupt.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_light.c b/targets/f7/furi_hal/furi_hal_light.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_light.c rename to targets/f7/furi_hal/furi_hal_light.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_memory.c b/targets/f7/furi_hal/furi_hal_memory.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_memory.c rename to targets/f7/furi_hal/furi_hal_memory.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_mpu.c b/targets/f7/furi_hal/furi_hal_mpu.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_mpu.c rename to targets/f7/furi_hal/furi_hal_mpu.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/targets/f7/furi_hal/furi_hal_nfc.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc.c rename to targets/f7/furi_hal/furi_hal_nfc.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_event.c b/targets/f7/furi_hal/furi_hal_nfc_event.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc_event.c rename to targets/f7/furi_hal/furi_hal_nfc_event.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_felica.c b/targets/f7/furi_hal/furi_hal_nfc_felica.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc_felica.c rename to targets/f7/furi_hal/furi_hal_nfc_felica.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_i.h b/targets/f7/furi_hal/furi_hal_nfc_i.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc_i.h rename to targets/f7/furi_hal/furi_hal_nfc_i.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_irq.c b/targets/f7/furi_hal/furi_hal_nfc_irq.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc_irq.c rename to targets/f7/furi_hal/furi_hal_nfc_irq.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_iso14443a.c b/targets/f7/furi_hal/furi_hal_nfc_iso14443a.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc_iso14443a.c rename to targets/f7/furi_hal/furi_hal_nfc_iso14443a.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_iso14443b.c b/targets/f7/furi_hal/furi_hal_nfc_iso14443b.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc_iso14443b.c rename to targets/f7/furi_hal/furi_hal_nfc_iso14443b.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_iso15693.c b/targets/f7/furi_hal/furi_hal_nfc_iso15693.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc_iso15693.c rename to targets/f7/furi_hal/furi_hal_nfc_iso15693.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_tech_i.h b/targets/f7/furi_hal/furi_hal_nfc_tech_i.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc_tech_i.h rename to targets/f7/furi_hal/furi_hal_nfc_tech_i.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc_timer.c b/targets/f7/furi_hal/furi_hal_nfc_timer.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_nfc_timer.c rename to targets/f7/furi_hal/furi_hal_nfc_timer.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_os.c b/targets/f7/furi_hal/furi_hal_os.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_os.c rename to targets/f7/furi_hal/furi_hal_os.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_os.h b/targets/f7/furi_hal/furi_hal_os.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_os.h rename to targets/f7/furi_hal/furi_hal_os.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/targets/f7/furi_hal/furi_hal_power.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_power.c rename to targets/f7/furi_hal/furi_hal_power.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_power_config.c b/targets/f7/furi_hal/furi_hal_power_config.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_power_config.c rename to targets/f7/furi_hal/furi_hal_power_config.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.c b/targets/f7/furi_hal/furi_hal_pwm.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_pwm.c rename to targets/f7/furi_hal/furi_hal_pwm.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.h b/targets/f7/furi_hal/furi_hal_pwm.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_pwm.h rename to targets/f7/furi_hal/furi_hal_pwm.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_random.c b/targets/f7/furi_hal/furi_hal_random.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_random.c rename to targets/f7/furi_hal/furi_hal_random.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_region.c b/targets/f7/furi_hal/furi_hal_region.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_region.c rename to targets/f7/furi_hal/furi_hal_region.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/targets/f7/furi_hal/furi_hal_resources.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_resources.c rename to targets/f7/furi_hal/furi_hal_resources.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.h b/targets/f7/furi_hal/furi_hal_resources.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_resources.h rename to targets/f7/furi_hal/furi_hal_resources.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/targets/f7/furi_hal/furi_hal_rfid.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_rfid.c rename to targets/f7/furi_hal/furi_hal_rfid.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.h b/targets/f7/furi_hal/furi_hal_rfid.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_rfid.h rename to targets/f7/furi_hal/furi_hal_rfid.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_rtc.c b/targets/f7/furi_hal/furi_hal_rtc.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_rtc.c rename to targets/f7/furi_hal/furi_hal_rtc.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_sd.c b/targets/f7/furi_hal/furi_hal_sd.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_sd.c rename to targets/f7/furi_hal/furi_hal_sd.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_speaker.c b/targets/f7/furi_hal/furi_hal_speaker.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_speaker.c rename to targets/f7/furi_hal/furi_hal_speaker.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi.c b/targets/f7/furi_hal/furi_hal_spi.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_spi.c rename to targets/f7/furi_hal/furi_hal_spi.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c b/targets/f7/furi_hal/furi_hal_spi_config.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_spi_config.c rename to targets/f7/furi_hal/furi_hal_spi_config.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_config.h b/targets/f7/furi_hal/furi_hal_spi_config.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_spi_config.h rename to targets/f7/furi_hal/furi_hal_spi_config.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_types.h b/targets/f7/furi_hal/furi_hal_spi_types.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_spi_types.h rename to targets/f7/furi_hal/furi_hal_spi_types.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_subghz.c rename to targets/f7/furi_hal/furi_hal_subghz.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.h b/targets/f7/furi_hal/furi_hal_subghz.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_subghz.h rename to targets/f7/furi_hal/furi_hal_subghz.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_target_hw.h b/targets/f7/furi_hal/furi_hal_target_hw.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_target_hw.h rename to targets/f7/furi_hal/furi_hal_target_hw.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_uart.c b/targets/f7/furi_hal/furi_hal_uart.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_uart.c rename to targets/f7/furi_hal/furi_hal_uart.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_uart.h b/targets/f7/furi_hal/furi_hal_uart.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_uart.h rename to targets/f7/furi_hal/furi_hal_uart.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/targets/f7/furi_hal/furi_hal_usb.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_usb.c rename to targets/f7/furi_hal/furi_hal_usb.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_ccid.c b/targets/f7/furi_hal/furi_hal_usb_ccid.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_usb_ccid.c rename to targets/f7/furi_hal/furi_hal_usb_ccid.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c b/targets/f7/furi_hal/furi_hal_usb_cdc.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_usb_cdc.c rename to targets/f7/furi_hal/furi_hal_usb_cdc.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h b/targets/f7/furi_hal/furi_hal_usb_cdc.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_usb_cdc.h rename to targets/f7/furi_hal/furi_hal_usb_cdc.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_hid.c b/targets/f7/furi_hal/furi_hal_usb_hid.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_usb_hid.c rename to targets/f7/furi_hal/furi_hal_usb_hid.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_i.h b/targets/f7/furi_hal/furi_hal_usb_i.h similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_usb_i.h rename to targets/f7/furi_hal/furi_hal_usb_i.h diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c b/targets/f7/furi_hal/furi_hal_usb_u2f.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_usb_u2f.c rename to targets/f7/furi_hal/furi_hal_usb_u2f.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_version.c b/targets/f7/furi_hal/furi_hal_version.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_version.c rename to targets/f7/furi_hal/furi_hal_version.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_version_device.c b/targets/f7/furi_hal/furi_hal_version_device.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_version_device.c rename to targets/f7/furi_hal/furi_hal_version_device.c diff --git a/firmware/targets/f7/furi_hal/furi_hal_vibro.c b/targets/f7/furi_hal/furi_hal_vibro.c similarity index 100% rename from firmware/targets/f7/furi_hal/furi_hal_vibro.c rename to targets/f7/furi_hal/furi_hal_vibro.c diff --git a/firmware/targets/f7/inc/FreeRTOSConfig.h b/targets/f7/inc/FreeRTOSConfig.h similarity index 100% rename from firmware/targets/f7/inc/FreeRTOSConfig.h rename to targets/f7/inc/FreeRTOSConfig.h diff --git a/firmware/targets/f7/inc/alt_boot.h b/targets/f7/inc/alt_boot.h similarity index 100% rename from firmware/targets/f7/inc/alt_boot.h rename to targets/f7/inc/alt_boot.h diff --git a/firmware/targets/f7/inc/stm32.h b/targets/f7/inc/stm32.h similarity index 100% rename from firmware/targets/f7/inc/stm32.h rename to targets/f7/inc/stm32.h diff --git a/firmware/targets/f7/inc/stm32_assert.h b/targets/f7/inc/stm32_assert.h similarity index 100% rename from firmware/targets/f7/inc/stm32_assert.h rename to targets/f7/inc/stm32_assert.h diff --git a/firmware/targets/f7/platform_specific/intrinsic_export.h b/targets/f7/platform_specific/intrinsic_export.h similarity index 100% rename from firmware/targets/f7/platform_specific/intrinsic_export.h rename to targets/f7/platform_specific/intrinsic_export.h diff --git a/firmware/targets/f7/platform_specific/math_wrapper.h b/targets/f7/platform_specific/math_wrapper.h similarity index 100% rename from firmware/targets/f7/platform_specific/math_wrapper.h rename to targets/f7/platform_specific/math_wrapper.h diff --git a/firmware/targets/f7/src/dfu.c b/targets/f7/src/dfu.c similarity index 100% rename from firmware/targets/f7/src/dfu.c rename to targets/f7/src/dfu.c diff --git a/firmware/targets/f7/src/main.c b/targets/f7/src/main.c similarity index 100% rename from firmware/targets/f7/src/main.c rename to targets/f7/src/main.c diff --git a/firmware/targets/f7/src/recovery.c b/targets/f7/src/recovery.c similarity index 100% rename from firmware/targets/f7/src/recovery.c rename to targets/f7/src/recovery.c diff --git a/firmware/targets/f7/src/system_stm32wbxx.c b/targets/f7/src/system_stm32wbxx.c similarity index 100% rename from firmware/targets/f7/src/system_stm32wbxx.c rename to targets/f7/src/system_stm32wbxx.c diff --git a/firmware/targets/f7/src/update.c b/targets/f7/src/update.c similarity index 100% rename from firmware/targets/f7/src/update.c rename to targets/f7/src/update.c diff --git a/firmware/targets/f7/startup_stm32wb55xx_cm4.s b/targets/f7/startup_stm32wb55xx_cm4.s similarity index 100% rename from firmware/targets/f7/startup_stm32wb55xx_cm4.s rename to targets/f7/startup_stm32wb55xx_cm4.s diff --git a/firmware/targets/f7/stm32wb55xx_flash.ld b/targets/f7/stm32wb55xx_flash.ld similarity index 100% rename from firmware/targets/f7/stm32wb55xx_flash.ld rename to targets/f7/stm32wb55xx_flash.ld diff --git a/firmware/targets/f7/stm32wb55xx_ram_fw.ld b/targets/f7/stm32wb55xx_ram_fw.ld similarity index 100% rename from firmware/targets/f7/stm32wb55xx_ram_fw.ld rename to targets/f7/stm32wb55xx_ram_fw.ld diff --git a/firmware/targets/f7/target.json b/targets/f7/target.json similarity index 100% rename from firmware/targets/f7/target.json rename to targets/f7/target.json diff --git a/firmware/targets/furi_hal_include/furi_hal.h b/targets/furi_hal_include/furi_hal.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal.h rename to targets/furi_hal_include/furi_hal.h diff --git a/firmware/targets/furi_hal_include/furi_hal_bt.h b/targets/furi_hal_include/furi_hal_bt.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_bt.h rename to targets/furi_hal_include/furi_hal_bt.h diff --git a/firmware/targets/furi_hal_include/furi_hal_bt_hid.h b/targets/furi_hal_include/furi_hal_bt_hid.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_bt_hid.h rename to targets/furi_hal_include/furi_hal_bt_hid.h diff --git a/firmware/targets/furi_hal_include/furi_hal_bt_serial.h b/targets/furi_hal_include/furi_hal_bt_serial.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_bt_serial.h rename to targets/furi_hal_include/furi_hal_bt_serial.h diff --git a/firmware/targets/furi_hal_include/furi_hal_cortex.h b/targets/furi_hal_include/furi_hal_cortex.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_cortex.h rename to targets/furi_hal_include/furi_hal_cortex.h diff --git a/firmware/targets/furi_hal_include/furi_hal_crypto.h b/targets/furi_hal_include/furi_hal_crypto.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_crypto.h rename to targets/furi_hal_include/furi_hal_crypto.h diff --git a/firmware/targets/furi_hal_include/furi_hal_debug.h b/targets/furi_hal_include/furi_hal_debug.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_debug.h rename to targets/furi_hal_include/furi_hal_debug.h diff --git a/firmware/targets/furi_hal_include/furi_hal_i2c.h b/targets/furi_hal_include/furi_hal_i2c.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_i2c.h rename to targets/furi_hal_include/furi_hal_i2c.h diff --git a/firmware/targets/furi_hal_include/furi_hal_info.h b/targets/furi_hal_include/furi_hal_info.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_info.h rename to targets/furi_hal_include/furi_hal_info.h diff --git a/firmware/targets/furi_hal_include/furi_hal_infrared.h b/targets/furi_hal_include/furi_hal_infrared.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_infrared.h rename to targets/furi_hal_include/furi_hal_infrared.h diff --git a/firmware/targets/furi_hal_include/furi_hal_light.h b/targets/furi_hal_include/furi_hal_light.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_light.h rename to targets/furi_hal_include/furi_hal_light.h diff --git a/firmware/targets/furi_hal_include/furi_hal_memory.h b/targets/furi_hal_include/furi_hal_memory.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_memory.h rename to targets/furi_hal_include/furi_hal_memory.h diff --git a/firmware/targets/furi_hal_include/furi_hal_mpu.h b/targets/furi_hal_include/furi_hal_mpu.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_mpu.h rename to targets/furi_hal_include/furi_hal_mpu.h diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/targets/furi_hal_include/furi_hal_nfc.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_nfc.h rename to targets/furi_hal_include/furi_hal_nfc.h diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/targets/furi_hal_include/furi_hal_power.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_power.h rename to targets/furi_hal_include/furi_hal_power.h diff --git a/firmware/targets/furi_hal_include/furi_hal_random.h b/targets/furi_hal_include/furi_hal_random.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_random.h rename to targets/furi_hal_include/furi_hal_random.h diff --git a/firmware/targets/furi_hal_include/furi_hal_region.h b/targets/furi_hal_include/furi_hal_region.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_region.h rename to targets/furi_hal_include/furi_hal_region.h diff --git a/firmware/targets/furi_hal_include/furi_hal_rtc.h b/targets/furi_hal_include/furi_hal_rtc.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_rtc.h rename to targets/furi_hal_include/furi_hal_rtc.h diff --git a/firmware/targets/furi_hal_include/furi_hal_sd.h b/targets/furi_hal_include/furi_hal_sd.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_sd.h rename to targets/furi_hal_include/furi_hal_sd.h diff --git a/firmware/targets/furi_hal_include/furi_hal_speaker.h b/targets/furi_hal_include/furi_hal_speaker.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_speaker.h rename to targets/furi_hal_include/furi_hal_speaker.h diff --git a/firmware/targets/furi_hal_include/furi_hal_spi.h b/targets/furi_hal_include/furi_hal_spi.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_spi.h rename to targets/furi_hal_include/furi_hal_spi.h diff --git a/firmware/targets/furi_hal_include/furi_hal_usb.h b/targets/furi_hal_include/furi_hal_usb.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_usb.h rename to targets/furi_hal_include/furi_hal_usb.h diff --git a/firmware/targets/furi_hal_include/furi_hal_usb_ccid.h b/targets/furi_hal_include/furi_hal_usb_ccid.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_usb_ccid.h rename to targets/furi_hal_include/furi_hal_usb_ccid.h diff --git a/firmware/targets/furi_hal_include/furi_hal_usb_hid.h b/targets/furi_hal_include/furi_hal_usb_hid.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_usb_hid.h rename to targets/furi_hal_include/furi_hal_usb_hid.h diff --git a/firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h b/targets/furi_hal_include/furi_hal_usb_hid_u2f.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_usb_hid_u2f.h rename to targets/furi_hal_include/furi_hal_usb_hid_u2f.h diff --git a/firmware/targets/furi_hal_include/furi_hal_version.h b/targets/furi_hal_include/furi_hal_version.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_version.h rename to targets/furi_hal_include/furi_hal_version.h diff --git a/firmware/targets/furi_hal_include/furi_hal_vibro.h b/targets/furi_hal_include/furi_hal_vibro.h similarity index 100% rename from firmware/targets/furi_hal_include/furi_hal_vibro.h rename to targets/furi_hal_include/furi_hal_vibro.h From c8180747dbfb7b6976bca9226ae42227737e0d0d Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:20:35 +0300 Subject: [PATCH 07/40] [FL-3456] Allow for larger Infrared remotes (#3164) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Do not load all signals at once (Draft) * Minor cleanup * Refactor remote renaming * Improve function signatures * Rename infrared_remote functions * Optimise signal loading * Implement adding signals to remote * Add read_name() method * Deprecate a function * Partially implement deleting signals (draft) * Use m-array instead of m-list for signal name directory * Use plain C strings instead of furi_string * Implement deleting signals * Implement deleting signals via generalised callback * Implement renaming signals * Rename some types * Some more renaming * Remove unused type * Implement inserting signals (internal use) * Improve InfraredMoveView * Send an event to move a signal * Remove unused type * Implement moving signals * Implement creating new remotes with one signal * Un-deprecate and rename a function * Add InfraredRemote API docs * Add InfraredSignal API docs * Better error messages * Show progress pop-up when moving buttons in a remote * Copy labels to the InfraredMoveView to avoid pointer invalidation * Improve file selection scene * Show progress pop-up when renaming buttons in a remote * Refactor a scene * Show progress when deleting a button from remote * Use a random name for temp files * Add docs to infrared_brute_force.h * Rename Infrared type to InfraredApp * Add docs to infrared_app_i.h Co-authored-by: あく --- applications/main/infrared/infrared.h | 3 - .../infrared/{infrared.c => infrared_app.c} | 183 ++++--- applications/main/infrared/infrared_app.h | 15 + applications/main/infrared/infrared_app_i.h | 288 +++++++++++ .../main/infrared/infrared_brute_force.c | 6 +- .../main/infrared/infrared_brute_force.h | 89 +++- applications/main/infrared/infrared_cli.c | 4 +- applications/main/infrared/infrared_i.h | 146 ------ applications/main/infrared/infrared_remote.c | 483 +++++++++++++----- applications/main/infrared/infrared_remote.h | 231 ++++++++- .../main/infrared/infrared_remote_button.c | 37 -- .../main/infrared/infrared_remote_button.h | 14 - applications/main/infrared/infrared_signal.c | 54 +- applications/main/infrared/infrared_signal.h | 179 ++++++- .../common/infrared_scene_universal_common.c | 17 +- .../infrared/scenes/infrared_scene_ask_back.c | 10 +- .../scenes/infrared_scene_ask_retry.c | 10 +- .../infrared/scenes/infrared_scene_debug.c | 14 +- .../infrared/scenes/infrared_scene_edit.c | 10 +- .../infrared_scene_edit_button_select.c | 16 +- .../scenes/infrared_scene_edit_delete.c | 62 ++- .../scenes/infrared_scene_edit_delete_done.c | 8 +- .../scenes/infrared_scene_edit_move.c | 73 ++- .../scenes/infrared_scene_edit_rename.c | 35 +- .../scenes/infrared_scene_edit_rename_done.c | 8 +- .../scenes/infrared_scene_error_databases.c | 8 +- .../infrared/scenes/infrared_scene_learn.c | 8 +- .../scenes/infrared_scene_learn_done.c | 8 +- .../scenes/infrared_scene_learn_enter_name.c | 37 +- .../scenes/infrared_scene_learn_success.c | 20 +- .../infrared/scenes/infrared_scene_remote.c | 16 +- .../scenes/infrared_scene_remote_list.c | 31 +- .../main/infrared/scenes/infrared_scene_rpc.c | 13 +- .../infrared/scenes/infrared_scene_start.c | 10 +- .../scenes/infrared_scene_universal.c | 10 +- .../scenes/infrared_scene_universal_ac.c | 4 +- .../scenes/infrared_scene_universal_audio.c | 4 +- .../infrared_scene_universal_projector.c | 4 +- .../scenes/infrared_scene_universal_tv.c | 4 +- .../main/infrared/views/infrared_move_view.c | 212 ++++---- .../main/infrared/views/infrared_move_view.h | 13 +- 41 files changed, 1622 insertions(+), 775 deletions(-) delete mode 100644 applications/main/infrared/infrared.h rename applications/main/infrared/{infrared.c => infrared_app.c} (74%) create mode 100644 applications/main/infrared/infrared_app.h create mode 100644 applications/main/infrared/infrared_app_i.h delete mode 100644 applications/main/infrared/infrared_i.h delete mode 100644 applications/main/infrared/infrared_remote_button.c delete mode 100644 applications/main/infrared/infrared_remote_button.h diff --git a/applications/main/infrared/infrared.h b/applications/main/infrared/infrared.h deleted file mode 100644 index e5eeb11772..0000000000 --- a/applications/main/infrared/infrared.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -typedef struct Infrared Infrared; diff --git a/applications/main/infrared/infrared.c b/applications/main/infrared/infrared_app.c similarity index 74% rename from applications/main/infrared/infrared.c rename to applications/main/infrared/infrared_app.c index fcf45c25c2..e29eda30fb 100644 --- a/applications/main/infrared/infrared.c +++ b/applications/main/infrared/infrared_app.c @@ -1,48 +1,52 @@ -#include "infrared_i.h" +#include "infrared_app_i.h" #include +#include #include +#define TAG "InfraredApp" + #define INFRARED_TX_MIN_INTERVAL_MS 50U -static const NotificationSequence* infrared_notification_sequences[] = { - &sequence_success, - &sequence_set_only_green_255, - &sequence_reset_green, - &sequence_solid_yellow, - &sequence_reset_rgb, - &sequence_blink_start_cyan, - &sequence_blink_start_magenta, - &sequence_blink_stop, +static const NotificationSequence* + infrared_notification_sequences[InfraredNotificationMessageCount] = { + &sequence_success, + &sequence_set_only_green_255, + &sequence_reset_green, + &sequence_solid_yellow, + &sequence_reset_rgb, + &sequence_blink_start_cyan, + &sequence_blink_start_magenta, + &sequence_blink_stop, }; -static void infrared_make_app_folder(Infrared* infrared) { +static void infrared_make_app_folder(InfraredApp* infrared) { if(!storage_simply_mkdir(infrared->storage, INFRARED_APP_FOLDER)) { - dialog_message_show_storage_error(infrared->dialogs, "Cannot create\napp folder"); + infrared_show_error_message(infrared, "Cannot create\napp folder"); } } static bool infrared_custom_event_callback(void* context, uint32_t event) { furi_assert(context); - Infrared* infrared = context; + InfraredApp* infrared = context; return scene_manager_handle_custom_event(infrared->scene_manager, event); } static bool infrared_back_event_callback(void* context) { furi_assert(context); - Infrared* infrared = context; + InfraredApp* infrared = context; return scene_manager_handle_back_event(infrared->scene_manager); } static void infrared_tick_event_callback(void* context) { furi_assert(context); - Infrared* infrared = context; + InfraredApp* infrared = context; scene_manager_handle_tick_event(infrared->scene_manager); } static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context) { furi_assert(context); - Infrared* infrared = context; + InfraredApp* infrared = context; furi_assert(infrared->rpc_ctx); if(event == RpcAppEventSessionClose) { @@ -109,8 +113,8 @@ static void infrared_find_vacant_remote_name(FuriString* name, const char* path) furi_record_close(RECORD_STORAGE); } -static Infrared* infrared_alloc() { - Infrared* infrared = malloc(sizeof(Infrared)); +static InfraredApp* infrared_alloc() { + InfraredApp* infrared = malloc(sizeof(InfraredApp)); infrared->file_path = furi_string_alloc(); @@ -139,7 +143,7 @@ static Infrared* infrared_alloc() { infrared->worker = infrared_worker_alloc(); infrared->remote = infrared_remote_alloc(); - infrared->received_signal = infrared_signal_alloc(); + infrared->current_signal = infrared_signal_alloc(); infrared->brute_force = infrared_brute_force_alloc(); infrared->submenu = submenu_alloc(); @@ -184,7 +188,7 @@ static Infrared* infrared_alloc() { return infrared; } -static void infrared_free(Infrared* infrared) { +static void infrared_free(InfraredApp* infrared) { furi_assert(infrared); ViewDispatcher* view_dispatcher = infrared->view_dispatcher; InfraredAppState* app_state = &infrared->app_state; @@ -229,7 +233,7 @@ static void infrared_free(Infrared* infrared) { scene_manager_free(infrared->scene_manager); infrared_brute_force_free(infrared->brute_force); - infrared_signal_free(infrared->received_signal); + infrared_signal_free(infrared->current_signal); infrared_remote_free(infrared->remote); infrared_worker_free(infrared->worker); @@ -248,65 +252,61 @@ static void infrared_free(Infrared* infrared) { } bool infrared_add_remote_with_button( - Infrared* infrared, + const InfraredApp* infrared, const char* button_name, - InfraredSignal* signal) { + const InfraredSignal* signal) { InfraredRemote* remote = infrared->remote; - FuriString *new_name, *new_path; - new_name = furi_string_alloc_set(INFRARED_DEFAULT_REMOTE_NAME); - new_path = furi_string_alloc_set(INFRARED_APP_FOLDER); + FuriString* new_name = furi_string_alloc_set(INFRARED_DEFAULT_REMOTE_NAME); + FuriString* new_path = furi_string_alloc_set(INFRARED_APP_FOLDER); infrared_find_vacant_remote_name(new_name, furi_string_get_cstr(new_path)); furi_string_cat_printf( new_path, "/%s%s", furi_string_get_cstr(new_name), INFRARED_APP_EXTENSION); - infrared_remote_reset(remote); - infrared_remote_set_name(remote, furi_string_get_cstr(new_name)); - infrared_remote_set_path(remote, furi_string_get_cstr(new_path)); + bool success = false; + + do { + if(!infrared_remote_create(remote, furi_string_get_cstr(new_path))) break; + if(!infrared_remote_append_signal(remote, signal, button_name)) break; + success = true; + } while(false); furi_string_free(new_name); furi_string_free(new_path); - return infrared_remote_add_button(remote, button_name, signal); + + return success; } -bool infrared_rename_current_remote(Infrared* infrared, const char* name) { +bool infrared_rename_current_remote(const InfraredApp* infrared, const char* new_name) { InfraredRemote* remote = infrared->remote; - const char* remote_path = infrared_remote_get_path(remote); + const char* old_path = infrared_remote_get_path(remote); - if(!strcmp(infrared_remote_get_name(remote), name)) { + if(!strcmp(infrared_remote_get_name(remote), new_name)) { return true; } - FuriString* new_name; - new_name = furi_string_alloc_set(name); + FuriString* new_name_fstr = furi_string_alloc_set(new_name); + FuriString* new_path_fstr = furi_string_alloc_set(old_path); - infrared_find_vacant_remote_name(new_name, remote_path); + infrared_find_vacant_remote_name(new_name_fstr, old_path); - FuriString* new_path; - new_path = furi_string_alloc_set(infrared_remote_get_path(remote)); - if(furi_string_end_with(new_path, INFRARED_APP_EXTENSION)) { - size_t filename_start = furi_string_search_rchar(new_path, '/'); - furi_string_left(new_path, filename_start); + if(furi_string_end_with(new_path_fstr, INFRARED_APP_EXTENSION)) { + path_extract_dirname(old_path, new_path_fstr); } - furi_string_cat_printf( - new_path, "/%s%s", furi_string_get_cstr(new_name), INFRARED_APP_EXTENSION); - Storage* storage = furi_record_open(RECORD_STORAGE); + path_append(new_path_fstr, furi_string_get_cstr(new_name_fstr)); + furi_string_cat(new_path_fstr, INFRARED_APP_EXTENSION); - FS_Error status = storage_common_rename( - storage, infrared_remote_get_path(remote), furi_string_get_cstr(new_path)); - infrared_remote_set_name(remote, furi_string_get_cstr(new_name)); - infrared_remote_set_path(remote, furi_string_get_cstr(new_path)); + const bool success = infrared_remote_rename(remote, furi_string_get_cstr(new_path_fstr)); - furi_string_free(new_name); - furi_string_free(new_path); + furi_string_free(new_name_fstr); + furi_string_free(new_path_fstr); - furi_record_close(RECORD_STORAGE); - return (status == FSE_OK || status == FSE_EXIST); + return success; } -void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { +void infrared_tx_start(InfraredApp* infrared) { if(infrared->app_state.is_transmitting) { return; } @@ -317,12 +317,12 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { return; } - if(infrared_signal_is_raw(signal)) { - InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + if(infrared_signal_is_raw(infrared->current_signal)) { + const InfraredRawSignal* raw = infrared_signal_get_raw_signal(infrared->current_signal); infrared_worker_set_raw_signal( infrared->worker, raw->timings, raw->timings_size, raw->frequency, raw->duty_cycle); } else { - InfraredMessage* message = infrared_signal_get_message(signal); + const InfraredMessage* message = infrared_signal_get_message(infrared->current_signal); infrared_worker_set_decoded_signal(infrared->worker, message); } @@ -336,20 +336,20 @@ void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal) { infrared->app_state.is_transmitting = true; } -void infrared_tx_start_button_index(Infrared* infrared, size_t button_index) { - furi_assert(button_index < infrared_remote_get_button_count(infrared->remote)); +void infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index) { + furi_assert(button_index < infrared_remote_get_signal_count(infrared->remote)); - InfraredRemoteButton* button = infrared_remote_get_button(infrared->remote, button_index); - InfraredSignal* signal = infrared_remote_button_get_signal(button); - - infrared_tx_start_signal(infrared, signal); + if(infrared_remote_load_signal(infrared->remote, infrared->current_signal, button_index)) { + infrared_tx_start(infrared); + } else { + infrared_show_error_message( + infrared, + "Failed to load\n\"%s\"", + infrared_remote_get_signal_name(infrared->remote, button_index)); + } } -void infrared_tx_start_received(Infrared* infrared) { - infrared_tx_start_signal(infrared, infrared->received_signal); -} - -void infrared_tx_stop(Infrared* infrared) { +void infrared_tx_stop(InfraredApp* infrared) { if(!infrared->app_state.is_transmitting) { return; } @@ -363,25 +363,27 @@ void infrared_tx_stop(Infrared* infrared) { infrared->app_state.last_transmit_time = furi_get_tick(); } -void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...) { +void infrared_text_store_set(InfraredApp* infrared, uint32_t bank, const char* fmt, ...) { va_list args; - va_start(args, text); + va_start(args, fmt); - vsnprintf(infrared->text_store[bank], INFRARED_TEXT_STORE_SIZE, text, args); + vsnprintf(infrared->text_store[bank], INFRARED_TEXT_STORE_SIZE, fmt, args); va_end(args); } -void infrared_text_store_clear(Infrared* infrared, uint32_t bank) { +void infrared_text_store_clear(InfraredApp* infrared, uint32_t bank) { memset(infrared->text_store[bank], 0, INFRARED_TEXT_STORE_SIZE + 1); } -void infrared_play_notification_message(Infrared* infrared, uint32_t message) { - furi_assert(message < sizeof(infrared_notification_sequences) / sizeof(NotificationSequence*)); +void infrared_play_notification_message( + const InfraredApp* infrared, + InfraredNotificationMessage message) { + furi_assert(message < InfraredNotificationMessageCount); notification_message(infrared->notifications, infrared_notification_sequences[message]); } -void infrared_show_loading_popup(Infrared* infrared, bool show) { +void infrared_show_loading_popup(const InfraredApp* infrared, bool show) { TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); ViewStack* view_stack = infrared->view_stack; Loading* loading = infrared->loading; @@ -397,19 +399,30 @@ void infrared_show_loading_popup(Infrared* infrared, bool show) { } } +void infrared_show_error_message(const InfraredApp* infrared, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + + FuriString* message = furi_string_alloc_vprintf(fmt, args); + dialog_message_show_storage_error(infrared->dialogs, furi_string_get_cstr(message)); + + furi_string_free(message); + va_end(args); +} + void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal) { furi_assert(context); - Infrared* infrared = context; + InfraredApp* infrared = context; if(infrared_worker_signal_is_decoded(received_signal)) { infrared_signal_set_message( - infrared->received_signal, infrared_worker_get_decoded_signal(received_signal)); + infrared->current_signal, infrared_worker_get_decoded_signal(received_signal)); } else { const uint32_t* timings; size_t timings_size; infrared_worker_get_raw_signal(received_signal, &timings, &timings_size); infrared_signal_set_raw_signal( - infrared->received_signal, + infrared->current_signal, timings, timings_size, INFRARED_COMMON_CARRIER_FREQUENCY, @@ -422,20 +435,20 @@ void infrared_signal_received_callback(void* context, InfraredWorkerSignal* rece void infrared_text_input_callback(void* context) { furi_assert(context); - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeTextEditDone); } void infrared_popup_closed_callback(void* context) { furi_assert(context); - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypePopupClosed); } int32_t infrared_app(void* p) { - Infrared* infrared = infrared_alloc(); + InfraredApp* infrared = infrared_alloc(); infrared_make_app_folder(infrared); @@ -451,13 +464,15 @@ int32_t infrared_app(void* p) { rpc_system_app_send_started(infrared->rpc_ctx); is_rpc_mode = true; } else { - furi_string_set(infrared->file_path, (const char*)p); - is_remote_loaded = infrared_remote_load(infrared->remote, infrared->file_path); + const char* file_path = (const char*)p; + is_remote_loaded = infrared_remote_load(infrared->remote, file_path); + if(!is_remote_loaded) { - dialog_message_show_storage_error( - infrared->dialogs, "Failed to load\nselected remote"); + infrared_show_error_message(infrared, "Failed to load\n\"%s\"", file_path); return -1; } + + furi_string_set(infrared->file_path, file_path); } } diff --git a/applications/main/infrared/infrared_app.h b/applications/main/infrared/infrared_app.h new file mode 100644 index 0000000000..a6f87402a9 --- /dev/null +++ b/applications/main/infrared/infrared_app.h @@ -0,0 +1,15 @@ +/** + * @file infrared_app.h + * @brief Infrared application - start here. + * + * @see infrared_app_i.h for the main application data structure and functions. + * @see infrared_signal.h for the infrared signal library - loading, storing and transmitting signals. + * @see infrared_remote.hl for the infrared remote library - loading, storing and manipulating remotes. + * @see infrared_brute_force.h for the infrared brute force - loading and transmitting multiple signals. + */ +#pragma once + +/** + * @brief InfraredApp opaque type declaration. + */ +typedef struct InfraredApp InfraredApp; diff --git a/applications/main/infrared/infrared_app_i.h b/applications/main/infrared/infrared_app_i.h new file mode 100644 index 0000000000..c9dfe3ab86 --- /dev/null +++ b/applications/main/infrared/infrared_app_i.h @@ -0,0 +1,288 @@ +/** + * @file infrared_app_i.h + * @brief Main Infrared application types and functions. + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include "infrared_app.h" +#include "infrared_remote.h" +#include "infrared_brute_force.h" +#include "infrared_custom_event.h" + +#include "scenes/infrared_scene.h" +#include "views/infrared_progress_view.h" +#include "views/infrared_debug_view.h" +#include "views/infrared_move_view.h" + +#include "rpc/rpc_app.h" + +#define INFRARED_FILE_NAME_SIZE 100 +#define INFRARED_TEXT_STORE_NUM 2 +#define INFRARED_TEXT_STORE_SIZE 128 + +#define INFRARED_MAX_BUTTON_NAME_LENGTH 22 +#define INFRARED_MAX_REMOTE_NAME_LENGTH 22 + +#define INFRARED_APP_FOLDER ANY_PATH("infrared") +#define INFRARED_APP_EXTENSION ".ir" + +#define INFRARED_DEFAULT_REMOTE_NAME "Remote" +#define INFRARED_LOG_TAG "InfraredApp" + +/** + * @brief Enumeration of invalid remote button indices. + */ +typedef enum { + InfraredButtonIndexNone = -1, /**< No button is currently selected. */ +} InfraredButtonIndex; + +/** + * @brief Enumeration of editing targets. + */ +typedef enum { + InfraredEditTargetNone, /**< No editing target is selected. */ + InfraredEditTargetRemote, /**< Whole remote is selected as editing target. */ + InfraredEditTargetButton, /**< Single button is selected as editing target. */ +} InfraredEditTarget; + +/** + * @brief Enumeration of editing modes. + */ +typedef enum { + InfraredEditModeNone, /**< No editing mode is selected. */ + InfraredEditModeRename, /**< Rename mode is selected. */ + InfraredEditModeDelete, /**< Delete mode is selected. */ +} InfraredEditMode; + +/** + * @brief Infrared application state type. + */ +typedef struct { + bool is_learning_new_remote; /**< Learning new remote or adding to an existing one. */ + bool is_debug_enabled; /**< Whether to enable or disable debugging features. */ + bool is_transmitting; /**< Whether a signal is currently being transmitted. */ + InfraredEditTarget edit_target : 8; /**< Selected editing target (a remote or a button). */ + InfraredEditMode edit_mode : 8; /**< Selected editing operation (rename or delete). */ + int32_t current_button_index; /**< Selected button index (move destination). */ + int32_t prev_button_index; /**< Previous button index (move source). */ + uint32_t last_transmit_time; /**< Lat time a signal was transmitted. */ +} InfraredAppState; + +/** + * @brief Infrared application type. + */ +struct InfraredApp { + SceneManager* scene_manager; /**< Pointer to a SceneManager instance. */ + ViewDispatcher* view_dispatcher; /**< Pointer to a ViewDispatcher instance. */ + + Gui* gui; /**< Pointer to a Gui instance. */ + Storage* storage; /**< Pointer to a Storage instance. */ + DialogsApp* dialogs; /**< Pointer to a DialogsApp instance. */ + NotificationApp* notifications; /**< Pointer to a NotificationApp instance. */ + InfraredWorker* worker; /**< Used to send or receive signals. */ + InfraredRemote* remote; /**< Holds the currently loaded remote. */ + InfraredSignal* current_signal; /**< Holds the currently loaded signal. */ + InfraredBruteForce* brute_force; /**< Used for the Universal Remote feature. */ + + Submenu* submenu; /**< Standard view for displaying application menus. */ + TextInput* text_input; /**< Standard view for receiving user text input. */ + DialogEx* dialog_ex; /**< Standard view for displaying dialogs. */ + ButtonMenu* button_menu; /**< Custom view for interacting with IR remotes. */ + Popup* popup; /**< Standard view for displaying messages. */ + + ViewStack* view_stack; /**< Standard view for displaying stacked interfaces. */ + InfraredDebugView* debug_view; /**< Custom view for displaying debug information. */ + InfraredMoveView* move_view; /**< Custom view for rearranging buttons in a remote. */ + + ButtonPanel* button_panel; /**< Standard view for displaying control panels. */ + Loading* loading; /**< Standard view for informing about long operations. */ + InfraredProgressView* progress; /**< Custom view for showing brute force progress. */ + + FuriString* file_path; /**< Full path to the currently loaded file. */ + /** Arbitrary text storage for various inputs. */ + char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1]; + InfraredAppState app_state; /**< Application state. */ + + void* rpc_ctx; /**< Pointer to the RPC context object. */ +}; + +/** + * @brief Enumeration of all used view types. + */ +typedef enum { + InfraredViewSubmenu, + InfraredViewTextInput, + InfraredViewDialogEx, + InfraredViewButtonMenu, + InfraredViewPopup, + InfraredViewStack, + InfraredViewDebugView, + InfraredViewMove, +} InfraredView; + +/** + * @brief Enumeration of all notification message types. + */ +typedef enum { + InfraredNotificationMessageSuccess, /**< Play a short happy tune. */ + InfraredNotificationMessageGreenOn, /**< Turn green LED on. */ + InfraredNotificationMessageGreenOff, /**< Turn green LED off. */ + InfraredNotificationMessageYellowOn, /**< Turn yellow LED on. */ + InfraredNotificationMessageYellowOff, /**< Turn yellow LED off. */ + InfraredNotificationMessageBlinkStartRead, /**< Blink the LED to indicate receiver mode. */ + InfraredNotificationMessageBlinkStartSend, /**< Blink the LED to indicate transmitter mode. */ + InfraredNotificationMessageBlinkStop, /**< Stop blinking the LED. */ + InfraredNotificationMessageCount, /**< Special value equal to the message type count. */ +} InfraredNotificationMessage; + +/** + * @brief Add a new remote with a single signal. + * + * The filename will be automatically generated depending on + * the names and number of other files in the infrared data directory. + * + * @param[in] infrared pointer to the application instance. + * @param[in] name pointer to a zero-terminated string containing the signal name. + * @param[in] signal pointer to the signal to be added. + * @return true if the remote was successfully created, false otherwise. + */ +bool infrared_add_remote_with_button( + const InfraredApp* infrared, + const char* name, + const InfraredSignal* signal); + +/** + * @brief Rename the currently loaded remote. + * + * @param[in] infrared pointer to the application instance. + * @param[in] new_name pointer to a zero-terminated string containing the new remote name. + * @return true if the remote was successfully renamed, false otherwise. + */ +bool infrared_rename_current_remote(const InfraredApp* infrared, const char* new_name); + +/** + * @brief Begin transmission of the currently loaded signal. + * + * The signal will be repeated indefinitely until stopped. + * + * @param[in,out] infrared pointer to the application instance. + */ +void infrared_tx_start(InfraredApp* infrared); + +/** + * @brief Load a signal under the given index and begin transmission. + * + * The signal will be repeated indefinitely until stopped. + * + * @param[in,out] infrared pointer to the application instance. + * @param[in] button_index index of the signal to be loaded. + * @returns true if the signal could be loaded, false otherwise. + */ +void infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index); + +/** + * @brief Stop transmission of the currently loaded signal. + * + * @param[in,out] infrared pointer to the application instance. + */ +void infrared_tx_stop(InfraredApp* infrared); + +/** + * @brief Set the internal text store with formatted text. + * + * @param[in,out] infrared pointer to the application instance. + * @param[in] bank index of text store bank (0 or 1). + * @param[in] fmt pointer to a zero-terminated string containing the format text. + * @param[in] ... additional arguments. + */ +void infrared_text_store_set(InfraredApp* infrared, uint32_t bank, const char* fmt, ...) + _ATTRIBUTE((__format__(__printf__, 3, 4))); + +/** + * @brief Clear the internal text store. + * + * @param[in,out] infrared pointer to the application instance. + * @param[in] bank index of text store bank (0 or 1). + */ +void infrared_text_store_clear(InfraredApp* infrared, uint32_t bank); + +/** + * @brief Play a sound and/or blink the LED. + * + * @param[in] infrared pointer to the application instance. + * @param[in] message type of the message to play. + */ +void infrared_play_notification_message( + const InfraredApp* infrared, + InfraredNotificationMessage message); + +/** + * @brief Show a loading pop-up screen. + * + * In order for this to work, a Stack view must be currently active and + * the main view must be added to it. + * + * @param[in] infrared pointer to the application instance. + * @param[in] show whether to show or hide the pop-up. + */ +void infrared_show_loading_popup(const InfraredApp* infrared, bool show); + +/** + * @brief Show a formatted error messsage. + * + * @param[in] infrared pointer to the application instance. + * @param[in] fmt pointer to a zero-terminated string containing the format text. + * @param[in] ... additional arguments. + */ +void infrared_show_error_message(const InfraredApp* infrared, const char* fmt, ...) + _ATTRIBUTE((__format__(__printf__, 2, 3))); + +/** + * @brief Common received signal callback. + * + * Called when the worker has received a complete infrared signal. + * + * @param[in,out] context pointer to the user-specified context object. + * @param[in] received_signal pointer to the received signal. + */ +void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal); + +/** + * @brief Common text input callback. + * + * Called when the input has been accepted by the user. + * + * @param[in,out] context pointer to the user-specified context object. + */ +void infrared_text_input_callback(void* context); + +/** + * @brief Common popup close callback. + * + * Called when the popup has been closed either by the user or after a timeout. + * + * @param[in,out] context pointer to the user-specified context object. + */ +void infrared_popup_closed_callback(void* context); diff --git a/applications/main/infrared/infrared_brute_force.c b/applications/main/infrared/infrared_brute_force.c index 3ca5c409f7..bb7992ae61 100644 --- a/applications/main/infrared/infrared_brute_force.c +++ b/applications/main/infrared/infrared_brute_force.c @@ -111,7 +111,7 @@ bool infrared_brute_force_start( return success; } -bool infrared_brute_force_is_started(InfraredBruteForce* brute_force) { +bool infrared_brute_force_is_started(const InfraredBruteForce* brute_force) { return brute_force->is_started; } @@ -129,7 +129,9 @@ void infrared_brute_force_stop(InfraredBruteForce* brute_force) { bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) { furi_assert(brute_force->is_started); const bool success = infrared_signal_search_and_read( - brute_force->current_signal, brute_force->ff, brute_force->current_record_name); + brute_force->current_signal, + brute_force->ff, + furi_string_get_cstr(brute_force->current_record_name)); if(success) { infrared_signal_transmit(brute_force->current_signal); } diff --git a/applications/main/infrared/infrared_brute_force.h b/applications/main/infrared/infrared_brute_force.h index 042d1556b7..33677d2ec1 100644 --- a/applications/main/infrared/infrared_brute_force.h +++ b/applications/main/infrared/infrared_brute_force.h @@ -1,23 +1,110 @@ +/** + * @file infrared_brute_force.h + * @brief Infrared signal brute-forcing library. + * + * The BruteForce library is used to send large quantities of signals, + * sorted by a category. It is used to implement the Universal Remote + * feature. + */ #pragma once #include #include +/** + * @brief InfraredBruteForce opaque type declaration. + */ typedef struct InfraredBruteForce InfraredBruteForce; +/** + * @brief Create a new InfraredBruteForce instance. + * + * @returns pointer to the created instance. + */ InfraredBruteForce* infrared_brute_force_alloc(); + +/** + * @brief Delete an InfraredBruteForce instance. + * + * @param[in,out] brute_force pointer to the instance to be deleted. + */ void infrared_brute_force_free(InfraredBruteForce* brute_force); + +/** + * @brief Set an InfraredBruteForce instance to use a signal database contained in a file. + * + * @param[in,out] brute_force pointer to the instance to be configured. + * @param[in] db_filename pointer to a zero-terminated string containing a full path to the database file. + */ void infrared_brute_force_set_db_filename(InfraredBruteForce* brute_force, const char* db_filename); + +/** + * @brief Build a signal dictionary from a previously set database file. + * + * This function must be called each time after setting the database via + * a infrared_brute_force_set_db_filename() call. + * + * @param[in,out] brute_force pointer to the instance to be updated. + * @returns true on success, false otherwise. + */ bool infrared_brute_force_calculate_messages(InfraredBruteForce* brute_force); + +/** + * @brief Start transmitting signals from a category stored in an InfraredBruteForce's instance dictionary. + * + * @param[in,out] brute_force pointer to the instance to be started. + * @param[in] index index of the signal category in the dictionary. + * @returns true on success, false otherwise. + */ bool infrared_brute_force_start( InfraredBruteForce* brute_force, uint32_t index, uint32_t* record_count); -bool infrared_brute_force_is_started(InfraredBruteForce* brute_force); + +/** + * @brief Determine whether the transmission was started. + * + * @param[in] brute_force pointer to the instance to be tested. + * @returns true if transmission was started, false otherwise. + */ +bool infrared_brute_force_is_started(const InfraredBruteForce* brute_force); + +/** + * @brief Stop transmitting the signals. + * + * @param[in] brute_force pointer to the instance to be stopped. + */ void infrared_brute_force_stop(InfraredBruteForce* brute_force); + +/** + * @brief Send the next signal from the chosen category. + * + * This function is called repeatedly until no more signals are left + * in the chosen signal category. + * + * @warning Transmission must be started first by calling infrared_brute_force_start() + * before calling this function. + * + * @param[in,out] brute_force pointer to the instance to be used. + * @returns true if the next signal existed and could be transmitted, false otherwise. + */ bool infrared_brute_force_send_next(InfraredBruteForce* brute_force); + +/** + * @brief Add a signal category to an InfraredBruteForce instance's dictionary. + * + * @param[in,out] brute_force pointer to the instance to be updated. + * @param[in] index index of the category to be added. + * @param[in] name name of the category to be added. + */ void infrared_brute_force_add_record( InfraredBruteForce* brute_force, uint32_t index, const char* name); + +/** + * @brief Reset an InfraredBruteForce instance. + * + * @param[in,out] brute_force pointer to the instance to be reset. + */ void infrared_brute_force_reset(InfraredBruteForce* brute_force); diff --git a/applications/main/infrared/infrared_cli.c b/applications/main/infrared/infrared_cli.c index 54b5cabab7..c960ffa285 100644 --- a/applications/main/infrared/infrared_cli.c +++ b/applications/main/infrared/infrared_cli.c @@ -202,7 +202,7 @@ static bool } static bool infrared_cli_decode_raw_signal( - InfraredRawSignal* raw_signal, + const InfraredRawSignal* raw_signal, InfraredDecoderHandler* decoder, FlipperFormat* output_file, const char* signal_name) { @@ -274,7 +274,7 @@ static bool infrared_cli_decode_file(FlipperFormat* input_file, FlipperFormat* o continue; } } - InfraredRawSignal* raw_signal = infrared_signal_get_raw_signal(signal); + const InfraredRawSignal* raw_signal = infrared_signal_get_raw_signal(signal); printf( "Raw signal: %s, %zu samples\r\n", furi_string_get_cstr(tmp), diff --git a/applications/main/infrared/infrared_i.h b/applications/main/infrared/infrared_i.h deleted file mode 100644 index 6fb6a65c7b..0000000000 --- a/applications/main/infrared/infrared_i.h +++ /dev/null @@ -1,146 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#include "infrared.h" -#include "infrared_remote.h" -#include "infrared_brute_force.h" -#include "infrared_custom_event.h" - -#include "scenes/infrared_scene.h" -#include "views/infrared_progress_view.h" -#include "views/infrared_debug_view.h" -#include "views/infrared_move_view.h" - -#include "rpc/rpc_app.h" - -#define INFRARED_FILE_NAME_SIZE 100 -#define INFRARED_TEXT_STORE_NUM 2 -#define INFRARED_TEXT_STORE_SIZE 128 - -#define INFRARED_MAX_BUTTON_NAME_LENGTH 22 -#define INFRARED_MAX_REMOTE_NAME_LENGTH 22 - -#define INFRARED_APP_FOLDER ANY_PATH("infrared") -#define INFRARED_APP_EXTENSION ".ir" - -#define INFRARED_DEFAULT_REMOTE_NAME "Remote" -#define INFRARED_LOG_TAG "InfraredApp" - -typedef enum { - InfraredButtonIndexNone = -1, -} InfraredButtonIndex; - -typedef enum { - InfraredEditTargetNone, - InfraredEditTargetRemote, - InfraredEditTargetButton, -} InfraredEditTarget; - -typedef enum { - InfraredEditModeNone, - InfraredEditModeRename, - InfraredEditModeDelete, -} InfraredEditMode; - -typedef struct { - bool is_learning_new_remote; - bool is_debug_enabled; - bool is_transmitting; - InfraredEditTarget edit_target : 8; - InfraredEditMode edit_mode : 8; - int32_t current_button_index; - int32_t current_button_index_move_orig; - uint32_t last_transmit_time; -} InfraredAppState; - -struct Infrared { - SceneManager* scene_manager; - ViewDispatcher* view_dispatcher; - - Gui* gui; - Storage* storage; - DialogsApp* dialogs; - NotificationApp* notifications; - InfraredWorker* worker; - InfraredRemote* remote; - InfraredSignal* received_signal; - InfraredBruteForce* brute_force; - - Submenu* submenu; - TextInput* text_input; - DialogEx* dialog_ex; - ButtonMenu* button_menu; - Popup* popup; - - ViewStack* view_stack; - InfraredDebugView* debug_view; - InfraredMoveView* move_view; - - ButtonPanel* button_panel; - Loading* loading; - InfraredProgressView* progress; - - FuriString* file_path; - char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1]; - InfraredAppState app_state; - - void* rpc_ctx; -}; - -typedef enum { - InfraredViewSubmenu, - InfraredViewTextInput, - InfraredViewDialogEx, - InfraredViewButtonMenu, - InfraredViewPopup, - InfraredViewStack, - InfraredViewDebugView, - InfraredViewMove, -} InfraredView; - -typedef enum { - InfraredNotificationMessageSuccess, - InfraredNotificationMessageGreenOn, - InfraredNotificationMessageGreenOff, - InfraredNotificationMessageYellowOn, - InfraredNotificationMessageYellowOff, - InfraredNotificationMessageBlinkStartRead, - InfraredNotificationMessageBlinkStartSend, - InfraredNotificationMessageBlinkStop, -} InfraredNotificationMessage; - -bool infrared_add_remote_with_button(Infrared* infrared, const char* name, InfraredSignal* signal); -bool infrared_rename_current_remote(Infrared* infrared, const char* name); -void infrared_tx_start_signal(Infrared* infrared, InfraredSignal* signal); -void infrared_tx_start_button_index(Infrared* infrared, size_t button_index); -void infrared_tx_start_received(Infrared* infrared); -void infrared_tx_stop(Infrared* infrared); -void infrared_text_store_set(Infrared* infrared, uint32_t bank, const char* text, ...); -void infrared_text_store_clear(Infrared* infrared, uint32_t bank); -void infrared_play_notification_message(Infrared* infrared, uint32_t message); -void infrared_show_loading_popup(Infrared* infrared, bool show); - -void infrared_signal_received_callback(void* context, InfraredWorkerSignal* received_signal); -void infrared_text_input_callback(void* context); -void infrared_popup_closed_callback(void* context); diff --git a/applications/main/infrared/infrared_remote.c b/applications/main/infrared/infrared_remote.c index 70d1b59ef3..5b241fe9f6 100644 --- a/applications/main/infrared/infrared_remote.c +++ b/applications/main/infrared/infrared_remote.c @@ -1,197 +1,428 @@ #include "infrared_remote.h" -#include -#include -#include #include + +#include #include #include -#include #define TAG "InfraredRemote" -ARRAY_DEF(InfraredButtonArray, InfraredRemoteButton*, M_PTR_OPLIST); +#define INFRARED_FILE_HEADER "IR signals file" +#define INFRARED_FILE_VERSION (1) + +ARRAY_DEF(StringArray, const char*, M_CSTR_DUP_OPLIST); //-V575 struct InfraredRemote { - InfraredButtonArray_t buttons; + StringArray_t signal_names; FuriString* name; FuriString* path; }; -static void infrared_remote_clear_buttons(InfraredRemote* remote) { - InfraredButtonArray_it_t it; - for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it); - InfraredButtonArray_next(it)) { - infrared_remote_button_free(*InfraredButtonArray_cref(it)); - } - InfraredButtonArray_reset(remote->buttons); -} +typedef struct { + InfraredRemote* remote; + FlipperFormat* ff_in; + FlipperFormat* ff_out; + FuriString* signal_name; + InfraredSignal* signal; + size_t signal_index; +} InfraredBatch; + +typedef struct { + size_t signal_index; + const char* signal_name; + const InfraredSignal* signal; +} InfraredBatchTarget; + +typedef bool ( + *InfraredBatchCallback)(const InfraredBatch* batch, const InfraredBatchTarget* target); InfraredRemote* infrared_remote_alloc() { InfraredRemote* remote = malloc(sizeof(InfraredRemote)); - InfraredButtonArray_init(remote->buttons); + StringArray_init(remote->signal_names); remote->name = furi_string_alloc(); remote->path = furi_string_alloc(); return remote; } void infrared_remote_free(InfraredRemote* remote) { - infrared_remote_clear_buttons(remote); - InfraredButtonArray_clear(remote->buttons); + StringArray_clear(remote->signal_names); furi_string_free(remote->path); furi_string_free(remote->name); free(remote); } void infrared_remote_reset(InfraredRemote* remote) { - infrared_remote_clear_buttons(remote); + StringArray_reset(remote->signal_names); furi_string_reset(remote->name); furi_string_reset(remote->path); } -void infrared_remote_set_name(InfraredRemote* remote, const char* name) { - furi_string_set(remote->name, name); -} - -const char* infrared_remote_get_name(InfraredRemote* remote) { +const char* infrared_remote_get_name(const InfraredRemote* remote) { return furi_string_get_cstr(remote->name); } -void infrared_remote_set_path(InfraredRemote* remote, const char* path) { +static void infrared_remote_set_path(InfraredRemote* remote, const char* path) { furi_string_set(remote->path, path); + path_extract_filename(remote->path, remote->name, true); } -const char* infrared_remote_get_path(InfraredRemote* remote) { +const char* infrared_remote_get_path(const InfraredRemote* remote) { return furi_string_get_cstr(remote->path); } -size_t infrared_remote_get_button_count(InfraredRemote* remote) { - return InfraredButtonArray_size(remote->buttons); +size_t infrared_remote_get_signal_count(const InfraredRemote* remote) { + return StringArray_size(remote->signal_names); } -InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t index) { - furi_assert(index < InfraredButtonArray_size(remote->buttons)); - return *InfraredButtonArray_get(remote->buttons, index); +const char* infrared_remote_get_signal_name(const InfraredRemote* remote, size_t index) { + furi_assert(index < infrared_remote_get_signal_count(remote)); + return *StringArray_cget(remote->signal_names, index); } -bool infrared_remote_find_button_by_name(InfraredRemote* remote, const char* name, size_t* index) { - for(size_t i = 0; i < InfraredButtonArray_size(remote->buttons); i++) { - InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, i); - if(!strcmp(infrared_remote_button_get_name(button), name)) { +bool infrared_remote_load_signal( + const InfraredRemote* remote, + InfraredSignal* signal, + size_t index) { + furi_assert(index < infrared_remote_get_signal_count(remote)); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + + bool success = false; + + do { + const char* path = furi_string_get_cstr(remote->path); + if(!flipper_format_buffered_file_open_existing(ff, path)) break; + + const char* name = infrared_remote_get_signal_name(remote, index); + + if(!infrared_signal_search_and_read(signal, ff, name)) { + FURI_LOG_E(TAG, "Failed to load signal '%s' from file '%s'", name, path); + break; + } + + success = true; + } while(false); + + flipper_format_free(ff); + furi_record_close(RECORD_STORAGE); + + return success; +} + +bool infrared_remote_get_signal_index( + const InfraredRemote* remote, + const char* name, + size_t* index) { + uint32_t i = 0; + StringArray_it_t it; + + for(StringArray_it(it, remote->signal_names); !StringArray_end_p(it); + StringArray_next(it), ++i) { + if(strcmp(*StringArray_cref(it), name) == 0) { *index = i; return true; } } + return false; } -bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal) { - InfraredRemoteButton* button = infrared_remote_button_alloc(); - infrared_remote_button_set_name(button, name); - infrared_remote_button_set_signal(button, signal); - InfraredButtonArray_push_back(remote->buttons, button); - return infrared_remote_store(remote); -} - -bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index) { - furi_assert(index < InfraredButtonArray_size(remote->buttons)); - InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, index); - infrared_remote_button_set_name(button, new_name); - return infrared_remote_store(remote); -} - -bool infrared_remote_delete_button(InfraredRemote* remote, size_t index) { - furi_assert(index < InfraredButtonArray_size(remote->buttons)); - InfraredRemoteButton* button; - InfraredButtonArray_pop_at(&button, remote->buttons, index); - infrared_remote_button_free(button); - return infrared_remote_store(remote); -} - -void infrared_remote_move_button(InfraredRemote* remote, size_t index_orig, size_t index_dest) { - furi_assert(index_orig < InfraredButtonArray_size(remote->buttons)); - furi_assert(index_dest < InfraredButtonArray_size(remote->buttons)); - - InfraredRemoteButton* button; - InfraredButtonArray_pop_at(&button, remote->buttons, index_orig); - InfraredButtonArray_push_at(remote->buttons, index_dest, button); -} - -bool infrared_remote_store(InfraredRemote* remote) { +bool infrared_remote_append_signal( + InfraredRemote* remote, + const InfraredSignal* signal, + const char* name) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* ff = flipper_format_file_alloc(storage); + + bool success = false; const char* path = furi_string_get_cstr(remote->path); - FURI_LOG_I(TAG, "store file: \'%s\'", path); - - bool success = flipper_format_file_open_always(ff, path) && - flipper_format_write_header_cstr(ff, "IR signals file", 1); - if(success) { - InfraredButtonArray_it_t it; - for(InfraredButtonArray_it(it, remote->buttons); !InfraredButtonArray_end_p(it); - InfraredButtonArray_next(it)) { - InfraredRemoteButton* button = *InfraredButtonArray_cref(it); - success = infrared_signal_save( - infrared_remote_button_get_signal(button), - ff, - infrared_remote_button_get_name(button)); - if(!success) { - break; - } - } - } - - flipper_format_free(ff); - furi_record_close(RECORD_STORAGE); - return success; -} - -bool infrared_remote_load(InfraredRemote* remote, FuriString* path) { - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); - - FuriString* buf; - buf = furi_string_alloc(); - - FURI_LOG_I(TAG, "load file: \'%s\'", furi_string_get_cstr(path)); - bool success = false; - do { - if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(path))) break; - uint32_t version; - if(!flipper_format_read_header(ff, buf, &version)) break; - if(!furi_string_equal(buf, "IR signals file") || (version != 1)) break; + if(!flipper_format_file_open_append(ff, path)) break; + if(!infrared_signal_save(signal, ff, name)) break; - path_extract_filename(path, buf, true); - infrared_remote_clear_buttons(remote); - infrared_remote_set_name(remote, furi_string_get_cstr(buf)); - infrared_remote_set_path(remote, furi_string_get_cstr(path)); - - for(bool can_read = true; can_read;) { - InfraredRemoteButton* button = infrared_remote_button_alloc(); - can_read = infrared_signal_read(infrared_remote_button_get_signal(button), ff, buf); - if(can_read) { - infrared_remote_button_set_name(button, furi_string_get_cstr(buf)); - InfraredButtonArray_push_back(remote->buttons, button); - } else { - infrared_remote_button_free(button); - } - } + StringArray_push_back(remote->signal_names, name); success = true; } while(false); - furi_string_free(buf); flipper_format_free(ff); furi_record_close(RECORD_STORAGE); + + return success; +} + +static bool infrared_remote_batch_start( + InfraredRemote* remote, + InfraredBatchCallback batch_callback, + const InfraredBatchTarget* target) { + FuriString* tmp = furi_string_alloc(); + Storage* storage = furi_record_open(RECORD_STORAGE); + + InfraredBatch batch_context = { + .remote = remote, + .ff_in = flipper_format_buffered_file_alloc(storage), + .ff_out = flipper_format_buffered_file_alloc(storage), + .signal_name = furi_string_alloc(), + .signal = infrared_signal_alloc(), + .signal_index = 0, + }; + + const char* path_in = furi_string_get_cstr(remote->path); + const char* path_out; + + FS_Error status; + + do { + furi_string_printf(tmp, "%s.temp%08x.swp", path_in, rand()); + path_out = furi_string_get_cstr(tmp); + status = storage_common_stat(storage, path_out, NULL); + } while(status == FSE_OK || status == FSE_EXIST); + + bool success = false; + + do { + if(!flipper_format_buffered_file_open_existing(batch_context.ff_in, path_in)) break; + if(!flipper_format_buffered_file_open_always(batch_context.ff_out, path_out)) break; + if(!flipper_format_write_header_cstr( + batch_context.ff_out, INFRARED_FILE_HEADER, INFRARED_FILE_VERSION)) + break; + + const size_t signal_count = infrared_remote_get_signal_count(remote); + + for(; batch_context.signal_index < signal_count; ++batch_context.signal_index) { + if(!infrared_signal_read( + batch_context.signal, batch_context.ff_in, batch_context.signal_name)) + break; + if(!batch_callback(&batch_context, target)) break; + } + + if(batch_context.signal_index != signal_count) break; + + if(!flipper_format_buffered_file_close(batch_context.ff_out)) break; + if(!flipper_format_buffered_file_close(batch_context.ff_in)) break; + + const FS_Error status = storage_common_rename(storage, path_out, path_in); + success = (status == FSE_OK || status == FSE_EXIST); + } while(false); + + infrared_signal_free(batch_context.signal); + furi_string_free(batch_context.signal_name); + flipper_format_free(batch_context.ff_out); + flipper_format_free(batch_context.ff_in); + furi_string_free(tmp); + + furi_record_close(RECORD_STORAGE); + + return success; +} + +static bool infrared_remote_insert_signal_callback( + const InfraredBatch* batch, + const InfraredBatchTarget* target) { + // Insert a signal under the specified index + if(batch->signal_index == target->signal_index) { + if(!infrared_signal_save(target->signal, batch->ff_out, target->signal_name)) return false; + StringArray_push_at( + batch->remote->signal_names, target->signal_index, target->signal_name); + } + + // Write the rest normally + return infrared_signal_save( + batch->signal, batch->ff_out, furi_string_get_cstr(batch->signal_name)); +} + +bool infrared_remote_insert_signal( + InfraredRemote* remote, + const InfraredSignal* signal, + const char* name, + size_t index) { + if(index >= infrared_remote_get_signal_count(remote)) { + return infrared_remote_append_signal(remote, signal, name); + } + + const InfraredBatchTarget insert_target = { + .signal_index = index, + .signal_name = name, + .signal = signal, + }; + + return infrared_remote_batch_start( + remote, infrared_remote_insert_signal_callback, &insert_target); +} + +static bool infrared_remote_rename_signal_callback( + const InfraredBatch* batch, + const InfraredBatchTarget* target) { + const char* signal_name; + + if(batch->signal_index == target->signal_index) { + // Rename the signal at requested index + signal_name = target->signal_name; + StringArray_set_at(batch->remote->signal_names, batch->signal_index, signal_name); + } else { + // Use the original name otherwise + signal_name = furi_string_get_cstr(batch->signal_name); + } + + return infrared_signal_save(batch->signal, batch->ff_out, signal_name); +} + +bool infrared_remote_rename_signal(InfraredRemote* remote, size_t index, const char* new_name) { + furi_assert(index < infrared_remote_get_signal_count(remote)); + + const InfraredBatchTarget rename_target = { + .signal_index = index, + .signal_name = new_name, + .signal = NULL, + }; + + return infrared_remote_batch_start( + remote, infrared_remote_rename_signal_callback, &rename_target); +} + +static bool infrared_remote_delete_signal_callback( + const InfraredBatch* batch, + const InfraredBatchTarget* target) { + if(batch->signal_index == target->signal_index) { + // Do not save the signal to be deleted, remove it from the signal name list instead + StringArray_remove_v( + batch->remote->signal_names, batch->signal_index, batch->signal_index + 1); + } else { + // Pass other signals through + return infrared_signal_save( + batch->signal, batch->ff_out, furi_string_get_cstr(batch->signal_name)); + } + + return true; +} + +bool infrared_remote_delete_signal(InfraredRemote* remote, size_t index) { + furi_assert(index < infrared_remote_get_signal_count(remote)); + + const InfraredBatchTarget delete_target = { + .signal_index = index, + .signal_name = NULL, + .signal = NULL, + }; + + return infrared_remote_batch_start( + remote, infrared_remote_delete_signal_callback, &delete_target); +} + +bool infrared_remote_move_signal(InfraredRemote* remote, size_t index, size_t new_index) { + const size_t signal_count = infrared_remote_get_signal_count(remote); + furi_assert(index < signal_count); + furi_assert(new_index < signal_count); + + if(index == new_index) return true; + + InfraredSignal* signal = infrared_signal_alloc(); + char* signal_name = strdup(infrared_remote_get_signal_name(remote, index)); + + bool success = false; + + do { + if(!infrared_remote_load_signal(remote, signal, index)) break; + if(!infrared_remote_delete_signal(remote, index)) break; + if(!infrared_remote_insert_signal(remote, signal, signal_name, new_index)) break; + + success = true; + } while(false); + + free(signal_name); + infrared_signal_free(signal); + + return success; +} + +bool infrared_remote_create(InfraredRemote* remote, const char* path) { + FURI_LOG_I(TAG, "Creating new file: '%s'", path); + + infrared_remote_reset(remote); + infrared_remote_set_path(remote, path); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_file_alloc(storage); + + bool success = false; + + do { + if(!flipper_format_file_open_always(ff, path)) break; + if(!flipper_format_write_header_cstr(ff, INFRARED_FILE_HEADER, INFRARED_FILE_VERSION)) + break; + + success = true; + } while(false); + + flipper_format_free(ff); + furi_record_close(RECORD_STORAGE); + + return success; +} + +bool infrared_remote_load(InfraredRemote* remote, const char* path) { + FURI_LOG_I(TAG, "Loading file: '%s'", path); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + + FuriString* tmp = furi_string_alloc(); + bool success = false; + + do { + if(!flipper_format_buffered_file_open_existing(ff, path)) break; + + uint32_t version; + if(!flipper_format_read_header(ff, tmp, &version)) break; + + if(!furi_string_equal(tmp, INFRARED_FILE_HEADER) || (version != INFRARED_FILE_VERSION)) + break; + + infrared_remote_set_path(remote, path); + StringArray_reset(remote->signal_names); + + while(infrared_signal_read_name(ff, tmp)) { + StringArray_push_back(remote->signal_names, furi_string_get_cstr(tmp)); + } + + success = true; + } while(false); + + furi_string_free(tmp); + flipper_format_free(ff); + furi_record_close(RECORD_STORAGE); + + return success; +} + +bool infrared_remote_rename(InfraredRemote* remote, const char* new_path) { + const char* old_path = infrared_remote_get_path(remote); + + Storage* storage = furi_record_open(RECORD_STORAGE); + const FS_Error status = storage_common_rename(storage, old_path, new_path); + furi_record_close(RECORD_STORAGE); + + const bool success = (status == FSE_OK || status == FSE_EXIST); + + if(success) { + infrared_remote_set_path(remote, new_path); + } + return success; } bool infrared_remote_remove(InfraredRemote* remote) { Storage* storage = furi_record_open(RECORD_STORAGE); - - FS_Error status = storage_common_remove(storage, furi_string_get_cstr(remote->path)); - infrared_remote_reset(remote); - + const FS_Error status = storage_common_remove(storage, infrared_remote_get_path(remote)); furi_record_close(RECORD_STORAGE); - return (status == FSE_OK || status == FSE_NOT_EXIST); + + const bool success = (status == FSE_OK || status == FSE_NOT_EXIST); + + if(success) { + infrared_remote_reset(remote); + } + + return success; } diff --git a/applications/main/infrared/infrared_remote.h b/applications/main/infrared/infrared_remote.h index 47aa77e2ef..7477cd3b5a 100644 --- a/applications/main/infrared/infrared_remote.h +++ b/applications/main/infrared/infrared_remote.h @@ -1,30 +1,229 @@ +/** + * @file infrared_remote.h + * @brief Infrared remote library. + * + * An infrared remote contains zero or more infrared signals which + * have a (possibly non-unique) name each. + * + * The current implementation does load only the names into the memory, + * while the signals themselves are loaded on-demand one by one. In theory, + * this should allow for quite large remotes with relatively bulky signals. + */ #pragma once -#include - -#include "infrared_remote_button.h" +#include "infrared_signal.h" +/** + * @brief InfraredRemote opaque type declaration. + */ typedef struct InfraredRemote InfraredRemote; +/** + * @brief Create a new InfraredRemote instance. + * + * @returns pointer to the created instance. + */ InfraredRemote* infrared_remote_alloc(); + +/** + * @brief Delete an InfraredRemote instance. + * + * @param[in,out] remote pointer to the instance to be deleted. + */ void infrared_remote_free(InfraredRemote* remote); + +/** + * @brief Reset an InfraredRemote instance. + * + * Resetting a remote clears its signal name list and + * the associated file path. + * + * @param[in,out] remote pointer to the instance to be deleted. + */ void infrared_remote_reset(InfraredRemote* remote); -void infrared_remote_set_name(InfraredRemote* remote, const char* name); -const char* infrared_remote_get_name(InfraredRemote* remote); +/** + * @brief Get an InfraredRemote instance's name. + * + * The name is deduced from the file path. + * + * The return value remains valid unless one of the following functions is called: + * - infrared_remote_reset() + * - infrared_remote_load() + * - infrared_remote_create() + * + * @param[in] remote pointer to the instance to be queried. + * @returns pointer to a zero-terminated string containing the name. + */ +const char* infrared_remote_get_name(const InfraredRemote* remote); -void infrared_remote_set_path(InfraredRemote* remote, const char* path); -const char* infrared_remote_get_path(InfraredRemote* remote); +/** + * @brief Get an InfraredRemote instance's file path. + * + * Same return value validity considerations as infrared_remote_get_name(). + * + * @param[in] remote pointer to the instance to be queried. + * @returns pointer to a zero-terminated string containing the path. + */ +const char* infrared_remote_get_path(const InfraredRemote* remote); -size_t infrared_remote_get_button_count(InfraredRemote* remote); -InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t index); -bool infrared_remote_find_button_by_name(InfraredRemote* remote, const char* name, size_t* index); +/** + * @brief Get the number of signals listed in an InfraredRemote instance. + * + * @param[in] remote pointer to the instance to be queried. + * @returns number of signals, zero or more + */ +size_t infrared_remote_get_signal_count(const InfraredRemote* remote); -bool infrared_remote_add_button(InfraredRemote* remote, const char* name, InfraredSignal* signal); -bool infrared_remote_rename_button(InfraredRemote* remote, const char* new_name, size_t index); -bool infrared_remote_delete_button(InfraredRemote* remote, size_t index); -void infrared_remote_move_button(InfraredRemote* remote, size_t index_orig, size_t index_dest); +/** + * @brief Get the name of a signal listed in an InfraredRemote instance. + * + * @param[in] remote pointer to the instance to be queried. + * @param[in] index index of the signal in question. Must be less than the total signal count. + */ +const char* infrared_remote_get_signal_name(const InfraredRemote* remote, size_t index); -bool infrared_remote_store(InfraredRemote* remote); -bool infrared_remote_load(InfraredRemote* remote, FuriString* path); +/** + * @brief Get the index of a signal listed in an InfraredRemote instance by its name. + * + * @param[in] remote pointer to the instance to be queried. + * @param[in] name pointer to a zero-terminated string containig the name of the signal in question. + * @param[out] index pointer to the variable to hold the signal index. + * @returns true if a signal with the given name was found, false otherwise. + */ +bool infrared_remote_get_signal_index( + const InfraredRemote* remote, + const char* name, + size_t* index); + +/** + * @brief Load a signal listed in an InfraredRemote instance. + * + * As mentioned above, the signals are loaded on-demand. The user code must call this function + * each time it wants to interact with a new signal. + * + * @param[in] remote pointer to the instance to load from. + * @param[out] signal pointer to the signal to load into. Must be allocated. + * @param[in] index index of the signal to be loaded. Must be less than the total signal count. + * @return true if the signal was successfully loaded, false otherwise. + */ +bool infrared_remote_load_signal( + const InfraredRemote* remote, + InfraredSignal* signal, + size_t index); + +/** + * @brief Append a signal to the file associated with an InfraredRemote instance. + * + * The file path must be somehow initialised first by calling either infrared_remote_load() or + * infrared_remote_create(). As the name suggests, the signal will be put in the end of the file. + * + * @param[in,out] remote pointer to the instance to append to. + * @param[in] signal pointer to the signal to be appended. + * @param[in] name pointer to a zero-terminated string containing the name of the signal. + * @returns true if the signal was successfully appended, false otherwise. + */ +bool infrared_remote_append_signal( + InfraredRemote* remote, + const InfraredSignal* signal, + const char* name); + +/** + * @brief Insert a signal to the file associated with an InfraredRemote instance. + * + * Same behaviour as infrared_remote_append_signal(), but the user code can decide where to + * put the signal in the file. + * + * Index values equal to or greater than the total signal count will result in behaviour + * identical to infrared_remote_append_signal(). + * + * @param[in,out] remote pointer to the instance to insert to. + * @param[in] signal pointer to the signal to be inserted. + * @param[in] name pointer to a zero-terminated string containing the name of the signal. + * @param[in] index the index under which the signal shall be inserted. + * @returns true if the signal was successfully inserted, false otherwise. + */ +bool infrared_remote_insert_signal( + InfraredRemote* remote, + const InfraredSignal* signal, + const char* name, + size_t index); + +/** + * @brief Rename a signal in the file associated with an InfraredRemote instance. + * + * Only changes the signal's name, but neither its position nor contents. + * + * @param[in,out] remote pointer to the instance to be modified. + * @param[in] index index of the signal to be renamed. Must be less than the total signal count. + * @param[in] new_name pointer to a zero-terminated string containig the signal's new name. + * @returns true if the signal was successfully renamed, false otherwise. + */ +bool infrared_remote_rename_signal(InfraredRemote* remote, size_t index, const char* new_name); + +/** + * @brief Change a signal's position in the file associated with an InfraredRemote instance. + * + * Only changes the signal's position (index), but neither its name nor contents. + * + * @param[in,out] remote pointer to the instance to be modified. + * @param[in] index index of the signal to be moved. Must be less than the total signal count. + * @param[in] new_index index of the signal to be moved. Must be less than the total signal count. + */ +bool infrared_remote_move_signal(InfraredRemote* remote, size_t index, size_t new_index); + +/** + * @brief Delete a signal in the file associated with an InfraredRemote instance. + * + * @param[in,out] remote pointer to the instance to be modified. + * @param[in] index index of the signal to be deleted. Must be less than the total signal count. + * @returns true if the signal was successfully deleted, false otherwise. + */ +bool infrared_remote_delete_signal(InfraredRemote* remote, size_t index); + +/** + * @brief Create a new file and associate it with an InfraredRemote instance. + * + * The instance will be reset and given a new empty file with just the header. + * + * @param[in,out] remote pointer to the instance to be assigned with a new file. + * @param[in] path pointer to a zero-terminated string containing the full file path. + * @returns true if the file was successfully created, false otherwise. + */ +bool infrared_remote_create(InfraredRemote* remote, const char* path); + +/** + * @brief Associate an InfraredRemote instance with a file and load the signal names from it. + * + * The instance will be reset and fill its signal name list from the given file. + * The file must already exist and be valid. + * + * @param[in,out] remote pointer to the instance to be assigned with an existing file. + * @param[in] path pointer to a zero-terminated string containing the full file path. + * @returns true if the file was successfully loaded, false otherwise. + */ +bool infrared_remote_load(InfraredRemote* remote, const char* path); + +/** + * @brief Rename the file associated with an InfraredRemote instance. + * + * Only renames the file, no signals are added, moved or deleted. + * + * @param[in,out] remote pointer to the instance to be modified. + * @param[in] new_path pointer to a zero-terminated string containing the new full file path. + * @returns true if the file was successfully renamed, false otherwise. + */ +bool infrared_remote_rename(InfraredRemote* remote, const char* new_path); + +/** + * @brief Remove the file associated with an InfraredRemote instance. + * + * This operation is irreversible and fully deletes the remote file + * from the underlying filesystem. + * After calling this function, the instance becomes invalid until + * infrared_remote_create() or infrared_remote_load() are successfully executed. + * + * @param[in,out] remote pointer to the instance to be modified. + * @returns true if the file was successfully removed, false otherwise. + */ bool infrared_remote_remove(InfraredRemote* remote); diff --git a/applications/main/infrared/infrared_remote_button.c b/applications/main/infrared/infrared_remote_button.c deleted file mode 100644 index 1f6315ec52..0000000000 --- a/applications/main/infrared/infrared_remote_button.c +++ /dev/null @@ -1,37 +0,0 @@ -#include "infrared_remote_button.h" - -#include - -struct InfraredRemoteButton { - FuriString* name; - InfraredSignal* signal; -}; - -InfraredRemoteButton* infrared_remote_button_alloc() { - InfraredRemoteButton* button = malloc(sizeof(InfraredRemoteButton)); - button->name = furi_string_alloc(); - button->signal = infrared_signal_alloc(); - return button; -} - -void infrared_remote_button_free(InfraredRemoteButton* button) { - furi_string_free(button->name); - infrared_signal_free(button->signal); - free(button); -} - -void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name) { - furi_string_set(button->name, name); -} - -const char* infrared_remote_button_get_name(InfraredRemoteButton* button) { - return furi_string_get_cstr(button->name); -} - -void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal) { - infrared_signal_set_signal(button->signal, signal); -} - -InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button) { - return button->signal; -} diff --git a/applications/main/infrared/infrared_remote_button.h b/applications/main/infrared/infrared_remote_button.h deleted file mode 100644 index f25b759b56..0000000000 --- a/applications/main/infrared/infrared_remote_button.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "infrared_signal.h" - -typedef struct InfraredRemoteButton InfraredRemoteButton; - -InfraredRemoteButton* infrared_remote_button_alloc(); -void infrared_remote_button_free(InfraredRemoteButton* button); - -void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name); -const char* infrared_remote_button_get_name(InfraredRemoteButton* button); - -void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal); -InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button); diff --git a/applications/main/infrared/infrared_signal.c b/applications/main/infrared/infrared_signal.c index 9154dfbf68..c73e4db98d 100644 --- a/applications/main/infrared/infrared_signal.c +++ b/applications/main/infrared/infrared_signal.c @@ -8,6 +8,8 @@ #define TAG "InfraredSignal" +#define INFRARED_SIGNAL_NAME_KEY "name" + struct InfraredSignal { bool is_raw; union { @@ -24,7 +26,7 @@ static void infrared_signal_clear_timings(InfraredSignal* signal) { } } -static bool infrared_signal_is_message_valid(InfraredMessage* message) { +static bool infrared_signal_is_message_valid(const InfraredMessage* message) { if(!infrared_is_protocol_valid(message->protocol)) { FURI_LOG_E(TAG, "Unknown protocol"); return false; @@ -57,7 +59,7 @@ static bool infrared_signal_is_message_valid(InfraredMessage* message) { return true; } -static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) { +static bool infrared_signal_is_raw_valid(const InfraredRawSignal* raw) { if((raw->frequency > INFRARED_MAX_FREQUENCY) || (raw->frequency < INFRARED_MIN_FREQUENCY)) { FURI_LOG_E( TAG, @@ -83,7 +85,8 @@ static bool infrared_signal_is_raw_valid(InfraredRawSignal* raw) { return true; } -static inline bool infrared_signal_save_message(InfraredMessage* message, FlipperFormat* ff) { +static inline bool + infrared_signal_save_message(const InfraredMessage* message, FlipperFormat* ff) { const char* protocol_name = infrared_get_protocol_name(message->protocol); return flipper_format_write_string_cstr(ff, "type", "parsed") && flipper_format_write_string_cstr(ff, "protocol", protocol_name) && @@ -91,7 +94,7 @@ static inline bool infrared_signal_save_message(InfraredMessage* message, Flippe flipper_format_write_hex(ff, "command", (uint8_t*)&message->command, 4); } -static inline bool infrared_signal_save_raw(InfraredRawSignal* raw, FlipperFormat* ff) { +static inline bool infrared_signal_save_raw(const InfraredRawSignal* raw, FlipperFormat* ff) { furi_assert(raw->timings_size <= MAX_TIMINGS_AMOUNT); return flipper_format_write_string_cstr(ff, "type", "raw") && flipper_format_write_uint32(ff, "frequency", &raw->frequency, 1) && @@ -180,11 +183,11 @@ void infrared_signal_free(InfraredSignal* signal) { free(signal); } -bool infrared_signal_is_raw(InfraredSignal* signal) { +bool infrared_signal_is_raw(const InfraredSignal* signal) { return signal->is_raw; } -bool infrared_signal_is_valid(InfraredSignal* signal) { +bool infrared_signal_is_valid(const InfraredSignal* signal) { return signal->is_raw ? infrared_signal_is_raw_valid(&signal->payload.raw) : infrared_signal_is_message_valid(&signal->payload.message); } @@ -218,7 +221,7 @@ void infrared_signal_set_raw_signal( memcpy(signal->payload.raw.timings, timings, timings_size * sizeof(uint32_t)); } -InfraredRawSignal* infrared_signal_get_raw_signal(InfraredSignal* signal) { +const InfraredRawSignal* infrared_signal_get_raw_signal(const InfraredSignal* signal) { furi_assert(signal->is_raw); return &signal->payload.raw; } @@ -230,14 +233,14 @@ void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* signal->payload.message = *message; } -InfraredMessage* infrared_signal_get_message(InfraredSignal* signal) { +const InfraredMessage* infrared_signal_get_message(const InfraredSignal* signal) { furi_assert(!signal->is_raw); return &signal->payload.message; } -bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name) { +bool infrared_signal_save(const InfraredSignal* signal, FlipperFormat* ff, const char* name) { if(!flipper_format_write_comment_cstr(ff, "") || - !flipper_format_write_string_cstr(ff, "name", name)) { + !flipper_format_write_string_cstr(ff, INFRARED_SIGNAL_NAME_KEY, name)) { return false; } else if(signal->is_raw) { return infrared_signal_save_raw(&signal->payload.raw, ff); @@ -247,33 +250,30 @@ bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* } bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name) { - FuriString* tmp = furi_string_alloc(); - bool success = false; do { - if(!flipper_format_read_string(ff, "name", tmp)) break; - furi_string_set(name, tmp); + if(!infrared_signal_read_name(ff, name)) break; if(!infrared_signal_read_body(signal, ff)) break; - success = true; - } while(0); - furi_string_free(tmp); + success = true; //-V779 + } while(false); + return success; } -bool infrared_signal_search_and_read( - InfraredSignal* signal, - FlipperFormat* ff, - const FuriString* name) { +bool infrared_signal_read_name(FlipperFormat* ff, FuriString* name) { + return flipper_format_read_string(ff, INFRARED_SIGNAL_NAME_KEY, name); +} + +bool infrared_signal_search_and_read(InfraredSignal* signal, FlipperFormat* ff, const char* name) { bool success = false; FuriString* tmp = furi_string_alloc(); do { bool is_name_found = false; - while(flipper_format_read_string(ff, "name", tmp)) { - is_name_found = furi_string_equal(name, tmp); - if(is_name_found) break; + while(!is_name_found && infrared_signal_read_name(ff, tmp)) { //-V560 + is_name_found = furi_string_equal(tmp, name); } if(!is_name_found) break; //-V547 if(!infrared_signal_read_body(signal, ff)) break; //-V779 @@ -284,9 +284,9 @@ bool infrared_signal_search_and_read( return success; } -void infrared_signal_transmit(InfraredSignal* signal) { +void infrared_signal_transmit(const InfraredSignal* signal) { if(signal->is_raw) { - InfraredRawSignal* raw_signal = &signal->payload.raw; + const InfraredRawSignal* raw_signal = &signal->payload.raw; infrared_send_raw_ext( raw_signal->timings, raw_signal->timings_size, @@ -294,7 +294,7 @@ void infrared_signal_transmit(InfraredSignal* signal) { raw_signal->frequency, raw_signal->duty_cycle); } else { - InfraredMessage* message = &signal->payload.message; + const InfraredMessage* message = &signal->payload.message; infrared_send(message, 1); } } diff --git a/applications/main/infrared/infrared_signal.h b/applications/main/infrared/infrared_signal.h index 29c6619383..fcbb3c8739 100644 --- a/applications/main/infrared/infrared_signal.h +++ b/applications/main/infrared/infrared_signal.h @@ -1,45 +1,186 @@ +/** + * @file infrared_signal.h + * @brief Infrared signal library. + * + * Infrared signals may be of two types: + * - known to the infrared signal decoder, or *parsed* signals + * - the rest, or *raw* signals, which are treated merely as a set of timings. + */ #pragma once -#include -#include -#include - -#include #include +#include +/** + * @brief InfraredSignal opaque type declaration. + */ typedef struct InfraredSignal InfraredSignal; +/** + * @brief Raw signal type definition. + * + * Measurement units used: + * - time: microseconds (uS) + * - frequency: Hertz (Hz) + * - duty_cycle: no units, fraction between 0 and 1. + */ typedef struct { - size_t timings_size; - uint32_t* timings; - uint32_t frequency; - float duty_cycle; + size_t timings_size; /**< Number of elements in the timings array. */ + uint32_t* timings; /**< Pointer to an array of timings describing the signal. */ + uint32_t frequency; /**< Carrier frequency of the signal. */ + float duty_cycle; /**< Duty cycle of the signal. */ } InfraredRawSignal; +/** + * @brief Create a new InfraredSignal instance. + * + * @returns pointer to the instance created. + */ InfraredSignal* infrared_signal_alloc(); + +/** + * @brief Delete an InfraredSignal instance. + * + * @param[in,out] signal pointer to the instance to be deleted. + */ void infrared_signal_free(InfraredSignal* signal); -bool infrared_signal_is_raw(InfraredSignal* signal); -bool infrared_signal_is_valid(InfraredSignal* signal); +/** + * @brief Test whether an InfraredSignal instance holds a raw signal. + * + * @param[in] signal pointer to the instance to be tested. + * @returns true if the instance holds a raw signal, false otherwise. + */ +bool infrared_signal_is_raw(const InfraredSignal* signal); +/** + * @brief Test whether an InfraredSignal instance holds any signal. + * + * @param[in] signal pointer to the instance to be tested. + * @returns true if the instance holds raw signal, false otherwise. + */ +bool infrared_signal_is_valid(const InfraredSignal* signal); + +/** + * @brief Set an InfraredInstance to hold the signal from another one. + * + * Any instance's previous contents will be automatically deleted before + * copying the source instance's contents. + * + * @param[in,out] signal pointer to the destination instance. + * @param[in] other pointer to the source instance. + */ void infrared_signal_set_signal(InfraredSignal* signal, const InfraredSignal* other); +/** + * @brief Set an InfraredInstance to hold a raw signal. + * + * Any instance's previous contents will be automatically deleted before + * copying the raw signal. + * + * After this call, infrared_signal_is_raw() will return true. + * + * @param[in,out] signal pointer to the destination instance. + * @param[in] timings pointer to an array containing the raw signal timings. + * @param[in] timings_size number of elements in the timings array. + * @param[in] frequency signal carrier frequency, in Hertz. + * @param[in] duty_cycle signal duty cycle, fraction between 0 and 1. + */ void infrared_signal_set_raw_signal( InfraredSignal* signal, const uint32_t* timings, size_t timings_size, uint32_t frequency, float duty_cycle); -InfraredRawSignal* infrared_signal_get_raw_signal(InfraredSignal* signal); +/** + * @brief Get the raw signal held by an InfraredSignal instance. + * + * @warning the instance MUST hold a *raw* signal, otherwise undefined behaviour will occur. + * + * @param[in] signal pointer to the instance to be queried. + * @returns pointer to the raw signal structure held by the instance. + */ +const InfraredRawSignal* infrared_signal_get_raw_signal(const InfraredSignal* signal); + +/** + * @brief Set an InfraredInstance to hold a parsed signal. + * + * Any instance's previous contents will be automatically deleted before + * copying the raw signal. + * + * After this call, infrared_signal_is_raw() will return false. + * + * @param[in,out] signal pointer to the destination instance. + * @param[in] message pointer to the message containing the parsed signal. + */ void infrared_signal_set_message(InfraredSignal* signal, const InfraredMessage* message); -InfraredMessage* infrared_signal_get_message(InfraredSignal* signal); -bool infrared_signal_save(InfraredSignal* signal, FlipperFormat* ff, const char* name); +/** + * @brief Get the parsed signal held by an InfraredSignal instance. + * + * @warning the instance MUST hold a *parsed* signal, otherwise undefined behaviour will occur. + * + * @param[in] signal pointer to the instance to be queried. + * @returns pointer to the parsed signal structure held by the instance. + */ +const InfraredMessage* infrared_signal_get_message(const InfraredSignal* signal); + +/** + * @brief Read a signal from a FlipperFormat file into an InfraredSignal instance. + * + * The file must be allocated and open prior to this call. The seek position determines + * which signal will be read (if there is more than one in the file). Calling this function + * repeatedly will result in all signals in the file to be read until no more are left. + * + * @param[in,out] signal pointer to the instance to be read into. + * @param[in,out] ff pointer to the FlipperFormat file instance to read from. + * @param[out] name pointer to the string to hold the signal name. Must be properly allocated. + * @returns true if a signal was successfully read, false otherwise (e.g. no more signals to read). + */ bool infrared_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name); -bool infrared_signal_search_and_read( - InfraredSignal* signal, - FlipperFormat* ff, - const FuriString* name); -void infrared_signal_transmit(InfraredSignal* signal); +/** + * @brief Read a signal name from a FlipperFormat file. + * + * Same behaviour as infrared_signal_read(), but only the name is read. + * + * @param[in,out] ff pointer to the FlipperFormat file instance to read from. + * @param[out] name pointer to the string to hold the signal name. Must be properly allocated. + * @returns true if a signal name was successfully read, false otherwise (e.g. no more signals to read). + */ +bool infrared_signal_read_name(FlipperFormat* ff, FuriString* name); + +/** + * @brief Read a signal with a particular name from a FlipperFormat file into an InfraredSignal instance. + * + * This function will look for a signal with the given name and if found, attempt to read it. + * Same considerations apply as to infrared_signal_read(). + * + * @param[in,out] signal pointer to the instance to be read into. + * @param[in,out] ff pointer to the FlipperFormat file instance to read from. + * @param[in] name pointer to a zero-terminated string containing the requested signal name. + * @returns true if a signal was found and successfully read, false otherwise (e.g. the signal was not found). + */ +bool infrared_signal_search_and_read(InfraredSignal* signal, FlipperFormat* ff, const char* name); + +/** + * @brief Save a signal contained in an InfraredSignal instance to a FlipperFormat file. + * + * The file must be allocated and open prior to this call. Additionally, an appropriate header + * must be already written into the file. + * + * @param[in] signal pointer to the instance holding the signal to be saved. + * @param[in,out] ff pointer to the FlipperFormat file instance to write to. + * @param[in] name pointer to a zero-terminated string contating the name of the signal. + */ +bool infrared_signal_save(const InfraredSignal* signal, FlipperFormat* ff, const char* name); + +/** + * @brief Transmit a signal contained in an InfraredSignal instance. + * + * The transmission happens once per call using the built-in hardware (via HAL calls). + * + * @param[in] signal pointer to the instance holding the signal to be transmitted. + */ +void infrared_signal_transmit(const InfraredSignal* signal); diff --git a/applications/main/infrared/scenes/common/infrared_scene_universal_common.c b/applications/main/infrared/scenes/common/infrared_scene_universal_common.c index 96f28cc489..4967d19566 100644 --- a/applications/main/infrared/scenes/common/infrared_scene_universal_common.c +++ b/applications/main/infrared/scenes/common/infrared_scene_universal_common.c @@ -1,20 +1,21 @@ -#include "../../infrared_i.h" +#include "../../infrared_app_i.h" #include void infrared_scene_universal_common_item_callback(void* context, uint32_t index) { - Infrared* infrared = context; + InfraredApp* infrared = context; uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeButtonSelected, index); view_dispatcher_send_custom_event(infrared->view_dispatcher, event); } static void infrared_scene_universal_common_progress_back_callback(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeBackPressed, -1); view_dispatcher_send_custom_event(infrared->view_dispatcher, event); } -static void infrared_scene_universal_common_show_popup(Infrared* infrared, uint32_t record_count) { +static void + infrared_scene_universal_common_show_popup(InfraredApp* infrared, uint32_t record_count) { ViewStack* view_stack = infrared->view_stack; InfraredProgressView* progress = infrared->progress; infrared_progress_view_set_progress_total(progress, record_count); @@ -24,7 +25,7 @@ static void infrared_scene_universal_common_show_popup(Infrared* infrared, uint3 infrared_play_notification_message(infrared, InfraredNotificationMessageBlinkStartSend); } -static void infrared_scene_universal_common_hide_popup(Infrared* infrared) { +static void infrared_scene_universal_common_hide_popup(InfraredApp* infrared) { ViewStack* view_stack = infrared->view_stack; InfraredProgressView* progress = infrared->progress; view_stack_remove_view(view_stack, infrared_progress_view_get_view(progress)); @@ -32,12 +33,12 @@ static void infrared_scene_universal_common_hide_popup(Infrared* infrared) { } void infrared_scene_universal_common_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; view_stack_add_view(infrared->view_stack, button_panel_get_view(infrared->button_panel)); } bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; InfraredBruteForce* brute_force = infrared->brute_force; bool consumed = false; @@ -84,7 +85,7 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e } void infrared_scene_universal_common_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; ButtonPanel* button_panel = infrared->button_panel; view_stack_remove_view(infrared->view_stack, button_panel_get_view(button_panel)); infrared_brute_force_reset(infrared->brute_force); diff --git a/applications/main/infrared/scenes/infrared_scene_ask_back.c b/applications/main/infrared/scenes/infrared_scene_ask_back.c index 77fc97f987..f97a38bb09 100644 --- a/applications/main/infrared/scenes/infrared_scene_ask_back.c +++ b/applications/main/infrared/scenes/infrared_scene_ask_back.c @@ -1,12 +1,12 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" static void infrared_scene_dialog_result_callback(DialogExResult result, void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event(infrared->view_dispatcher, result); } void infrared_scene_ask_back_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; DialogEx* dialog_ex = infrared->dialog_ex; if(infrared->app_state.is_learning_new_remote) { @@ -28,7 +28,7 @@ void infrared_scene_ask_back_on_enter(void* context) { } bool infrared_scene_ask_back_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; bool consumed = false; @@ -54,6 +54,6 @@ bool infrared_scene_ask_back_on_event(void* context, SceneManagerEvent event) { } void infrared_scene_ask_back_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; dialog_ex_reset(infrared->dialog_ex); } diff --git a/applications/main/infrared/scenes/infrared_scene_ask_retry.c b/applications/main/infrared/scenes/infrared_scene_ask_retry.c index 602e470c7c..365ed5c812 100644 --- a/applications/main/infrared/scenes/infrared_scene_ask_retry.c +++ b/applications/main/infrared/scenes/infrared_scene_ask_retry.c @@ -1,12 +1,12 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" static void infrared_scene_dialog_result_callback(DialogExResult result, void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event(infrared->view_dispatcher, result); } void infrared_scene_ask_retry_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; DialogEx* dialog_ex = infrared->dialog_ex; dialog_ex_set_header(dialog_ex, "Retry Reading?", 64, 11, AlignCenter, AlignTop); @@ -23,7 +23,7 @@ void infrared_scene_ask_retry_on_enter(void* context) { } bool infrared_scene_ask_retry_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; bool consumed = false; @@ -43,6 +43,6 @@ bool infrared_scene_ask_retry_on_event(void* context, SceneManagerEvent event) { } void infrared_scene_ask_retry_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; dialog_ex_reset(infrared->dialog_ex); } diff --git a/applications/main/infrared/scenes/infrared_scene_debug.c b/applications/main/infrared/scenes/infrared_scene_debug.c index 204978697b..adffbc83ac 100644 --- a/applications/main/infrared/scenes/infrared_scene_debug.c +++ b/applications/main/infrared/scenes/infrared_scene_debug.c @@ -1,7 +1,7 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" void infrared_scene_debug_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; InfraredWorker* worker = infrared->worker; infrared_worker_rx_set_received_signal_callback( @@ -14,16 +14,16 @@ void infrared_scene_debug_on_enter(void* context) { } bool infrared_scene_debug_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == InfraredCustomEventTypeSignalReceived) { InfraredDebugView* debug_view = infrared->debug_view; - InfraredSignal* signal = infrared->received_signal; + InfraredSignal* signal = infrared->current_signal; if(infrared_signal_is_raw(signal)) { - InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + const InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); infrared_debug_view_set_text(debug_view, "RAW\n%d samples\n", raw->timings_size); printf("RAW, %zu samples:\r\n", raw->timings_size); @@ -33,7 +33,7 @@ bool infrared_scene_debug_on_event(void* context, SceneManagerEvent event) { printf("\r\n"); } else { - InfraredMessage* message = infrared_signal_get_message(signal); + const InfraredMessage* message = infrared_signal_get_message(signal); infrared_debug_view_set_text( debug_view, "%s\nA:0x%0*lX\nC:0x%0*lX\n%s\n", @@ -61,7 +61,7 @@ bool infrared_scene_debug_on_event(void* context, SceneManagerEvent event) { } void infrared_scene_debug_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; InfraredWorker* worker = infrared->worker; infrared_worker_rx_stop(worker); infrared_worker_rx_enable_blink_on_receiving(worker, false); diff --git a/applications/main/infrared/scenes/infrared_scene_edit.c b/applications/main/infrared/scenes/infrared_scene_edit.c index 02bba7a3f4..c22e953963 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit.c +++ b/applications/main/infrared/scenes/infrared_scene_edit.c @@ -1,4 +1,4 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" typedef enum { SubmenuIndexAddButton, @@ -10,12 +10,12 @@ typedef enum { } SubmenuIndex; static void infrared_scene_edit_submenu_callback(void* context, uint32_t index) { - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event(infrared->view_dispatcher, index); } void infrared_scene_edit_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Submenu* submenu = infrared->submenu; SceneManager* scene_manager = infrared->scene_manager; @@ -64,7 +64,7 @@ void infrared_scene_edit_on_enter(void* context) { } bool infrared_scene_edit_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; bool consumed = false; @@ -106,6 +106,6 @@ bool infrared_scene_edit_on_event(void* context, SceneManagerEvent event) { } void infrared_scene_edit_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; submenu_reset(infrared->submenu); } diff --git a/applications/main/infrared/scenes/infrared_scene_edit_button_select.c b/applications/main/infrared/scenes/infrared_scene_edit_button_select.c index 5f5a1d8fac..a76b4e836b 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_button_select.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_button_select.c @@ -1,12 +1,12 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" static void infrared_scene_edit_button_select_submenu_callback(void* context, uint32_t index) { - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event(infrared->view_dispatcher, index); } void infrared_scene_edit_button_select_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Submenu* submenu = infrared->submenu; InfraredRemote* remote = infrared->remote; InfraredAppState* app_state = &infrared->app_state; @@ -16,16 +16,16 @@ void infrared_scene_edit_button_select_on_enter(void* context) { "Delete Button:"; submenu_set_header(submenu, header); - const size_t button_count = infrared_remote_get_button_count(remote); + const size_t button_count = infrared_remote_get_signal_count(remote); for(size_t i = 0; i < button_count; ++i) { - InfraredRemoteButton* button = infrared_remote_get_button(remote, i); submenu_add_item( submenu, - infrared_remote_button_get_name(button), + infrared_remote_get_signal_name(remote, i), i, infrared_scene_edit_button_select_submenu_callback, context); } + if(button_count && app_state->current_button_index != InfraredButtonIndexNone) { submenu_set_selected_item(submenu, app_state->current_button_index); app_state->current_button_index = InfraredButtonIndexNone; @@ -35,7 +35,7 @@ void infrared_scene_edit_button_select_on_enter(void* context) { } bool infrared_scene_edit_button_select_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; InfraredAppState* app_state = &infrared->app_state; SceneManager* scene_manager = infrared->scene_manager; bool consumed = false; @@ -57,6 +57,6 @@ bool infrared_scene_edit_button_select_on_event(void* context, SceneManagerEvent } void infrared_scene_edit_button_select_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; submenu_reset(infrared->submenu); } diff --git a/applications/main/infrared/scenes/infrared_scene_edit_delete.c b/applications/main/infrared/scenes/infrared_scene_edit_delete.c index 4dfc054fbd..c1735da082 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_delete.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_delete.c @@ -1,42 +1,49 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" static void infrared_scene_edit_delete_dialog_result_callback(DialogExResult result, void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event(infrared->view_dispatcher, result); } void infrared_scene_edit_delete_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; DialogEx* dialog_ex = infrared->dialog_ex; InfraredRemote* remote = infrared->remote; const InfraredEditTarget edit_target = infrared->app_state.edit_target; if(edit_target == InfraredEditTargetButton) { - int32_t current_button_index = infrared->app_state.current_button_index; - furi_assert(current_button_index != InfraredButtonIndexNone); - dialog_ex_set_header(dialog_ex, "Delete Button?", 64, 0, AlignCenter, AlignTop); - InfraredRemoteButton* current_button = - infrared_remote_get_button(remote, current_button_index); - InfraredSignal* signal = infrared_remote_button_get_signal(current_button); - if(infrared_signal_is_raw(signal)) { - const InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + const int32_t current_button_index = infrared->app_state.current_button_index; + furi_check(current_button_index != InfraredButtonIndexNone); + + if(!infrared_remote_load_signal(remote, infrared->current_signal, current_button_index)) { + infrared_show_error_message( + infrared, + "Failed to load\n\"%s\"", + infrared_remote_get_signal_name(remote, current_button_index)); + scene_manager_previous_scene(infrared->scene_manager); + return; + } + + if(infrared_signal_is_raw(infrared->current_signal)) { + const InfraredRawSignal* raw = + infrared_signal_get_raw_signal(infrared->current_signal); infrared_text_store_set( infrared, 0, - "%s\nRAW\n%ld samples", - infrared_remote_button_get_name(current_button), + "%s\nRAW\n%zu samples", + infrared_remote_get_signal_name(remote, current_button_index), raw->timings_size); } else { - const InfraredMessage* message = infrared_signal_get_message(signal); + const InfraredMessage* message = infrared_signal_get_message(infrared->current_signal); infrared_text_store_set( infrared, 0, "%s\n%s\nA=0x%0*lX C=0x%0*lX", - infrared_remote_button_get_name(current_button), + infrared_remote_get_signal_name(remote, current_button_index), infrared_get_protocol_name(message->protocol), ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4), message->address, @@ -49,9 +56,9 @@ void infrared_scene_edit_delete_on_enter(void* context) { infrared_text_store_set( infrared, 0, - "%s\n with %lu buttons", + "%s\n with %zu buttons", infrared_remote_get_name(remote), - infrared_remote_get_button_count(remote)); + infrared_remote_get_signal_count(remote)); } else { furi_assert(0); } @@ -63,11 +70,14 @@ void infrared_scene_edit_delete_on_enter(void* context) { dialog_ex_set_result_callback(dialog_ex, infrared_scene_edit_delete_dialog_result_callback); dialog_ex_set_context(dialog_ex, context); - view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationHorizontal); + view_stack_add_view(infrared->view_stack, dialog_ex_get_view(infrared->dialog_ex)); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); } bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; bool consumed = false; @@ -83,18 +93,24 @@ bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event) if(edit_target == InfraredEditTargetButton) { furi_assert(app_state->current_button_index != InfraredButtonIndexNone); - success = infrared_remote_delete_button(remote, app_state->current_button_index); + infrared_show_loading_popup(infrared, true); + success = infrared_remote_delete_signal(remote, app_state->current_button_index); + infrared_show_loading_popup(infrared, false); app_state->current_button_index = InfraredButtonIndexNone; } else if(edit_target == InfraredEditTargetRemote) { success = infrared_remote_remove(remote); app_state->current_button_index = InfraredButtonIndexNone; } else { - furi_assert(0); + furi_crash(NULL); } if(success) { scene_manager_next_scene(scene_manager, InfraredSceneEditDeleteDone); } else { + infrared_show_error_message( + infrared, + "Failed to\ndelete %s", + edit_target == InfraredEditTargetButton ? "button" : "file"); const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; scene_manager_search_and_switch_to_previous_scene_one_of( scene_manager, possible_scenes, COUNT_OF(possible_scenes)); @@ -107,6 +123,6 @@ bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event) } void infrared_scene_edit_delete_on_exit(void* context) { - Infrared* infrared = context; - UNUSED(infrared); + InfraredApp* infrared = context; + view_stack_remove_view(infrared->view_stack, dialog_ex_get_view(infrared->dialog_ex)); } diff --git a/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c b/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c index 49a299d2aa..0ee6399142 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c @@ -1,7 +1,7 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" void infrared_scene_edit_delete_done_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Popup* popup = infrared->popup; popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62); @@ -16,7 +16,7 @@ void infrared_scene_edit_delete_done_on_enter(void* context) { } bool infrared_scene_edit_delete_done_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; bool consumed = false; @@ -43,6 +43,6 @@ bool infrared_scene_edit_delete_done_on_event(void* context, SceneManagerEvent e } void infrared_scene_edit_delete_done_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; UNUSED(infrared); } diff --git a/applications/main/infrared/scenes/infrared_scene_edit_move.c b/applications/main/infrared/scenes/infrared_scene_edit_move.c index 370c352dbd..4959a83109 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_move.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_move.c @@ -1,44 +1,69 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" -static void infrared_scene_move_button(uint32_t index_old, uint32_t index_new, void* context) { - InfraredRemote* remote = context; - furi_assert(remote); - infrared_remote_move_button(remote, index_old, index_new); -} +static void infrared_scene_edit_move_button_callback( + uint32_t index_old, + uint32_t index_new, + void* context) { + InfraredApp* infrared = context; + furi_assert(infrared); -static const char* infrared_scene_get_btn_name(uint32_t index, void* context) { - InfraredRemote* remote = context; - furi_assert(remote); - InfraredRemoteButton* button = infrared_remote_get_button(remote, index); - return (infrared_remote_button_get_name(button)); + infrared->app_state.prev_button_index = index_old; + infrared->app_state.current_button_index = index_new; + + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeButtonSelected); } void infrared_scene_edit_move_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; InfraredRemote* remote = infrared->remote; - infrared_move_view_set_callback(infrared->move_view, infrared_scene_move_button); + for(size_t i = 0; i < infrared_remote_get_signal_count(remote); ++i) { + infrared_move_view_add_item( + infrared->move_view, infrared_remote_get_signal_name(remote, i)); + } - uint32_t btn_count = infrared_remote_get_button_count(remote); - infrared_move_view_list_init( - infrared->move_view, btn_count, infrared_scene_get_btn_name, remote); - infrared_move_view_list_update(infrared->move_view); + infrared_move_view_set_callback( + infrared->move_view, infrared_scene_edit_move_button_callback, infrared); - view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewMove); + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationHorizontal); + view_stack_add_view(infrared->view_stack, infrared_move_view_get_view(infrared->move_view)); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); } bool infrared_scene_edit_move_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; bool consumed = false; - UNUSED(event); - UNUSED(infrared); + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == InfraredCustomEventTypeButtonSelected) { + infrared_show_loading_popup(infrared, true); + const bool button_moved = infrared_remote_move_signal( + infrared->remote, + infrared->app_state.prev_button_index, + infrared->app_state.current_button_index); + infrared_show_loading_popup(infrared, false); + + if(!button_moved) { + infrared_show_error_message( + infrared, + "Failed to move\n\"%s\"", + infrared_remote_get_signal_name( + infrared->remote, infrared->app_state.current_button_index)); + scene_manager_search_and_switch_to_previous_scene( + infrared->scene_manager, InfraredSceneRemoteList); + } + + consumed = true; + } + } return consumed; } void infrared_scene_edit_move_on_exit(void* context) { - Infrared* infrared = context; - InfraredRemote* remote = infrared->remote; - infrared_remote_store(remote); + InfraredApp* infrared = context; + view_stack_remove_view(infrared->view_stack, infrared_move_view_get_view(infrared->move_view)); + infrared_move_view_reset(infrared->move_view); } diff --git a/applications/main/infrared/scenes/infrared_scene_edit_rename.c b/applications/main/infrared/scenes/infrared_scene_edit_rename.c index a2199215d7..e29f108651 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_rename.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_rename.c @@ -1,10 +1,10 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" #include #include void infrared_scene_edit_rename_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; InfraredRemote* remote = infrared->remote; TextInput* text_input = infrared->text_input; size_t enter_name_length = 0; @@ -14,14 +14,12 @@ void infrared_scene_edit_rename_on_enter(void* context) { text_input_set_header_text(text_input, "Name the button"); const int32_t current_button_index = infrared->app_state.current_button_index; - furi_assert(current_button_index != InfraredButtonIndexNone); + furi_check(current_button_index != InfraredButtonIndexNone); - InfraredRemoteButton* current_button = - infrared_remote_get_button(remote, current_button_index); enter_name_length = INFRARED_MAX_BUTTON_NAME_LENGTH; strncpy( infrared->text_store[0], - infrared_remote_button_get_name(current_button), + infrared_remote_get_signal_name(remote, current_button_index), enter_name_length); } else if(edit_target == InfraredEditTargetRemote) { @@ -44,7 +42,7 @@ void infrared_scene_edit_rename_on_enter(void* context) { furi_string_free(folder_path); } else { - furi_assert(0); + furi_crash(NULL); } text_input_set_result_callback( @@ -55,11 +53,14 @@ void infrared_scene_edit_rename_on_enter(void* context) { enter_name_length, false); - view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewTextInput); + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationHorizontal); + view_stack_add_view(infrared->view_stack, text_input_get_view(infrared->text_input)); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); } bool infrared_scene_edit_rename_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; InfraredRemote* remote = infrared->remote; SceneManager* scene_manager = infrared->scene_manager; InfraredAppState* app_state = &infrared->app_state; @@ -72,18 +73,24 @@ bool infrared_scene_edit_rename_on_event(void* context, SceneManagerEvent event) if(edit_target == InfraredEditTargetButton) { const int32_t current_button_index = app_state->current_button_index; furi_assert(current_button_index != InfraredButtonIndexNone); - success = infrared_remote_rename_button( - remote, infrared->text_store[0], current_button_index); + infrared_show_loading_popup(infrared, true); + success = infrared_remote_rename_signal( + remote, current_button_index, infrared->text_store[0]); + infrared_show_loading_popup(infrared, false); app_state->current_button_index = InfraredButtonIndexNone; } else if(edit_target == InfraredEditTargetRemote) { success = infrared_rename_current_remote(infrared, infrared->text_store[0]); } else { - furi_assert(0); + furi_crash(NULL); } if(success) { scene_manager_next_scene(scene_manager, InfraredSceneEditRenameDone); } else { + infrared_show_error_message( + infrared, + "Failed to\nrename %s", + edit_target == InfraredEditTargetButton ? "button" : "file"); scene_manager_search_and_switch_to_previous_scene( scene_manager, InfraredSceneRemoteList); } @@ -95,9 +102,11 @@ bool infrared_scene_edit_rename_on_event(void* context, SceneManagerEvent event) } void infrared_scene_edit_rename_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; TextInput* text_input = infrared->text_input; + view_stack_remove_view(infrared->view_stack, text_input_get_view(text_input)); + void* validator_context = text_input_get_validator_callback_context(text_input); text_input_set_validator(text_input, NULL, NULL); diff --git a/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c b/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c index 6c7096e17d..35f5159894 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_rename_done.c @@ -1,7 +1,7 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" void infrared_scene_edit_rename_done_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Popup* popup = infrared->popup; popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); @@ -16,7 +16,7 @@ void infrared_scene_edit_rename_done_on_enter(void* context) { } bool infrared_scene_edit_rename_done_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -33,6 +33,6 @@ bool infrared_scene_edit_rename_done_on_event(void* context, SceneManagerEvent e } void infrared_scene_edit_rename_done_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; UNUSED(infrared); } diff --git a/applications/main/infrared/scenes/infrared_scene_error_databases.c b/applications/main/infrared/scenes/infrared_scene_error_databases.c index 4ed4dee583..f51f83f25f 100644 --- a/applications/main/infrared/scenes/infrared_scene_error_databases.c +++ b/applications/main/infrared/scenes/infrared_scene_error_databases.c @@ -1,7 +1,7 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" void infrared_scene_error_databases_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Popup* popup = infrared->popup; popup_set_icon(popup, 5, 11, &I_SDQuestion_35x43); @@ -16,7 +16,7 @@ void infrared_scene_error_databases_on_enter(void* context) { } bool infrared_scene_error_databases_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -31,7 +31,7 @@ bool infrared_scene_error_databases_on_event(void* context, SceneManagerEvent ev } void infrared_scene_error_databases_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; popup_reset(infrared->popup); infrared_play_notification_message(infrared, InfraredNotificationMessageYellowOff); } diff --git a/applications/main/infrared/scenes/infrared_scene_learn.c b/applications/main/infrared/scenes/infrared_scene_learn.c index 46646c6d69..bcd0a2cd0f 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn.c +++ b/applications/main/infrared/scenes/infrared_scene_learn.c @@ -1,8 +1,8 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" #include void infrared_scene_learn_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Popup* popup = infrared->popup; InfraredWorker* worker = infrared->worker; @@ -21,7 +21,7 @@ void infrared_scene_learn_on_enter(void* context) { } bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -37,7 +37,7 @@ bool infrared_scene_learn_on_event(void* context, SceneManagerEvent event) { } void infrared_scene_learn_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Popup* popup = infrared->popup; infrared_worker_rx_set_received_signal_callback(infrared->worker, NULL, NULL); infrared_worker_rx_stop(infrared->worker); diff --git a/applications/main/infrared/scenes/infrared_scene_learn_done.c b/applications/main/infrared/scenes/infrared_scene_learn_done.c index 54b7da7247..b4eb38331d 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_done.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_done.c @@ -1,7 +1,7 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" void infrared_scene_learn_done_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Popup* popup = infrared->popup; popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); @@ -21,7 +21,7 @@ void infrared_scene_learn_done_on_enter(void* context) { } bool infrared_scene_learn_done_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -38,7 +38,7 @@ bool infrared_scene_learn_done_on_event(void* context, SceneManagerEvent event) } void infrared_scene_learn_done_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; infrared->app_state.is_learning_new_remote = false; popup_set_header(infrared->popup, NULL, 0, 0, AlignLeft, AlignTop); } diff --git a/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c b/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c index 104a4cb7b6..be46a86916 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_enter_name.c @@ -1,16 +1,16 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" #include void infrared_scene_learn_enter_name_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; TextInput* text_input = infrared->text_input; - InfraredSignal* signal = infrared->received_signal; + InfraredSignal* signal = infrared->current_signal; if(infrared_signal_is_raw(signal)) { - InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); - infrared_text_store_set(infrared, 0, "RAW_%d", raw->timings_size); + const InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + infrared_text_store_set(infrared, 0, "RAW_%zu", raw->timings_size); } else { - InfraredMessage* message = infrared_signal_get_message(signal); + const InfraredMessage* message = infrared_signal_get_message(signal); infrared_text_store_set( infrared, 0, @@ -28,31 +28,32 @@ void infrared_scene_learn_enter_name_on_enter(void* context) { infrared->text_store[0], INFRARED_MAX_BUTTON_NAME_LENGTH, true); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewTextInput); } bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; - InfraredSignal* signal = infrared->received_signal; + InfraredApp* infrared = context; + InfraredSignal* signal = infrared->current_signal; SceneManager* scene_manager = infrared->scene_manager; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == InfraredCustomEventTypeTextEditDone) { - bool success = false; - if(infrared->app_state.is_learning_new_remote) { - success = - infrared_add_remote_with_button(infrared, infrared->text_store[0], signal); - } else { - success = - infrared_remote_add_button(infrared->remote, infrared->text_store[0], signal); - } + const char* signal_name = infrared->text_store[0]; + const bool success = + infrared->app_state.is_learning_new_remote ? + infrared_add_remote_with_button(infrared, signal_name, signal) : + infrared_remote_append_signal(infrared->remote, signal, signal_name); if(success) { scene_manager_next_scene(scene_manager, InfraredSceneLearnDone); dolphin_deed(DolphinDeedIrSave); } else { - dialog_message_show_storage_error(infrared->dialogs, "Failed to save file"); + infrared_show_error_message( + infrared, + "Failed to\n%s", + infrared->app_state.is_learning_new_remote ? "create file" : "add signal"); const uint32_t possible_scenes[] = {InfraredSceneRemoteList, InfraredSceneStart}; scene_manager_search_and_switch_to_previous_scene_one_of( scene_manager, possible_scenes, COUNT_OF(possible_scenes)); @@ -65,6 +66,6 @@ bool infrared_scene_learn_enter_name_on_event(void* context, SceneManagerEvent e } void infrared_scene_learn_enter_name_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; UNUSED(infrared); } diff --git a/applications/main/infrared/scenes/infrared_scene_learn_success.c b/applications/main/infrared/scenes/infrared_scene_learn_success.c index 469d4de9e4..deb54bb5ef 100644 --- a/applications/main/infrared/scenes/infrared_scene_learn_success.c +++ b/applications/main/infrared/scenes/infrared_scene_learn_success.c @@ -1,26 +1,26 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" static void infrared_scene_learn_success_dialog_result_callback(DialogExResult result, void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event(infrared->view_dispatcher, result); } void infrared_scene_learn_success_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; DialogEx* dialog_ex = infrared->dialog_ex; - InfraredSignal* signal = infrared->received_signal; + InfraredSignal* signal = infrared->current_signal; infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOn); if(infrared_signal_is_raw(signal)) { - InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); + const InfraredRawSignal* raw = infrared_signal_get_raw_signal(signal); dialog_ex_set_header(dialog_ex, "Unknown", 95, 10, AlignCenter, AlignCenter); - infrared_text_store_set(infrared, 0, "%d samples", raw->timings_size); + infrared_text_store_set(infrared, 0, "%zu samples", raw->timings_size); dialog_ex_set_text(dialog_ex, infrared->text_store[0], 75, 23, AlignLeft, AlignTop); } else { - InfraredMessage* message = infrared_signal_get_message(signal); + const InfraredMessage* message = infrared_signal_get_message(signal); uint8_t addr_digits = ROUND_UP_TO(infrared_get_protocol_address_length(message->protocol), 4); uint8_t cmd_digits = @@ -56,7 +56,7 @@ void infrared_scene_learn_success_on_enter(void* context) { } bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; const bool is_transmitter_idle = !infrared->app_state.is_transmitting; bool consumed = false; @@ -84,7 +84,7 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even consumed = true; } else if(event.event == DialogExPressCenter) { infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); - infrared_tx_start_received(infrared); + infrared_tx_start(infrared); consumed = true; } else if(event.event == DialogExReleaseCenter) { infrared_tx_stop(infrared); @@ -96,7 +96,7 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even } void infrared_scene_learn_success_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; dialog_ex_reset(infrared->dialog_ex); infrared_play_notification_message(infrared, InfraredNotificationMessageGreenOff); } diff --git a/applications/main/infrared/scenes/infrared_scene_remote.c b/applications/main/infrared/scenes/infrared_scene_remote.c index c1f5b6627c..5974acbfec 100644 --- a/applications/main/infrared/scenes/infrared_scene_remote.c +++ b/applications/main/infrared/scenes/infrared_scene_remote.c @@ -1,4 +1,4 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" typedef enum { ButtonIndexPlus = -2, @@ -8,7 +8,7 @@ typedef enum { static void infrared_scene_remote_button_menu_callback(void* context, int32_t index, InputType type) { - Infrared* infrared = context; + InfraredApp* infrared = context; uint16_t custom_type; if(type == InputTypePress) { @@ -26,17 +26,15 @@ static void } void infrared_scene_remote_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; InfraredRemote* remote = infrared->remote; ButtonMenu* button_menu = infrared->button_menu; SceneManager* scene_manager = infrared->scene_manager; - size_t button_count = infrared_remote_get_button_count(remote); - for(size_t i = 0; i < button_count; ++i) { - InfraredRemoteButton* button = infrared_remote_get_button(remote, i); + for(size_t i = 0; i < infrared_remote_get_signal_count(remote); ++i) { button_menu_add_item( button_menu, - infrared_remote_button_get_name(button), + infrared_remote_get_signal_name(remote, i), i, infrared_scene_remote_button_menu_callback, ButtonMenuItemTypeCommon, @@ -68,7 +66,7 @@ void infrared_scene_remote_on_enter(void* context) { } bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; const bool is_transmitter_idle = !infrared->app_state.is_transmitting; bool consumed = false; @@ -116,6 +114,6 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { } void infrared_scene_remote_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; button_menu_reset(infrared->button_menu); } diff --git a/applications/main/infrared/scenes/infrared_scene_remote_list.c b/applications/main/infrared/scenes/infrared_scene_remote_list.c index 55f14416bf..2276e270a0 100644 --- a/applications/main/infrared/scenes/infrared_scene_remote_list.c +++ b/applications/main/infrared/scenes/infrared_scene_remote_list.c @@ -1,31 +1,34 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" void infrared_scene_remote_list_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; ViewDispatcher* view_dispatcher = infrared->view_dispatcher; + view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); + view_dispatcher_switch_to_view(view_dispatcher, InfraredViewStack); + DialogsFileBrowserOptions browser_options; dialog_file_browser_set_basic_options(&browser_options, INFRARED_APP_EXTENSION, &I_ir_10px); browser_options.base_path = INFRARED_APP_FOLDER; - bool success = dialog_file_browser_show( - infrared->dialogs, infrared->file_path, infrared->file_path, &browser_options); - - if(success) { - view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); - view_dispatcher_switch_to_view(view_dispatcher, InfraredViewStack); + while(dialog_file_browser_show( + infrared->dialogs, infrared->file_path, infrared->file_path, &browser_options)) { + const char* file_path = furi_string_get_cstr(infrared->file_path); infrared_show_loading_popup(infrared, true); - success = infrared_remote_load(infrared->remote, infrared->file_path); + const bool remote_loaded = infrared_remote_load(infrared->remote, file_path); infrared_show_loading_popup(infrared, false); + + if(remote_loaded) { + scene_manager_next_scene(scene_manager, InfraredSceneRemote); + return; + } else { + infrared_show_error_message(infrared, "Failed to load\n\"%s\"", file_path); + } } - if(success) { - scene_manager_next_scene(scene_manager, InfraredSceneRemote); - } else { - scene_manager_previous_scene(scene_manager); - } + scene_manager_previous_scene(scene_manager); } bool infrared_scene_remote_list_on_event(void* context, SceneManagerEvent event) { diff --git a/applications/main/infrared/scenes/infrared_scene_rpc.c b/applications/main/infrared/scenes/infrared_scene_rpc.c index 04f17416d9..fa5a599afa 100644 --- a/applications/main/infrared/scenes/infrared_scene_rpc.c +++ b/applications/main/infrared/scenes/infrared_scene_rpc.c @@ -1,4 +1,4 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" #include typedef enum { @@ -8,7 +8,7 @@ typedef enum { } InfraredRpcState; void infrared_scene_rpc_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Popup* popup = infrared->popup; popup_set_header(popup, "Infrared", 89, 42, AlignCenter, AlignBottom); @@ -27,7 +27,7 @@ void infrared_scene_rpc_on_enter(void* context) { } bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -43,7 +43,8 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); if(arg && (state == InfraredRpcStateIdle)) { furi_string_set(infrared->file_path, arg); - result = infrared_remote_load(infrared->remote, infrared->file_path); + result = infrared_remote_load( + infrared->remote, furi_string_get_cstr(infrared->file_path)); if(result) { scene_manager_set_scene_state( infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded); @@ -61,7 +62,7 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); if(arg && (state == InfraredRpcStateLoaded)) { size_t button_index = 0; - if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) { + if(infrared_remote_get_signal_index(infrared->remote, arg, &button_index)) { infrared_tx_start_button_index(infrared, button_index); result = true; scene_manager_set_scene_state( @@ -91,7 +92,7 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { } void infrared_scene_rpc_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; if(scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneRpc) == InfraredRpcStateSending) { infrared_tx_stop(infrared); diff --git a/applications/main/infrared/scenes/infrared_scene_start.c b/applications/main/infrared/scenes/infrared_scene_start.c index c7df0f45ba..0e23bb7b8c 100644 --- a/applications/main/infrared/scenes/infrared_scene_start.c +++ b/applications/main/infrared/scenes/infrared_scene_start.c @@ -1,4 +1,4 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" enum SubmenuIndex { SubmenuIndexUniversalRemotes, @@ -8,12 +8,12 @@ enum SubmenuIndex { }; static void infrared_scene_start_submenu_callback(void* context, uint32_t index) { - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event(infrared->view_dispatcher, index); } void infrared_scene_start_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Submenu* submenu = infrared->submenu; SceneManager* scene_manager = infrared->scene_manager; @@ -50,7 +50,7 @@ void infrared_scene_start_on_enter(void* context) { } bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; bool consumed = false; @@ -79,6 +79,6 @@ bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) { } void infrared_scene_start_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; submenu_reset(infrared->submenu); } diff --git a/applications/main/infrared/scenes/infrared_scene_universal.c b/applications/main/infrared/scenes/infrared_scene_universal.c index e09abde70e..197478e334 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal.c +++ b/applications/main/infrared/scenes/infrared_scene_universal.c @@ -1,4 +1,4 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" typedef enum { SubmenuIndexUniversalTV, @@ -8,12 +8,12 @@ typedef enum { } SubmenuIndex; static void infrared_scene_universal_submenu_callback(void* context, uint32_t index) { - Infrared* infrared = context; + InfraredApp* infrared = context; view_dispatcher_send_custom_event(infrared->view_dispatcher, index); } void infrared_scene_universal_on_enter(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; Submenu* submenu = infrared->submenu; submenu_add_item( @@ -47,7 +47,7 @@ void infrared_scene_universal_on_enter(void* context) { } bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { - Infrared* infrared = context; + InfraredApp* infrared = context; SceneManager* scene_manager = infrared->scene_manager; bool consumed = false; @@ -72,6 +72,6 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { } void infrared_scene_universal_on_exit(void* context) { - Infrared* infrared = context; + InfraredApp* infrared = context; submenu_reset(infrared->submenu); } diff --git a/applications/main/infrared/scenes/infrared_scene_universal_ac.c b/applications/main/infrared/scenes/infrared_scene_universal_ac.c index 5f762d122f..764a951890 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_ac.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_ac.c @@ -1,11 +1,11 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" #include "common/infrared_scene_universal_common.h" void infrared_scene_universal_ac_on_enter(void* context) { infrared_scene_universal_common_on_enter(context); - Infrared* infrared = context; + InfraredApp* infrared = context; ButtonPanel* button_panel = infrared->button_panel; InfraredBruteForce* brute_force = infrared->brute_force; diff --git a/applications/main/infrared/scenes/infrared_scene_universal_audio.c b/applications/main/infrared/scenes/infrared_scene_universal_audio.c index 3938b6080d..241a22bcbb 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_audio.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_audio.c @@ -1,11 +1,11 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" #include "common/infrared_scene_universal_common.h" void infrared_scene_universal_audio_on_enter(void* context) { infrared_scene_universal_common_on_enter(context); - Infrared* infrared = context; + InfraredApp* infrared = context; ButtonPanel* button_panel = infrared->button_panel; InfraredBruteForce* brute_force = infrared->brute_force; diff --git a/applications/main/infrared/scenes/infrared_scene_universal_projector.c b/applications/main/infrared/scenes/infrared_scene_universal_projector.c index 27ca46ea9d..d8520deb39 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_projector.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_projector.c @@ -1,11 +1,11 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" #include "common/infrared_scene_universal_common.h" void infrared_scene_universal_projector_on_enter(void* context) { infrared_scene_universal_common_on_enter(context); - Infrared* infrared = context; + InfraredApp* infrared = context; ButtonPanel* button_panel = infrared->button_panel; InfraredBruteForce* brute_force = infrared->brute_force; diff --git a/applications/main/infrared/scenes/infrared_scene_universal_tv.c b/applications/main/infrared/scenes/infrared_scene_universal_tv.c index f2958d887d..6031205f55 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_tv.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_tv.c @@ -1,11 +1,11 @@ -#include "../infrared_i.h" +#include "../infrared_app_i.h" #include "common/infrared_scene_universal_common.h" void infrared_scene_universal_tv_on_enter(void* context) { infrared_scene_universal_common_on_enter(context); - Infrared* infrared = context; + InfraredApp* infrared = context; ButtonPanel* button_panel = infrared->button_panel; InfraredBruteForce* brute_force = infrared->brute_force; diff --git a/applications/main/infrared/views/infrared_move_view.c b/applications/main/infrared/views/infrared_move_view.c index d838a5f828..374a65a44e 100644 --- a/applications/main/infrared/views/infrared_move_view.c +++ b/applications/main/infrared/views/infrared_move_view.c @@ -1,10 +1,11 @@ #include "infrared_move_view.h" +#include + #include #include -#include -#include +#include #define LIST_ITEMS 4U #define LIST_LINE_H 13U @@ -13,42 +14,41 @@ struct InfraredMoveView { View* view; - InfraredMoveCallback move_cb; - void* cb_context; + InfraredMoveCallback callback; + void* callback_context; }; -typedef struct { - const char** btn_names; - uint32_t btn_number; - int32_t list_offset; - int32_t item_idx; - bool is_moving; +ARRAY_DEF(InfraredMoveViewItemArray, const char*, M_CSTR_DUP_OPLIST); //-V575 - InfraredMoveGetItemCallback get_item_cb; +typedef struct { + InfraredMoveViewItemArray_t labels; + int32_t list_offset; + int32_t current_idx; + int32_t start_idx; + bool is_moving; } InfraredMoveViewModel; static void infrared_move_view_draw_callback(Canvas* canvas, void* _model) { InfraredMoveViewModel* model = _model; - UNUSED(model); - canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontPrimary); elements_multiline_text_aligned( canvas, canvas_width(canvas) / 2, 0, AlignCenter, AlignTop, "Select a button to move"); - bool show_scrollbar = model->btn_number > LIST_ITEMS; + const size_t btn_number = InfraredMoveViewItemArray_size(model->labels); + const bool show_scrollbar = btn_number > LIST_ITEMS; canvas_set_font(canvas, FontSecondary); - for(uint32_t i = 0; i < MIN(model->btn_number, LIST_ITEMS); i++) { - int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->btn_number, 0u); - uint8_t x_offset = (model->is_moving && model->item_idx == idx) ? MOVE_X_OFFSET : 0; + for(uint32_t i = 0; i < MIN(btn_number, LIST_ITEMS); i++) { + int32_t idx = CLAMP((uint32_t)(i + model->list_offset), btn_number, 0U); + uint8_t x_offset = (model->is_moving && model->current_idx == idx) ? MOVE_X_OFFSET : 0; uint8_t y_offset = HEADER_H + i * LIST_LINE_H; uint8_t box_end_x = canvas_width(canvas) - (show_scrollbar ? 6 : 1); canvas_set_color(canvas, ColorBlack); - if(model->item_idx == idx) { + if(model->current_idx == idx) { canvas_draw_box(canvas, x_offset, y_offset, box_end_x - x_offset, LIST_LINE_H); canvas_set_color(canvas, ColorWhite); @@ -60,7 +60,12 @@ static void infrared_move_view_draw_callback(Canvas* canvas, void* _model) { canvas_draw_dot(canvas, box_end_x - 1, y_offset + LIST_LINE_H - 1); } canvas_draw_str_aligned( - canvas, x_offset + 3, y_offset + 3, AlignLeft, AlignTop, model->btn_names[idx]); + canvas, + x_offset + 3, + y_offset + 3, + AlignLeft, + AlignTop, + *InfraredMoveViewItemArray_cget(model->labels, idx)); } if(show_scrollbar) { @@ -69,22 +74,22 @@ static void infrared_move_view_draw_callback(Canvas* canvas, void* _model) { canvas_width(canvas), HEADER_H, canvas_height(canvas) - HEADER_H, - model->item_idx, - model->btn_number); + model->current_idx, + btn_number); } } static void update_list_offset(InfraredMoveViewModel* model) { - int32_t bounds = model->btn_number > (LIST_ITEMS - 1) ? 2 : model->btn_number; + const size_t btn_number = InfraredMoveViewItemArray_size(model->labels); + const int32_t bounds = btn_number > (LIST_ITEMS - 1) ? 2 : btn_number; - if((model->btn_number > (LIST_ITEMS - 1)) && - (model->item_idx >= ((int32_t)model->btn_number - 1))) { - model->list_offset = model->item_idx - (LIST_ITEMS - 1); - } else if(model->list_offset < model->item_idx - bounds) { - model->list_offset = CLAMP( - model->item_idx - (int32_t)(LIST_ITEMS - 2), (int32_t)model->btn_number - bounds, 0); - } else if(model->list_offset > model->item_idx - bounds) { - model->list_offset = CLAMP(model->item_idx - 1, (int32_t)model->btn_number - bounds, 0); + if((btn_number > (LIST_ITEMS - 1)) && (model->current_idx >= ((int32_t)btn_number - 1))) { + model->list_offset = model->current_idx - (LIST_ITEMS - 1); + } else if(model->list_offset < model->current_idx - bounds) { + model->list_offset = + CLAMP(model->current_idx - (int32_t)(LIST_ITEMS - 2), (int32_t)btn_number - bounds, 0); + } else if(model->list_offset > model->current_idx - bounds) { + model->list_offset = CLAMP(model->current_idx - 1, (int32_t)btn_number - bounds, 0); } } @@ -95,117 +100,130 @@ static bool infrared_move_view_input_callback(InputEvent* event, void* context) if(((event->type == InputTypeShort || event->type == InputTypeRepeat)) && ((event->key == InputKeyUp) || (event->key == InputKeyDown))) { - bool is_moving = false; - uint32_t index_old = 0; - uint32_t index_new = 0; with_view_model( move_view->view, InfraredMoveViewModel * model, { - is_moving = model->is_moving; - index_old = model->item_idx; + const size_t btn_number = InfraredMoveViewItemArray_size(model->labels); + const int32_t item_idx_prev = model->current_idx; + if(event->key == InputKeyUp) { - if(model->item_idx <= 0) { - model->item_idx = model->btn_number; + if(model->current_idx <= 0) { + model->current_idx = btn_number; } - model->item_idx--; + model->current_idx--; + } else if(event->key == InputKeyDown) { - model->item_idx++; - if(model->item_idx >= (int32_t)(model->btn_number)) { - model->item_idx = 0; + model->current_idx++; + if(model->current_idx >= (int32_t)(btn_number)) { + model->current_idx = 0; } } - index_new = model->item_idx; + + if(model->is_moving) { + InfraredMoveViewItemArray_swap_at( + model->labels, item_idx_prev, model->current_idx); + } + update_list_offset(model); }, - !is_moving); - if((is_moving) && (move_view->move_cb)) { - move_view->move_cb(index_old, index_new, move_view->cb_context); - infrared_move_view_list_update(move_view); - } - consumed = true; - } + true); - if((event->key == InputKeyOk) && (event->type == InputTypeShort)) { + consumed = true; + + } else if((event->key == InputKeyOk) && (event->type == InputTypeShort)) { with_view_model( move_view->view, InfraredMoveViewModel * model, - { model->is_moving = !(model->is_moving); }, + { + if(!model->is_moving) { + model->start_idx = model->current_idx; + } else if(move_view->callback) { + move_view->callback( + model->start_idx, model->current_idx, move_view->callback_context); + } + model->is_moving = !(model->is_moving); + }, true); + consumed = true; + + } else if(event->key == InputKeyBack) { + with_view_model( + move_view->view, + InfraredMoveViewModel * model, + { + if(model->is_moving && move_view->callback) { + move_view->callback( + model->start_idx, model->current_idx, move_view->callback_context); + } + model->is_moving = false; + }, + false); + + // Not consuming, Back event is passed thru } + return consumed; } -static void infrared_move_view_on_exit(void* context) { - furi_assert(context); - InfraredMoveView* move_view = context; - - with_view_model( - move_view->view, - InfraredMoveViewModel * model, - { - if(model->btn_names) { - free(model->btn_names); - model->btn_names = NULL; - } - model->btn_number = 0; - model->get_item_cb = NULL; - }, - false); - move_view->cb_context = NULL; -} - -void infrared_move_view_set_callback(InfraredMoveView* move_view, InfraredMoveCallback callback) { - furi_assert(move_view); - move_view->move_cb = callback; -} - -void infrared_move_view_list_init( +void infrared_move_view_set_callback( InfraredMoveView* move_view, - uint32_t item_count, - InfraredMoveGetItemCallback load_cb, + InfraredMoveCallback callback, void* context) { furi_assert(move_view); - move_view->cb_context = context; - with_view_model( - move_view->view, - InfraredMoveViewModel * model, - { - furi_assert(model->btn_names == NULL); - model->btn_names = malloc(sizeof(char*) * item_count); - model->btn_number = item_count; - model->get_item_cb = load_cb; - }, - false); + move_view->callback = callback; + move_view->callback_context = context; } -void infrared_move_view_list_update(InfraredMoveView* move_view) { - furi_assert(move_view); +void infrared_move_view_add_item(InfraredMoveView* move_view, const char* label) { + with_view_model( + move_view->view, + InfraredMoveViewModel * model, + { InfraredMoveViewItemArray_push_back(model->labels, label); }, + true); +} + +void infrared_move_view_reset(InfraredMoveView* move_view) { with_view_model( move_view->view, InfraredMoveViewModel * model, { - for(uint32_t i = 0; i < model->btn_number; i++) { - if(!model->get_item_cb) break; - model->btn_names[i] = model->get_item_cb(i, move_view->cb_context); - } + InfraredMoveViewItemArray_reset(model->labels); + model->list_offset = 0; + model->start_idx = 0; + model->current_idx = 0; + model->is_moving = false; }, - true); + false); + move_view->callback_context = NULL; } InfraredMoveView* infrared_move_view_alloc(void) { InfraredMoveView* move_view = malloc(sizeof(InfraredMoveView)); + move_view->view = view_alloc(); view_allocate_model(move_view->view, ViewModelTypeLocking, sizeof(InfraredMoveViewModel)); view_set_draw_callback(move_view->view, infrared_move_view_draw_callback); view_set_input_callback(move_view->view, infrared_move_view_input_callback); - view_set_exit_callback(move_view->view, infrared_move_view_on_exit); view_set_context(move_view->view, move_view); + + with_view_model( + move_view->view, + InfraredMoveViewModel * model, + { InfraredMoveViewItemArray_init(model->labels); }, + true); + return move_view; } void infrared_move_view_free(InfraredMoveView* move_view) { + with_view_model( + move_view->view, + InfraredMoveViewModel * model, + { InfraredMoveViewItemArray_clear(model->labels); }, + true); + view_free(move_view->view); free(move_view); } diff --git a/applications/main/infrared/views/infrared_move_view.h b/applications/main/infrared/views/infrared_move_view.h index b9b0cd864a..0ab15ce0d1 100644 --- a/applications/main/infrared/views/infrared_move_view.h +++ b/applications/main/infrared/views/infrared_move_view.h @@ -6,20 +6,17 @@ typedef struct InfraredMoveView InfraredMoveView; typedef void (*InfraredMoveCallback)(uint32_t index_old, uint32_t index_new, void* context); -typedef const char* (*InfraredMoveGetItemCallback)(uint32_t index, void* context); - InfraredMoveView* infrared_move_view_alloc(void); void infrared_move_view_free(InfraredMoveView* debug_view); View* infrared_move_view_get_view(InfraredMoveView* debug_view); -void infrared_move_view_set_callback(InfraredMoveView* move_view, InfraredMoveCallback callback); - -void infrared_move_view_list_init( +void infrared_move_view_set_callback( InfraredMoveView* move_view, - uint32_t item_count, - InfraredMoveGetItemCallback load_cb, + InfraredMoveCallback callback, void* context); -void infrared_move_view_list_update(InfraredMoveView* move_view); \ No newline at end of file +void infrared_move_view_add_item(InfraredMoveView* move_view, const char* label); + +void infrared_move_view_reset(InfraredMoveView* move_view); From 9af81ce8d03320ec73bafcda132199e7d82d8674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Tue, 31 Oct 2023 19:40:32 +0900 Subject: [PATCH 08/40] Furi: cleanup crash use (#3175) * Furi: optional message in furi_crash and furi_halt * Consistent furi_crash use * UnitTests: crash instead of assert * furi: check: fixed macro for default arg * unit_tests: fixed crashes everywhere * lib: infrared: fixed PVS warnings * furi: eliminated __FURI_ASSERT_MESSAGE_FLAG * Furi: update check.h docs * Furi: add check.h usage note * Docs: grammar --------- Co-authored-by: hedger --- applications/debug/unit_tests/bt/bt_test.c | 4 +- .../debug/unit_tests/infrared/infrared_test.c | 2 +- applications/debug/unit_tests/nfc/nfc_test.c | 2 +- .../debug/unit_tests/nfc/nfc_transport.c | 50 +++++++++---------- .../infrared_scene_edit_button_select.c | 2 +- .../scenes/infrared_scene_edit_delete.c | 4 +- .../scenes/infrared_scene_edit_delete_done.c | 2 +- .../scenes/infrared_scene_edit_rename.c | 4 +- .../desktop/animations/animation_manager.c | 6 +-- .../desktop/views/desktop_view_pin_input.c | 4 +- applications/services/gui/canvas.c | 8 +-- applications/services/gui/elements.c | 2 +- .../services/gui/modules/byte_input.c | 4 +- applications/services/gui/modules/popup.c | 2 +- .../services/gui/modules/text_input.c | 4 +- applications/services/gui/view.c | 4 +- applications/services/gui/view_dispatcher.c | 2 +- applications/services/rpc/rpc_app.c | 2 +- .../scenes/desktop_settings_scene_pin_auth.c | 2 +- .../scenes/desktop_settings_scene_pin_error.c | 2 +- .../desktop_settings_scene_pin_setup_howto.c | 2 +- .../desktop_settings_scene_pin_setup_howto2.c | 2 +- applications/system/hid_app/hid.c | 22 ++++---- documentation/FuriCheck.md | 40 +++++++++++++++ furi/core/check.c | 4 +- furi/core/check.h | 32 ++++++++---- lib/ibutton/ibutton_protocols.c | 2 +- .../nec/infrared_encoder_nec.c | 2 +- .../sirc/infrared_encoder_sirc.c | 2 +- lib/infrared/worker/infrared_transmit.c | 2 +- lib/infrared/worker/infrared_worker.c | 12 ++--- targets/f18/api_symbols.csv | 6 +-- targets/f7/api_symbols.csv | 6 +-- targets/f7/furi_hal/furi_hal_infrared.c | 14 +++--- targets/f7/furi_hal/furi_hal_spi.c | 2 +- targets/f7/furi_hal/furi_hal_subghz.c | 2 +- targets/f7/furi_hal/furi_hal_version.c | 2 +- 37 files changed, 159 insertions(+), 107 deletions(-) create mode 100644 documentation/FuriCheck.md diff --git a/applications/debug/unit_tests/bt/bt_test.c b/applications/debug/unit_tests/bt/bt_test.c index 2cbfd684a2..32cf6533f8 100644 --- a/applications/debug/unit_tests/bt/bt_test.c +++ b/applications/debug/unit_tests/bt/bt_test.c @@ -28,7 +28,7 @@ void bt_test_alloc() { } void bt_test_free() { - furi_assert(bt_test); + furi_check(bt_test); free(bt_test->nvm_ram_buff_ref); free(bt_test->nvm_ram_buff_dut); bt_keys_storage_free(bt_test->bt_keys_storage); @@ -89,7 +89,7 @@ static void bt_test_keys_remove_test_file() { } MU_TEST(bt_test_keys_storage_serial_profile) { - furi_assert(bt_test); + furi_check(bt_test); bt_test_keys_remove_test_file(); bt_test_keys_storage_profile(); diff --git a/applications/debug/unit_tests/infrared/infrared_test.c b/applications/debug/unit_tests/infrared/infrared_test.c index b2acad470e..294c2da9a5 100644 --- a/applications/debug/unit_tests/infrared/infrared_test.c +++ b/applications/debug/unit_tests/infrared/infrared_test.c @@ -27,7 +27,7 @@ static void infrared_test_alloc() { } static void infrared_test_free() { - furi_assert(test); + furi_check(test); infrared_free_decoder(test->decoder_handler); infrared_free_encoder(test->encoder_handler); flipper_format_free(test->ff); diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index e7406fab8a..2d647f8ef5 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -34,7 +34,7 @@ static void nfc_test_alloc() { } static void nfc_test_free() { - furi_assert(nfc_test); + furi_check(nfc_test); furi_record_close(RECORD_STORAGE); free(nfc_test); diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index ee2657bea1..e2e313fdef 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -122,7 +122,7 @@ Nfc* nfc_alloc() { } void nfc_free(Nfc* instance) { - furi_assert(instance); + furi_check(instance); free(instance); } @@ -165,9 +165,9 @@ NfcError nfc_iso14443a_listener_set_col_res_data( uint8_t uid_len, uint8_t* atqa, uint8_t sak) { - furi_assert(instance); - furi_assert(uid); - furi_assert(atqa); + furi_check(instance); + furi_check(uid); + furi_check(atqa); nfc_prepare_col_res_data(instance, uid, uid_len, atqa, sak); @@ -176,7 +176,7 @@ NfcError nfc_iso14443a_listener_set_col_res_data( static int32_t nfc_worker_poller(void* context) { Nfc* instance = context; - furi_assert(instance->callback); + furi_check(instance->callback); instance->state = NfcStateReady; NfcCommand command = NfcCommandContinue; @@ -196,7 +196,7 @@ static int32_t nfc_worker_poller(void* context) { } static void nfc_worker_listener_pass_col_res(Nfc* instance, uint8_t* rx_data, uint16_t rx_bits) { - furi_assert(instance->col_res_status != Iso14443_3aColResStatusDone); + furi_check(instance->col_res_status != Iso14443_3aColResStatusDone); BitBuffer* tx_buffer = bit_buffer_alloc(NFC_MAX_BUFFER_SIZE); bool processed = false; @@ -255,7 +255,7 @@ static void nfc_worker_listener_pass_col_res(Nfc* instance, uint8_t* rx_data, ui static int32_t nfc_worker_listener(void* context) { Nfc* instance = context; - furi_assert(instance->callback); + furi_check(instance->callback); NfcMessage message = {}; @@ -295,17 +295,17 @@ static int32_t nfc_worker_listener(void* context) { } void nfc_start(Nfc* instance, NfcEventCallback callback, void* context) { - furi_assert(instance); - furi_assert(instance->worker_thread == NULL); + furi_check(instance); + furi_check(instance->worker_thread == NULL); if(instance->mode == NfcModeListener) { - furi_assert(listener_queue == NULL); + furi_check(listener_queue == NULL); // Check that poller didn't start - furi_assert(poller_queue == NULL); + furi_check(poller_queue == NULL); } else { - furi_assert(poller_queue == NULL); + furi_check(poller_queue == NULL); // Check that poller is started after listener - furi_assert(listener_queue); + furi_check(listener_queue); } instance->callback = callback; @@ -334,8 +334,8 @@ void nfc_start(Nfc* instance, NfcEventCallback callback, void* context) { } void nfc_stop(Nfc* instance) { - furi_assert(instance); - furi_assert(instance->worker_thread); + furi_check(instance); + furi_check(instance->worker_thread); if(instance->mode == NfcModeListener) { NfcMessage message = {.type = NfcMessageTypeAbort}; @@ -361,10 +361,10 @@ void nfc_stop(Nfc* instance) { // Called from worker thread NfcError nfc_listener_tx(Nfc* instance, const BitBuffer* tx_buffer) { - furi_assert(instance); - furi_assert(poller_queue); - furi_assert(listener_queue); - furi_assert(tx_buffer); + furi_check(instance); + furi_check(poller_queue); + furi_check(listener_queue); + furi_check(tx_buffer); NfcMessage message = {}; message.type = NfcMessageTypeTx; @@ -382,11 +382,11 @@ NfcError nfc_iso14443a_listener_tx_custom_parity(Nfc* instance, const BitBuffer* NfcError nfc_poller_trx(Nfc* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt) { - furi_assert(instance); - furi_assert(tx_buffer); - furi_assert(rx_buffer); - furi_assert(poller_queue); - furi_assert(listener_queue); + furi_check(instance); + furi_check(tx_buffer); + furi_check(rx_buffer); + furi_check(poller_queue); + furi_check(listener_queue); UNUSED(fwt); NfcError error = NfcErrorNone; @@ -396,7 +396,7 @@ NfcError message.data.data_bits = bit_buffer_get_size(tx_buffer); bit_buffer_write_bytes(tx_buffer, message.data.data, bit_buffer_get_size_bytes(tx_buffer)); // Tx - furi_assert(furi_message_queue_put(listener_queue, &message, FuriWaitForever) == FuriStatusOk); + furi_check(furi_message_queue_put(listener_queue, &message, FuriWaitForever) == FuriStatusOk); // Rx FuriStatus status = furi_message_queue_get(poller_queue, &message, 50); diff --git a/applications/main/infrared/scenes/infrared_scene_edit_button_select.c b/applications/main/infrared/scenes/infrared_scene_edit_button_select.c index a76b4e836b..3fd59b5792 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_button_select.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_button_select.c @@ -48,7 +48,7 @@ bool infrared_scene_edit_button_select_on_event(void* context, SceneManagerEvent } else if(edit_mode == InfraredEditModeDelete) { scene_manager_next_scene(scene_manager, InfraredSceneEditDelete); } else { - furi_assert(0); + furi_crash(); } consumed = true; } diff --git a/applications/main/infrared/scenes/infrared_scene_edit_delete.c b/applications/main/infrared/scenes/infrared_scene_edit_delete.c index c1735da082..0cb88efdb6 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_delete.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_delete.c @@ -60,7 +60,7 @@ void infrared_scene_edit_delete_on_enter(void* context) { infrared_remote_get_name(remote), infrared_remote_get_signal_count(remote)); } else { - furi_assert(0); + furi_crash(); } dialog_ex_set_text(dialog_ex, infrared->text_store[0], 64, 31, AlignCenter, AlignCenter); @@ -101,7 +101,7 @@ bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event) success = infrared_remote_remove(remote); app_state->current_button_index = InfraredButtonIndexNone; } else { - furi_crash(NULL); + furi_crash(); } if(success) { diff --git a/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c b/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c index 0ee6399142..9205db4c4e 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_delete_done.c @@ -33,7 +33,7 @@ bool infrared_scene_edit_delete_done_on_event(void* context, SceneManagerEvent e view_dispatcher_stop(infrared->view_dispatcher); } } else { - furi_assert(0); + furi_crash(); } consumed = true; } diff --git a/applications/main/infrared/scenes/infrared_scene_edit_rename.c b/applications/main/infrared/scenes/infrared_scene_edit_rename.c index e29f108651..178690926d 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_rename.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_rename.c @@ -42,7 +42,7 @@ void infrared_scene_edit_rename_on_enter(void* context) { furi_string_free(folder_path); } else { - furi_crash(NULL); + furi_crash(); } text_input_set_result_callback( @@ -81,7 +81,7 @@ bool infrared_scene_edit_rename_on_event(void* context, SceneManagerEvent event) } else if(edit_target == InfraredEditTargetRemote) { success = infrared_rename_current_remote(infrared, infrared->text_store[0]); } else { - furi_crash(NULL); + furi_crash(); } if(success) { diff --git a/applications/services/desktop/animations/animation_manager.c b/applications/services/desktop/animations/animation_manager.c index f4c8f17a3a..873fb6aa2c 100644 --- a/applications/services/desktop/animations/animation_manager.c +++ b/applications/services/desktop/animations/animation_manager.c @@ -456,7 +456,7 @@ void animation_manager_unload_and_stall_animation(AnimationManager* animation_ma } furi_timer_stop(animation_manager->idle_animation_timer); } else { - furi_assert(0); + furi_crash(); } FURI_LOG_I( @@ -528,7 +528,7 @@ void animation_manager_load_and_continue_animation(AnimationManager* animation_m } } else { /* Unknown state is an error. But not in release version.*/ - furi_assert(0); + furi_crash(); } /* if can't restore previous animation - select new */ @@ -564,7 +564,7 @@ static void animation_manager_switch_to_one_shot_view(AnimationManager* animatio } else if(stats.level == 2) { one_shot_view_start_animation(animation_manager->one_shot_view, &A_Levelup2_128x64); } else { - furi_assert(0); + furi_crash(); } } diff --git a/applications/services/desktop/views/desktop_view_pin_input.c b/applications/services/desktop/views/desktop_view_pin_input.c index d3dadd7d71..93bbffedc6 100644 --- a/applications/services/desktop/views/desktop_view_pin_input.c +++ b/applications/services/desktop/views/desktop_view_pin_input.c @@ -78,7 +78,7 @@ static bool desktop_view_pin_input_input(InputEvent* event, void* context) { } break; default: - furi_assert(0); + furi_crash(); break; } } @@ -129,7 +129,7 @@ static void desktop_view_pin_input_draw_cells(Canvas* canvas, DesktopViewPinInpu canvas_draw_icon_ex(canvas, x + 2, y + 3, &I_Pin_arrow_up_7x9, IconRotation90); break; default: - furi_assert(0); + furi_crash(); break; } } diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 37edc5d33d..85c0528530 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -135,7 +135,7 @@ void canvas_set_font(Canvas* canvas, Font font) { } else if(font == FontBigNumbers) { u8g2_SetFont(&canvas->fb, u8g2_font_profont22_tn); } else { - furi_crash(NULL); + furi_crash(); } } @@ -175,7 +175,7 @@ void canvas_draw_str_aligned( x -= (u8g2_GetStrWidth(&canvas->fb, str) / 2); break; default: - furi_crash(NULL); + furi_crash(); break; } @@ -189,7 +189,7 @@ void canvas_draw_str_aligned( y += (u8g2_GetAscent(&canvas->fb) / 2); break; default: - furi_crash(NULL); + furi_crash(); break; } @@ -530,7 +530,7 @@ void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) { rotate_cb = U8G2_R1; break; default: - furi_assert(0); + furi_crash(); } if(need_swap) FURI_SWAP(canvas->width, canvas->height); diff --git a/applications/services/gui/elements.c b/applications/services/gui/elements.c index a6ab84fb8d..e92c2433cd 100644 --- a/applications/services/gui/elements.c +++ b/applications/services/gui/elements.c @@ -232,7 +232,7 @@ static size_t } else if(horizontal == AlignRight) { px_left = x; } else { - furi_assert(0); + furi_crash(); } if(len_px > px_left) { diff --git a/applications/services/gui/modules/byte_input.c b/applications/services/gui/modules/byte_input.c index 4846bbd8cc..e9cd78da02 100644 --- a/applications/services/gui/modules/byte_input.c +++ b/applications/services/gui/modules/byte_input.c @@ -79,7 +79,7 @@ static uint8_t byte_input_get_row_size(uint8_t row_index) { row_size = COUNT_OF(keyboard_keys_row_2); break; default: - furi_crash(NULL); + furi_crash(); } return row_size; @@ -102,7 +102,7 @@ static const ByteInputKey* byte_input_get_row(uint8_t row_index) { row = keyboard_keys_row_2; break; default: - furi_crash(NULL); + furi_crash(); } return row; diff --git a/applications/services/gui/modules/popup.c b/applications/services/gui/modules/popup.c index d75abb95fa..520efceef9 100644 --- a/applications/services/gui/modules/popup.c +++ b/applications/services/gui/modules/popup.c @@ -98,7 +98,7 @@ void popup_start_timer(void* context) { if(timer_period == 0) timer_period = 1; if(furi_timer_start(popup->timer, timer_period) != FuriStatusOk) { - furi_assert(0); + furi_crash(); }; } } diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index 86b7bca1e0..50453cf22c 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -101,7 +101,7 @@ static uint8_t get_row_size(uint8_t row_index) { row_size = COUNT_OF(keyboard_keys_row_3); break; default: - furi_crash(NULL); + furi_crash(); } return row_size; @@ -121,7 +121,7 @@ static const TextInputKey* get_row(uint8_t row_index) { row = keyboard_keys_row_3; break; default: - furi_crash(NULL); + furi_crash(); } return row; diff --git a/applications/services/gui/view.c b/applications/services/gui/view.c index 07ae072a17..316f5c612a 100644 --- a/applications/services/gui/view.c +++ b/applications/services/gui/view.c @@ -82,7 +82,7 @@ void view_allocate_model(View* view, ViewModelType type, size_t size) { model->data = malloc(size); view->model = model; } else { - furi_crash(NULL); + furi_crash(); } } @@ -99,7 +99,7 @@ void view_free_model(View* view) { free(model); view->model = NULL; } else { - furi_crash(NULL); + furi_crash(); } } diff --git a/applications/services/gui/view_dispatcher.c b/applications/services/gui/view_dispatcher.c index 0119abc200..87b07a87c4 100644 --- a/applications/services/gui/view_dispatcher.c +++ b/applications/services/gui/view_dispatcher.c @@ -207,7 +207,7 @@ void view_dispatcher_attach_to_gui( } else if(type == ViewDispatcherTypeFullscreen) { gui_add_view_port(gui, view_dispatcher->view_port, GuiLayerFullscreen); } else { - furi_check(NULL); + furi_crash(); } view_dispatcher->gui = gui; } diff --git a/applications/services/rpc/rpc_app.c b/applications/services/rpc/rpc_app.c index bf44ed2dee..e86eaa493d 100644 --- a/applications/services/rpc/rpc_app.c +++ b/applications/services/rpc/rpc_app.c @@ -62,7 +62,7 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context) } else if(status == LoaderStatusOk) { result = PB_CommandStatus_OK; } else { - furi_crash(NULL); + furi_crash(); } } else { result = PB_CommandStatus_ERROR_INVALID_PARAMETERS; diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c index be2ee48259..b73fe347b2 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_auth.c @@ -68,7 +68,7 @@ bool desktop_settings_scene_pin_auth_on_event(void* context, SceneManagerEvent e } else if(state == SCENE_STATE_PIN_AUTH_DISABLE) { scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinDisable); } else { - furi_assert(0); + furi_crash(); } consumed = true; break; diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c index 508992cee7..1ba3c1b2da 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_error.c @@ -39,7 +39,7 @@ void desktop_settings_scene_pin_error_on_enter(void* context) { } else if(state == SCENE_STATE_PIN_ERROR_WRONG) { desktop_view_pin_input_set_label_primary(app->pin_input_view, 35, 8, "Wrong PIN!"); } else { - furi_assert(0); + furi_crash(); } desktop_view_pin_input_set_label_secondary(app->pin_input_view, 0, 8, NULL); desktop_view_pin_input_set_label_button(app->pin_input_view, "Retry"); diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto.c index ec128246fa..31eec3871a 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto.c @@ -32,7 +32,7 @@ bool desktop_settings_scene_pin_setup_howto_on_event(void* context, SceneManager consumed = true; break; default: - furi_crash(NULL); + furi_crash(); } } return consumed; diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto2.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto2.c index 44b8e1bf79..0ebf85c64b 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto2.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_pin_setup_howto2.c @@ -52,7 +52,7 @@ bool desktop_settings_scene_pin_setup_howto2_on_event(void* context, SceneManage break; } default: - furi_crash(NULL); + furi_crash(); } } return consumed; diff --git a/applications/system/hid_app/hid.c b/applications/system/hid_app/hid.c index 6c4b928dea..a42fc60917 100644 --- a/applications/system/hid_app/hid.c +++ b/applications/system/hid_app/hid.c @@ -264,7 +264,7 @@ void hid_hal_keyboard_press(Hid* instance, uint16_t event) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_kb_press(event); } else { - furi_crash(NULL); + furi_crash(); } } @@ -275,7 +275,7 @@ void hid_hal_keyboard_release(Hid* instance, uint16_t event) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_kb_release(event); } else { - furi_crash(NULL); + furi_crash(); } } @@ -286,7 +286,7 @@ void hid_hal_keyboard_release_all(Hid* instance) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_kb_release_all(); } else { - furi_crash(NULL); + furi_crash(); } } @@ -297,7 +297,7 @@ void hid_hal_consumer_key_press(Hid* instance, uint16_t event) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_consumer_key_press(event); } else { - furi_crash(NULL); + furi_crash(); } } @@ -308,7 +308,7 @@ void hid_hal_consumer_key_release(Hid* instance, uint16_t event) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_consumer_key_release(event); } else { - furi_crash(NULL); + furi_crash(); } } @@ -319,7 +319,7 @@ void hid_hal_consumer_key_release_all(Hid* instance) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_kb_release_all(); } else { - furi_crash(NULL); + furi_crash(); } } @@ -330,7 +330,7 @@ void hid_hal_mouse_move(Hid* instance, int8_t dx, int8_t dy) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_mouse_move(dx, dy); } else { - furi_crash(NULL); + furi_crash(); } } @@ -341,7 +341,7 @@ void hid_hal_mouse_scroll(Hid* instance, int8_t delta) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_mouse_scroll(delta); } else { - furi_crash(NULL); + furi_crash(); } } @@ -352,7 +352,7 @@ void hid_hal_mouse_press(Hid* instance, uint16_t event) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_mouse_press(event); } else { - furi_crash(NULL); + furi_crash(); } } @@ -363,7 +363,7 @@ void hid_hal_mouse_release(Hid* instance, uint16_t event) { } else if(instance->transport == HidTransportUsb) { furi_hal_hid_mouse_release(event); } else { - furi_crash(NULL); + furi_crash(); } } @@ -375,7 +375,7 @@ void hid_hal_mouse_release_all(Hid* instance) { furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT); furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT); } else { - furi_crash(NULL); + furi_crash(); } } diff --git a/documentation/FuriCheck.md b/documentation/FuriCheck.md new file mode 100644 index 0000000000..02f3fc9173 --- /dev/null +++ b/documentation/FuriCheck.md @@ -0,0 +1,40 @@ +# Run time checks and forced system crash + +The best way to protect system integrity is to reduce amount cases that we must handle and crash the system as early as possible. +For that purpose we have bunch of helpers located in Furi Core check.h. + +## Couple notes before start + +- Definition of Crash - log event, save crash information in RTC and reboot the system. +- Definition of Halt - log event, stall the system. +- Debug and production builds behaves differently: debug build will never reset system in order to preserve state for debugging. +- If you have debugger connected we will stop before reboot automatically. +- All helpers accept optional MESSAGE_CSTR: it can be in RAM or Flash memory, but only messages from Flash will be shown after system reboot. +- MESSAGE_CSTR can be NULL, but macros magic already doing it for you, so just don't. + +## `furi_assert(CONDITION)` or `furi_assert(CONDITION, MESSAGE_CSTR)` + +Assert condition in development environment and crash the system if CONDITION is false. + +- Should be used at development stage in apps and services +- Keep in mind that release never contains this check +- Keep in mind that libraries never contains this check by default, use `LIB_DEBUG=1` if you need it +- Avoid putting function calls into CONDITION, since it may be omitted in some builds + +## `furi_check(CONDITION)` or `furi_check(CONDITION, MESSAGE_CSTR)` + +Always assert condition and crash the system if CONDITION is false. + +- Use it if you always need to check conditions + +## `furi_crash()` or `furi_crash(MESSAGE_CSTR)` + +Crash the system. + +- Use it to crash the system. For example: if abnormal condition detected. + +## `furi_halt()` or `furi_halt(MESSAGE_CSTR)` + +Halt the system. + +- We use it internally to shutdown flipper if poweroff is not possible. diff --git a/furi/core/check.c b/furi/core/check.c index 8888eddfb3..ea1de71425 100644 --- a/furi/core/check.c +++ b/furi/core/check.c @@ -128,7 +128,7 @@ static void __furi_print_name(bool isr) { } } -FURI_NORETURN void __furi_crash() { +FURI_NORETURN void __furi_crash_implementation() { __disable_irq(); GET_MESSAGE_AND_STORE_REGISTERS(); @@ -179,7 +179,7 @@ FURI_NORETURN void __furi_crash() { __builtin_unreachable(); } -FURI_NORETURN void __furi_halt() { +FURI_NORETURN void __furi_halt_implementation() { __disable_irq(); GET_MESSAGE_AND_STORE_REGISTERS(); diff --git a/furi/core/check.h b/furi/core/check.h index 004422e807..2d5df4cf6c 100644 --- a/furi/core/check.h +++ b/furi/core/check.h @@ -28,39 +28,51 @@ extern "C" { #define __FURI_CHECK_MESSAGE_FLAG (0x02) /** Crash system */ -FURI_NORETURN void __furi_crash(); +FURI_NORETURN void __furi_crash_implementation(); /** Halt system */ -FURI_NORETURN void __furi_halt(); +FURI_NORETURN void __furi_halt_implementation(); /** Crash system with message. Show message after reboot. */ -#define furi_crash(message) \ +#define __furi_crash(message) \ do { \ register const void* r12 asm("r12") = (void*)message; \ asm volatile("sukima%=:" : : "r"(r12)); \ - __furi_crash(); \ + __furi_crash_implementation(); \ } while(0) +/** Crash system + * + * @param optional message (const char*) + */ +#define furi_crash(...) M_APPLY(__furi_crash, M_IF_EMPTY(__VA_ARGS__)((NULL), (__VA_ARGS__))) + /** Halt system with message. */ -#define furi_halt(message) \ +#define __furi_halt(message) \ do { \ register const void* r12 asm("r12") = (void*)message; \ asm volatile("sukima%=:" : : "r"(r12)); \ - __furi_halt(); \ + __furi_halt_implementation(); \ } while(0) +/** Halt system + * + * @param optional message (const char*) + */ +#define furi_halt(...) M_APPLY(__furi_halt, M_IF_EMPTY(__VA_ARGS__)((NULL), (__VA_ARGS__))) + /** Check condition and crash if check failed */ #define __furi_check(__e, __m) \ do { \ if(!(__e)) { \ - furi_crash(__m); \ + __furi_crash(__m); \ } \ } while(0) /** Check condition and crash if failed * * @param condition to check - * @param optional message + * @param optional message (const char*) */ #define furi_check(...) \ M_APPLY(__furi_check, M_DEFAULT_ARGS(2, (__FURI_CHECK_MESSAGE_FLAG), __VA_ARGS__)) @@ -70,7 +82,7 @@ FURI_NORETURN void __furi_halt(); #define __furi_assert(__e, __m) \ do { \ if(!(__e)) { \ - furi_crash(__m); \ + __furi_crash(__m); \ } \ } while(0) #else @@ -86,7 +98,7 @@ FURI_NORETURN void __furi_halt(); * @warning only will do check if firmware compiled in debug mode * * @param condition to check - * @param optional message + * @param optional message (const char*) */ #define furi_assert(...) \ M_APPLY(__furi_assert, M_DEFAULT_ARGS(2, (__FURI_ASSERT_MESSAGE_FLAG), __VA_ARGS__)) diff --git a/lib/ibutton/ibutton_protocols.c b/lib/ibutton/ibutton_protocols.c index 75aa225efe..df74126708 100644 --- a/lib/ibutton/ibutton_protocols.c +++ b/lib/ibutton/ibutton_protocols.c @@ -48,7 +48,7 @@ static void ibutton_protocols_get_group_by_id( local_id -= ibutton_protocol_groups[i]->protocol_count; } } - furi_crash(NULL); + furi_crash(); } iButtonProtocols* ibutton_protocols_alloc() { diff --git a/lib/infrared/encoder_decoder/nec/infrared_encoder_nec.c b/lib/infrared/encoder_decoder/nec/infrared_encoder_nec.c index 87f815142a..47d8c3c649 100644 --- a/lib/infrared/encoder_decoder/nec/infrared_encoder_nec.c +++ b/lib/infrared/encoder_decoder/nec/infrared_encoder_nec.c @@ -48,7 +48,7 @@ void infrared_encoder_nec_reset(void* encoder_ptr, const InfraredMessage* messag *data2 = (message->command & 0xFFC0) >> 6; encoder->bits_to_encode = 42; } else { - furi_assert(0); + furi_crash(); } } diff --git a/lib/infrared/encoder_decoder/sirc/infrared_encoder_sirc.c b/lib/infrared/encoder_decoder/sirc/infrared_encoder_sirc.c index 6adf2235ce..39c2eb1667 100644 --- a/lib/infrared/encoder_decoder/sirc/infrared_encoder_sirc.c +++ b/lib/infrared/encoder_decoder/sirc/infrared_encoder_sirc.c @@ -23,7 +23,7 @@ void infrared_encoder_sirc_reset(void* encoder_ptr, const InfraredMessage* messa *data |= (message->address & 0x1FFF) << 7; encoder->bits_to_encode = 20; } else { - furi_assert(0); + furi_crash(); } } diff --git a/lib/infrared/worker/infrared_transmit.c b/lib/infrared/worker/infrared_transmit.c index 113fb63244..8f99c00662 100644 --- a/lib/infrared/worker/infrared_transmit.c +++ b/lib/infrared/worker/infrared_transmit.c @@ -88,7 +88,7 @@ FuriHalInfraredTxGetDataState state = FuriHalInfraredTxGetDataStateDone; } } else { - furi_crash(NULL); + furi_crash(); } return state; diff --git a/lib/infrared/worker/infrared_worker.c b/lib/infrared/worker/infrared_worker.c index 46effd420d..5e3257e260 100644 --- a/lib/infrared/worker/infrared_worker.c +++ b/lib/infrared/worker/infrared_worker.c @@ -367,10 +367,11 @@ static FuriHalInfraredTxGetDataState *duration = timing.duration; state = timing.state; } else { - furi_assert(0); + // Why bother if we crash anyway?.. *level = 0; *duration = 100; state = FuriHalInfraredTxGetDataStateDone; + furi_crash(); } uint32_t flags_set = furi_thread_flags_set( @@ -414,7 +415,7 @@ static bool infrared_get_new_signal(InfraredWorker* instance) { } else if(response == InfraredWorkerGetSignalResponseStop) { new_signal_obtained = false; } else { - furi_assert(0); + furi_crash(); } return new_signal_obtained; @@ -443,9 +444,8 @@ static bool infrared_worker_tx_fill_buffer(InfraredWorker* instance) { } if(status == InfraredStatusError) { - furi_assert(0); new_data_available = false; - break; + furi_crash(); } else if(status == InfraredStatusOk) { timing.state = FuriHalInfraredTxGetDataStateOk; } else if(status == InfraredStatusDone) { @@ -456,7 +456,7 @@ static bool infrared_worker_tx_fill_buffer(InfraredWorker* instance) { timing.state = FuriHalInfraredTxGetDataStateLastDone; } } else { - furi_assert(0); + furi_crash(); } uint32_t written_size = furi_stream_buffer_send(instance->stream, &timing, sizeof(InfraredWorkerTiming), 0); @@ -548,7 +548,7 @@ static int32_t infrared_worker_tx_thread(void* thread_context) { break; default: - furi_assert(0); + furi_crash(); break; } } diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index b4efd7911b..cb62b40c40 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,40.1,, +Version,+,41.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -302,10 +302,10 @@ Function,-,__eprintf,void,"const char*, const char*, unsigned int, const char*" Function,+,__errno,int*, Function,-,__fpclassifyd,int,double Function,-,__fpclassifyf,int,float -Function,+,__furi_crash,void, +Function,+,__furi_crash_implementation,void, Function,+,__furi_critical_enter,__FuriCriticalInfo, Function,+,__furi_critical_exit,void,__FuriCriticalInfo -Function,+,__furi_halt,void, +Function,+,__furi_halt_implementation,void, Function,-,__getdelim,ssize_t,"char**, size_t*, int, FILE*" Function,-,__getline,ssize_t,"char**, size_t*, FILE*" Function,-,__isinfd,int,double diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 7599230d72..9d9c1a01b3 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,40.1,, +Version,+,41.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -370,10 +370,10 @@ Function,-,__eprintf,void,"const char*, const char*, unsigned int, const char*" Function,+,__errno,int*, Function,-,__fpclassifyd,int,double Function,-,__fpclassifyf,int,float -Function,+,__furi_crash,void, +Function,+,__furi_crash_implementation,void, Function,+,__furi_critical_enter,__FuriCriticalInfo, Function,+,__furi_critical_exit,void,__FuriCriticalInfo -Function,+,__furi_halt,void, +Function,+,__furi_halt_implementation,void, Function,-,__getdelim,ssize_t,"char**, size_t*, int, FILE*" Function,-,__getline,ssize_t,"char**, size_t*, FILE*" Function,-,__isinfd,int,double diff --git a/targets/f7/furi_hal/furi_hal_infrared.c b/targets/f7/furi_hal/furi_hal_infrared.c index d3e36c2b5d..3b20b6bc3a 100644 --- a/targets/f7/furi_hal/furi_hal_infrared.c +++ b/targets/f7/furi_hal/furi_hal_infrared.c @@ -125,7 +125,7 @@ static void furi_hal_infrared_tim_rx_isr() { if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 1, duration); } else { - furi_assert(0); + furi_crash(); } } @@ -141,7 +141,7 @@ static void furi_hal_infrared_tim_rx_isr() { if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 0, duration); } else { - furi_assert(0); + furi_crash(); } } } @@ -254,7 +254,7 @@ static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { } else if(buffer_adr == (uint32_t)infrared_tim_tx.buffer[1].data) { buf_num = 1; } else { - furi_assert(0); + furi_crash(); } return buf_num; } @@ -263,7 +263,7 @@ static void furi_hal_infrared_tx_dma_polarity_isr() { #if INFRARED_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 if(LL_DMA_IsActiveFlag_TE1(INFRARED_DMA)) { LL_DMA_ClearFlag_TE1(INFRARED_DMA); - furi_crash(NULL); + furi_crash(); } if(LL_DMA_IsActiveFlag_TC1(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH1_DEF)) { LL_DMA_ClearFlag_TC1(INFRARED_DMA); @@ -285,7 +285,7 @@ static void furi_hal_infrared_tx_dma_isr() { #if INFRARED_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 if(LL_DMA_IsActiveFlag_TE2(INFRARED_DMA)) { LL_DMA_ClearFlag_TE2(INFRARED_DMA); - furi_crash(NULL); + furi_crash(); } if(LL_DMA_IsActiveFlag_HT2(INFRARED_DMA) && LL_DMA_IsEnabledIT_HT(INFRARED_DMA_CH2_DEF)) { LL_DMA_ClearFlag_HT2(INFRARED_DMA); @@ -303,7 +303,7 @@ static void furi_hal_infrared_tx_dma_isr() { } else if(furi_hal_infrared_state == InfraredStateAsyncTxStopReq) { /* fallthrough */ } else { - furi_crash(NULL); + furi_crash(); } } if(LL_DMA_IsActiveFlag_TC2(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH2_DEF)) { @@ -596,7 +596,7 @@ static void furi_hal_infrared_async_tx_free_resources(void) { void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { if((duty_cycle > 1) || (duty_cycle <= 0) || (freq > INFRARED_MAX_FREQUENCY) || (freq < INFRARED_MIN_FREQUENCY) || (infrared_tim_tx.data_callback == NULL)) { - furi_crash(NULL); + furi_crash(); } furi_assert(furi_hal_infrared_state == InfraredStateIdle); diff --git a/targets/f7/furi_hal/furi_hal_spi.c b/targets/f7/furi_hal/furi_hal_spi.c index a8884105aa..5c33760ea1 100644 --- a/targets/f7/furi_hal/furi_hal_spi.c +++ b/targets/f7/furi_hal/furi_hal_spi.c @@ -221,7 +221,7 @@ bool furi_hal_spi_bus_trx_dma( dma_rx_req = LL_DMAMUX_REQ_SPI2_RX; dma_tx_req = LL_DMAMUX_REQ_SPI2_TX; } else { - furi_crash(NULL); + furi_crash(); } if(rx_buffer == NULL) { diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index ac71b5f6c7..f751463532 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -604,7 +604,7 @@ static void furi_hal_subghz_async_tx_timer_isr() { furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullDown, GpioSpeedLow); LL_TIM_DisableCounter(TIM2); } else { - furi_crash(NULL); + furi_crash(); } } } diff --git a/targets/f7/furi_hal/furi_hal_version.c b/targets/f7/furi_hal/furi_hal_version.c index 859a8c39fc..e4364a5189 100644 --- a/targets/f7/furi_hal/furi_hal_version.c +++ b/targets/f7/furi_hal/furi_hal_version.c @@ -187,7 +187,7 @@ void furi_hal_version_init() { furi_hal_version_load_otp_v2(); break; default: - furi_crash(NULL); + furi_crash(); } furi_hal_rtc_set_register(FuriHalRtcRegisterVersion, (uint32_t)version_get()); From bbe68d6ffc10998a364118abace7ca44ecf6ace7 Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 31 Oct 2023 15:27:58 +0400 Subject: [PATCH 09/40] [FL-3629] fbt: SD card resource handling speedup (#3178) * fbt: reduced size of resources dependency graphs, resulting in faster build task evaluation * lib: flipper_app: fixed error message & error handling for plugins --- firmware.scons | 8 +- .../plugins/plugin_manager.c | 3 +- scripts/fbt_tools/fbt_assets.py | 26 +++--- scripts/fbt_tools/fbt_resources.py | 93 +++++++++++-------- 4 files changed, 74 insertions(+), 56 deletions(-) diff --git a/firmware.scons b/firmware.scons index e8e50022c7..537774254c 100644 --- a/firmware.scons +++ b/firmware.scons @@ -148,15 +148,11 @@ if env["IS_BASE_FIRMWARE"]: ) fw_artifacts.append(fw_extapps.sdk_tree) - # Resources for SD card - resources = fwenv.ResourcesDist( - _EXTRA_DIST=[fwenv["DOLPHIN_EXTERNAL_OUT_DIR"]], - ) - + # Resources & manifest for SD card manifest = fwenv.ManifestBuilder( "${RESOURCES_ROOT}/Manifest", - source=resources, GIT_UNIX_TIMESTAMP=get_git_commit_unix_timestamp(), + _EXTRA_DIST=[fwenv["DOLPHIN_EXTERNAL_OUT_DIR"]], ) fwenv.Replace(FW_RESOURCES_MANIFEST=manifest) fwenv.Alias("resources", manifest) diff --git a/lib/flipper_application/plugins/plugin_manager.c b/lib/flipper_application/plugins/plugin_manager.c index e2a7b83f42..8f30ed13ec 100644 --- a/lib/flipper_application/plugins/plugin_manager.c +++ b/lib/flipper_application/plugins/plugin_manager.c @@ -66,7 +66,8 @@ PluginManagerError plugin_manager_load_single(PluginManager* manager, const char FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(lib); if(load_status != FlipperApplicationLoadStatusSuccess) { - FURI_LOG_E(TAG, "Failed to load module_demo_plugin1.fal"); + FURI_LOG_E(TAG, "Failed to load %s", path); + error = PluginManagerErrorLoaderError; break; } diff --git a/scripts/fbt_tools/fbt_assets.py b/scripts/fbt_tools/fbt_assets.py index dcf391f2d2..5c32ae1a98 100644 --- a/scripts/fbt_tools/fbt_assets.py +++ b/scripts/fbt_tools/fbt_assets.py @@ -30,24 +30,26 @@ def _proto_emitter(target, source, env): def _dolphin_emitter(target, source, env): res_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) - source = [res_root_dir] + source = list() source.extend(env.GlobRecursive("*.*", res_root_dir.srcnode())) target_base_dir = target[0] env.Replace(_DOLPHIN_OUT_DIR=target[0]) + env.Replace(_DOLPHIN_SRC_DIR=res_root_dir) if env["DOLPHIN_RES_TYPE"] == "external": target = [target_base_dir.File("manifest.txt")] ## A detailed list of files to be generated + # Not used ATM, becasuse it inflates the internal dependency graph too much # Preserve original paths, do .png -> .bm conversion - target.extend( - map( - lambda node: target_base_dir.File( - res_root_dir.rel_path(node).replace(".png", ".bm") - ), - filter(lambda node: isinstance(node, File), source), - ) - ) + # target.extend( + # map( + # lambda node: target_base_dir.File( + # res_root_dir.rel_path(node).replace(".png", ".bm") + # ), + # filter(lambda node: isinstance(node, File), source), + # ) + # ) else: asset_basename = f"assets_dolphin_{env['DOLPHIN_RES_TYPE']}" target = [ @@ -55,7 +57,7 @@ def _dolphin_emitter(target, source, env): target_base_dir.File(asset_basename + ".h"), ] - # Debug output + ## Debug output # print( # f"Dolphin res type: {env['DOLPHIN_RES_TYPE']},\ntarget files:", # list(f.path for f in target), @@ -176,7 +178,7 @@ def generate(env): "dolphin", "-s", "dolphin_${DOLPHIN_RES_TYPE}", - "${SOURCE}", + "${_DOLPHIN_SRC_DIR}", "${_DOLPHIN_OUT_DIR}", ], ], @@ -191,7 +193,7 @@ def generate(env): "${PYTHON3}", "${ASSETS_COMPILER}", "dolphin", - "${SOURCE}", + "${_DOLPHIN_SRC_DIR}", "${_DOLPHIN_OUT_DIR}", ], ], diff --git a/scripts/fbt_tools/fbt_resources.py b/scripts/fbt_tools/fbt_resources.py index 47c624081f..4c3146ba45 100644 --- a/scripts/fbt_tools/fbt_resources.py +++ b/scripts/fbt_tools/fbt_resources.py @@ -7,16 +7,21 @@ from SCons.Errors import StopError from SCons.Node.FS import Dir, File -def _resources_dist_emitter(target, source, env): +def __generate_resources_dist_entries(env): + src_target_entries = [] + resources_root = env.Dir(env["RESOURCES_ROOT"]) - target = [] for app_artifacts in env["FW_EXTAPPS"].application_map.values(): for _, dist_path in filter( lambda dist_entry: dist_entry[0], app_artifacts.dist_entries ): - source.append(app_artifacts.compact) - target.append(resources_root.File(dist_path)) + src_target_entries.append( + ( + app_artifacts.compact, + resources_root.File(dist_path), + ) + ) # Deploy apps' resources too for app in env["APPBUILD"].apps: @@ -26,34 +31,48 @@ def _resources_dist_emitter(target, source, env): for res_file in env.GlobRecursive("*", apps_resource_dir): if not isinstance(res_file, File): continue - source.append(res_file) - target.append(resources_root.File(res_file.get_path(apps_resource_dir))) + src_target_entries.append( + ( + res_file, + resources_root.File( + res_file.get_path(apps_resource_dir), + ), + ) + ) # Deploy other stuff from _EXTRA_DIST for extra_dist in env["_EXTRA_DIST"]: if isinstance(extra_dist, Dir): - for extra_file in env.GlobRecursive("*", extra_dist): - if not isinstance(extra_file, File): - continue - source.append(extra_file) - target.append( - # Preserve dir name from original node - resources_root.Dir(extra_dist.name).File( - extra_file.get_path(extra_dist) - ) + src_target_entries.append( + ( + extra_dist, + resources_root.Dir(extra_dist.name), ) + ) else: raise StopError(f"Unsupported extra dist type: {type(extra_dist)}") - assert len(target) == len(source) + return src_target_entries + + +def _resources_dist_emitter(target, source, env): + src_target_entries = __generate_resources_dist_entries(env) + source = list(map(lambda entry: entry[0], src_target_entries)) return (target, source) def _resources_dist_action(target, source, env): + dist_entries = __generate_resources_dist_entries(env) + assert len(dist_entries) == len(source) shutil.rmtree(env.Dir(env["RESOURCES_ROOT"]).abspath, ignore_errors=True) - for src, target in zip(source, target): - os.makedirs(os.path.dirname(target.path), exist_ok=True) - shutil.copy(src.path, target.path) + for src, target in dist_entries: + if isinstance(src, File): + os.makedirs(os.path.dirname(target.path), exist_ok=True) + shutil.copy(src.path, target.path) + elif isinstance(src, Dir): + shutil.copytree(src.path, target.path) + else: + raise StopError(f"Unsupported dist entry type: {type(src)}") def generate(env, **kw): @@ -69,26 +88,26 @@ def generate(env, **kw): env.Append( BUILDERS={ - "ResourcesDist": Builder( - action=Action( - _resources_dist_action, - "${RESOURCEDISTCOMSTR}", - ), - emitter=_resources_dist_emitter, - ), "ManifestBuilder": Builder( - action=Action( - [ + action=[ + Action( + _resources_dist_action, + "${RESOURCEDISTCOMSTR}", + ), + Action( [ - "${PYTHON3}", - "${ASSETS_COMPILER}", - "manifest", - "${TARGET.dir.posix}", - "--timestamp=${GIT_UNIX_TIMESTAMP}", - ] - ], - "${RESMANIFESTCOMSTR}", - ) + [ + "${PYTHON3}", + "${ASSETS_COMPILER}", + "manifest", + "${TARGET.dir.posix}", + "--timestamp=${GIT_UNIX_TIMESTAMP}", + ] + ], + "${RESMANIFESTCOMSTR}", + ), + ], + emitter=_resources_dist_emitter, ), } ) From bf8984a225099152b23dd1590862b635d81a7329 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Tue, 31 Oct 2023 15:34:21 +0400 Subject: [PATCH 10/40] [FL-3647] Rename menu items related to dummy mode and sound (#3177) Co-authored-by: hedger --- .../services/desktop/views/desktop_view_lock_menu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index f4790ebb8c..1ba8542b4a 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -60,13 +60,13 @@ void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { str = "Lock"; } else if(i == DesktopLockMenuIndexStealth) { if(m->stealth_mode) { - str = "Sound Mode"; + str = "Unmute"; } else { - str = "Stealth Mode"; + str = "Mute"; } } else if(i == DesktopLockMenuIndexDummy) { //-V547 if(m->dummy_mode) { - str = "Brainiac Mode"; + str = "Default Mode"; } else { str = "Dummy Mode"; } From 7bd3bd7ea4a0d600d7e5171dcfe7574da2019526 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 1 Nov 2023 08:21:31 +0400 Subject: [PATCH 11/40] fbt: source collection improvements (#3181) * fbt: reduced amount of redundant compilation units * fbt: added GatherSources() method which can reject source paths starting with "!" in sources list; optimized apps' source lists * docs: updated on path exclusion for `sources` * apps: examples: fixed example_advanced_plugins source list * docs: more details on `sources`; apps: narrower sources lists --- .../examples/example_plugins/application.fam | 3 +++ .../example_plugins_advanced/application.fam | 1 + applications/main/ibutton/application.fam | 1 + applications/main/infrared/application.fam | 6 +++++ applications/main/lfrfid/application.fam | 1 + applications/main/nfc/application.fam | 12 +++++++++ applications/main/subghz/application.fam | 6 +++++ documentation/AppManifests.md | 2 +- firmware.scons | 2 +- scripts/fbt_tools/fbt_extapps.py | 12 +++------ scripts/fbt_tools/sconsrecursiveglob.py | 27 ++++++++++++++++++- 11 files changed, 61 insertions(+), 12 deletions(-) diff --git a/applications/examples/example_plugins/application.fam b/applications/examples/example_plugins/application.fam index a6e3c20781..d9a36da564 100644 --- a/applications/examples/example_plugins/application.fam +++ b/applications/examples/example_plugins/application.fam @@ -5,6 +5,7 @@ App( entry_point="example_plugins_app", stack_size=2 * 1024, fap_category="Examples", + sources=["*.c", "!plugin*.c"], ) App( @@ -21,6 +22,7 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="example_plugin1_ep", requires=["example_plugins", "example_plugins_multi"], + sources=["plugin1.c"], ) App( @@ -28,4 +30,5 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="example_plugin2_ep", requires=["example_plugins_multi"], + sources=["plugin2.c"], ) diff --git a/applications/examples/example_plugins_advanced/application.fam b/applications/examples/example_plugins_advanced/application.fam index d40c0dde29..0c7e3e3b94 100644 --- a/applications/examples/example_plugins_advanced/application.fam +++ b/applications/examples/example_plugins_advanced/application.fam @@ -5,6 +5,7 @@ App( entry_point="example_advanced_plugins_app", stack_size=2 * 1024, fap_category="Examples", + sources=["*.c*", "!plugin*.c"], ) App( diff --git a/applications/main/ibutton/application.fam b/applications/main/ibutton/application.fam index a8faa629ce..01c02ec23d 100644 --- a/applications/main/ibutton/application.fam +++ b/applications/main/ibutton/application.fam @@ -17,5 +17,6 @@ App( apptype=FlipperAppType.STARTUP, targets=["f7"], entry_point="ibutton_on_system_start", + sources=["ibutton_cli.c"], order=60, ) diff --git a/applications/main/infrared/application.fam b/applications/main/infrared/application.fam index 055d6c3e29..575bebbe48 100644 --- a/applications/main/infrared/application.fam +++ b/applications/main/infrared/application.fam @@ -7,6 +7,7 @@ App( icon="A_Infrared_14", stack_size=3 * 1024, order=40, + sources=["*.c", "!infrared_cli.c"], resources="resources", fap_libs=["assets"], fap_icon="icon.png", @@ -18,5 +19,10 @@ App( apptype=FlipperAppType.STARTUP, targets=["f7"], entry_point="infrared_on_system_start", + sources=[ + "infrared_cli.c", + "infrared_brute_force.c", + "infrared_signal.c", + ], order=20, ) diff --git a/applications/main/lfrfid/application.fam b/applications/main/lfrfid/application.fam index cad07fbf77..c067d786fc 100644 --- a/applications/main/lfrfid/application.fam +++ b/applications/main/lfrfid/application.fam @@ -17,5 +17,6 @@ App( targets=["f7"], apptype=FlipperAppType.STARTUP, entry_point="lfrfid_on_system_start", + sources=["lfrfid_cli.c"], order=50, ) diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 3c8dab2bf1..33a2011a70 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -8,6 +8,11 @@ App( stack_size=5 * 1024, order=30, resources="resources", + sources=[ + "*.c", + "!plugins", + "!nfc_cli.c", + ], fap_libs=["assets"], fap_icon="icon.png", fap_category="NFC", @@ -21,6 +26,7 @@ App( entry_point="all_in_one_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/all_in_one.c"], ) App( @@ -29,6 +35,7 @@ App( entry_point="opal_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/opal.c"], ) App( @@ -37,6 +44,7 @@ App( entry_point="myki_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/myki.c"], ) App( @@ -45,6 +53,7 @@ App( entry_point="troika_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/troika.c"], ) App( @@ -53,6 +62,7 @@ App( entry_point="plantain_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/plantain.c"], ) App( @@ -61,6 +71,7 @@ App( entry_point="two_cities_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/two_cities.c"], ) App( @@ -68,5 +79,6 @@ App( targets=["f7"], apptype=FlipperAppType.STARTUP, entry_point="nfc_on_system_start", + sources=["nfc_cli.c"], order=30, ) diff --git a/applications/main/subghz/application.fam b/applications/main/subghz/application.fam index ba9b16abfd..5f9f24dcd3 100644 --- a/applications/main/subghz/application.fam +++ b/applications/main/subghz/application.fam @@ -7,6 +7,11 @@ App( icon="A_Sub1ghz_14", stack_size=3 * 1024, order=10, + sources=[ + "*.c", + "!subghz_cli.c", + "!helpers/subghz_chat.c", + ], resources="resources", fap_libs=["assets", "hwdrivers"], fap_icon="icon.png", @@ -18,5 +23,6 @@ App( targets=["f7"], apptype=FlipperAppType.STARTUP, entry_point="subghz_on_system_start", + sources=["subghz_cli.c", "helpers/subghz_chat.c"], order=40, ) diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index 0b3217c58c..d190a798ba 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -47,7 +47,7 @@ Only two parameters are mandatory: **_appid_** and **_apptype_**. Others are opt The following parameters are used only for [FAPs](./AppsOnSDCard.md): -- **sources**: list of strings, file name masks used for gathering sources within the app folder. The default value of `["*.c*"]` includes C and C++ source files. Applications cannot use the `"lib"` folder for their own source code, as it is reserved for **fap_private_libs**. +- **sources**: list of strings, file name masks used for gathering sources within the app folder. The default value of `["*.c*"]` includes C and C++ source files. Applications cannot use the `"lib"` folder for their own source code, as it is reserved for **fap_private_libs**. Paths starting with `"!"` are excluded from the list of sources. They can also include wildcard characters and directory names. For example, a value of `["*.c*", "!plugins"]` will include all C and C++ source files in the app folder except those in the `plugins` (and `lib`) folders. Paths with no wildcards (`*, ?`) are treated as full literal paths for both inclusion and exclusion. - **fap_version**: string, application version. The default value is "0.1". You can also use a tuple of 2 numbers in the form of (x,y) to specify the version. It is also possible to add more dot-separated parts to the version, like patch number, but only major and minor version numbers are stored in the built .fap. - **fap_icon**: name of a `.png` file, 1-bit color depth, 10x10px, to be embedded within `.fap` file. - **fap_libs**: list of extra libraries to link the application against. Provides access to extra functions that are not exported as a part of main firmware at the expense of increased `.fap` file size and RAM consumption. diff --git a/firmware.scons b/firmware.scons index 537774254c..eca6afc4c7 100644 --- a/firmware.scons +++ b/firmware.scons @@ -197,7 +197,7 @@ sources = [apps_c] # Gather sources only from app folders in current configuration sources.extend( itertools.chain.from_iterable( - fwenv.GlobRecursive(source_type, appdir.relpath, exclude=["lib"]) + fwenv.GatherSources([source_type, "!lib"], appdir.relpath) for appdir, source_type in fwenv["APPBUILD"].get_builtin_app_folders() ) ) diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 94307539a7..b88fa79291 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -147,16 +147,10 @@ class AppBuilder: CPPPATH=[self.app_work_dir, self.app._appdir], ) - app_sources = list( - itertools.chain.from_iterable( - self.app_env.GlobRecursive( - source_type, - self.app_work_dir, - exclude="lib", - ) - for source_type in self.app.sources - ) + app_sources = self.app_env.GatherSources( + [self.app.sources, "!lib"], self.app_work_dir ) + if not app_sources: raise UserError(f"No source files found for {self.app.appid}") diff --git a/scripts/fbt_tools/sconsrecursiveglob.py b/scripts/fbt_tools/sconsrecursiveglob.py index e7eb8fb729..de64c76b7b 100644 --- a/scripts/fbt_tools/sconsrecursiveglob.py +++ b/scripts/fbt_tools/sconsrecursiveglob.py @@ -1,7 +1,9 @@ +import itertools + import SCons from fbt.util import GLOB_FILE_EXCLUSION -from SCons.Script import Flatten from SCons.Node.FS import has_glob_magic +from SCons.Script import Flatten def GlobRecursive(env, pattern, node=".", exclude=[]): @@ -23,12 +25,35 @@ def GlobRecursive(env, pattern, node=".", exclude=[]): # Otherwise, just assume that file at path exists else: results.append(node.File(pattern)) + ## Debug # print(f"Glob result for {pattern} from {node}: {results}") return results +def GatherSources(env, sources_list, node="."): + sources_list = list(set(Flatten(sources_list))) + include_sources = list(filter(lambda x: not x.startswith("!"), sources_list)) + exclude_sources = list(x[1:] for x in sources_list if x.startswith("!")) + gathered_sources = list( + itertools.chain.from_iterable( + env.GlobRecursive( + source_type, + node, + exclude=exclude_sources, + ) + for source_type in include_sources + ) + ) + ## Debug + # print( + # f"Gathered sources for {sources_list} from {node}: {list(f.path for f in gathered_sources)}" + # ) + return gathered_sources + + def generate(env): env.AddMethod(GlobRecursive) + env.AddMethod(GatherSources) def exists(env): From aa063285165abf2bef9582f3a01b422cedf651e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 1 Nov 2023 16:24:11 +0900 Subject: [PATCH 12/40] Furi, FuriHal: remove FreeRTOS headers leaks (#3179) * Furi: remove direct FreeRTOS timers use * Furi: eliminate FreeRTOS headers leak. What did it cost? Everything... * SubGhz: proper public api for protocols. Format Sources. * Furi: slightly less redundant declarations * Desktop: proper types in printf * Sync API Symbols * Furi: add timer reset and fix dolphin service, fix unit tests * Furi: proper timer restart method naming and correct behavior in timer stopped state. --------- Co-authored-by: hedger --- applications/debug/direct_draw/direct_draw.c | 2 +- applications/debug/unit_tests/rpc/rpc_test.c | 10 +- applications/debug/unit_tests/test_index.c | 4 +- applications/main/infrared/infrared_app.c | 5 +- applications/main/nfc/nfc_app.c | 5 +- applications/main/subghz/views/receiver.c | 6 +- .../desktop/animations/animation_manager.c | 3 +- .../desktop/animations/animation_storage.c | 4 +- .../animations/views/bubble_animation_view.c | 8 +- .../views/one_shot_animation_view.c | 13 +- .../desktop/scenes/desktop_scene_locked.c | 1 - .../desktop/scenes/desktop_scene_pin_input.c | 23 ++-- .../scenes/desktop_scene_pin_timeout.c | 1 - .../desktop/views/desktop_view_locked.c | 19 ++- .../desktop/views/desktop_view_main.c | 21 ++-- .../desktop/views/desktop_view_pin_input.c | 27 ++-- .../desktop/views/desktop_view_pin_timeout.c | 17 ++- applications/services/dolphin/dolphin.c | 43 ++++--- applications/services/dolphin/dolphin_i.h | 6 +- applications/services/gui/icon_animation.c | 8 +- applications/services/input/input.c | 20 +-- applications/services/rpc/rpc.c | 3 +- applications/services/rpc/rpc.h | 2 +- applications/services/rpc/rpc_cli.c | 1 - applications/system/updater/updater.c | 1 - furi/core/base.h | 1 + furi/core/check.c | 2 - furi/core/common_defines.h | 2 - furi/core/critical.c | 3 + furi/core/event_flag.c | 1 + furi/core/kernel.c | 7 ++ furi/core/kernel.h | 6 + furi/core/memmgr_heap.c | 4 +- furi/core/message_queue.c | 3 +- furi/core/mutex.c | 1 + furi/core/semaphore.c | 1 + furi/core/stream_buffer.c | 1 + furi/core/thread.c | 4 +- furi/core/thread.h | 6 +- furi/core/timer.c | 39 ++++++ furi/core/timer.h | 27 ++++ furi/flipper.c | 2 + furi/furi.c | 4 +- furi/furi.h | 3 - lib/infrared/worker/infrared_worker.c | 6 +- lib/lfrfid/lfrfid_worker.c | 4 +- .../iso14443_4a/iso14443_4a_poller_i.h | 2 - .../iso14443_4b/iso14443_4b_poller_i.h | 2 - lib/print/wrappers.h | 3 +- lib/subghz/SConscript | 1 + lib/subghz/protocols/bin_raw.h | 5 +- lib/subghz/protocols/keeloq.h | 21 +--- lib/subghz/protocols/public_api.h | 63 ++++++++++ lib/subghz/protocols/secplus_v1.h | 9 +- lib/subghz/protocols/secplus_v2.h | 21 +--- lib/subghz/subghz_protocol_registry.h | 23 ---- lib/toolbox/buffer_stream.c | 2 +- lib/toolbox/buffer_stream.h | 2 +- targets/f18/api_symbols.csv | 114 +---------------- targets/f7/api_symbols.csv | 115 ++---------------- targets/f7/ble_glue/gap.c | 2 - targets/f7/furi_hal/furi_hal_flash.c | 3 + targets/f7/furi_hal/furi_hal_os.c | 3 + targets/f7/furi_hal/furi_hal_power.c | 8 +- targets/f7/furi_hal/furi_hal_spi.c | 2 +- targets/f7/inc/FreeRTOSConfig.h | 3 +- targets/f7/inc/furi_config.h | 3 + targets/f7/src/main.c | 1 - 68 files changed, 316 insertions(+), 472 deletions(-) create mode 100644 lib/subghz/protocols/public_api.h create mode 100644 targets/f7/inc/furi_config.h diff --git a/applications/debug/direct_draw/direct_draw.c b/applications/debug/direct_draw/direct_draw.c index 71c65eab13..63e03530a7 100644 --- a/applications/debug/direct_draw/direct_draw.c +++ b/applications/debug/direct_draw/direct_draw.c @@ -71,7 +71,7 @@ static void direct_draw_run(DirectDraw* instance) { size_t counter = 0; float fps = 0; - vTaskPrioritySet(furi_thread_get_current_id(), FuriThreadPriorityIdle); + furi_thread_set_current_priority(FuriThreadPriorityIdle); do { size_t elapsed = DWT->CYCCNT - start; diff --git a/applications/debug/unit_tests/rpc/rpc_test.c b/applications/debug/unit_tests/rpc/rpc_test.c index 645e75e844..5659ba877d 100644 --- a/applications/debug/unit_tests/rpc/rpc_test.c +++ b/applications/debug/unit_tests/rpc/rpc_test.c @@ -18,6 +18,8 @@ #include #include #include + +#include #include LIST_DEF(MsgList, PB_Main, M_POD_OPLIST) @@ -36,7 +38,7 @@ typedef struct { FuriStreamBuffer* output_stream; SemaphoreHandle_t close_session_semaphore; SemaphoreHandle_t terminate_semaphore; - TickType_t timeout; + uint32_t timeout; } RpcSessionContext; static RpcSessionContext rpc_session[TEST_RPC_SESSIONS]; @@ -544,7 +546,7 @@ static bool test_rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_ RpcSessionContext* session_context = istream->state; size_t bytes_received = 0; - TickType_t now = xTaskGetTickCount(); + uint32_t now = furi_get_tick(); int32_t time_left = session_context->timeout - now; time_left = MAX(time_left, 0); bytes_received = @@ -688,7 +690,7 @@ static void test_rpc_decode_and_compare(MsgList_t expected_msg_list, uint8_t ses furi_check(!MsgList_empty_p(expected_msg_list)); furi_check(session < TEST_RPC_SESSIONS); - rpc_session[session].timeout = xTaskGetTickCount() + MAX_RECEIVE_OUTPUT_TIMEOUT; + rpc_session[session].timeout = furi_get_tick() + MAX_RECEIVE_OUTPUT_TIMEOUT; pb_istream_t istream = { .callback = test_rpc_pb_stream_read, .state = &rpc_session[session], @@ -712,7 +714,7 @@ static void test_rpc_decode_and_compare(MsgList_t expected_msg_list, uint8_t ses pb_release(&PB_Main_msg, &result); } - rpc_session[session].timeout = xTaskGetTickCount() + 50; + rpc_session[session].timeout = furi_get_tick() + 50; if(pb_decode_ex(&istream, &PB_Main_msg, &result, PB_DECODE_DELIMITED)) { mu_fail("decoded more than expected"); } diff --git a/applications/debug/unit_tests/test_index.c b/applications/debug/unit_tests/test_index.c index edaf950c54..7c1b6b4447 100644 --- a/applications/debug/unit_tests/test_index.c +++ b/applications/debug/unit_tests/test_index.c @@ -65,8 +65,8 @@ const UnitTest unit_tests[] = { void minunit_print_progress() { static const char progress[] = {'\\', '|', '/', '-'}; static uint8_t progress_counter = 0; - static TickType_t last_tick = 0; - TickType_t current_tick = xTaskGetTickCount(); + 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)]); diff --git a/applications/main/infrared/infrared_app.c b/applications/main/infrared/infrared_app.c index e29eda30fb..7abb4e4eb6 100644 --- a/applications/main/infrared/infrared_app.c +++ b/applications/main/infrared/infrared_app.c @@ -384,18 +384,17 @@ void infrared_play_notification_message( } void infrared_show_loading_popup(const InfraredApp* infrared, bool show) { - TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); ViewStack* view_stack = infrared->view_stack; Loading* loading = infrared->loading; if(show) { // Raise timer priority so that animations can play - vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated); view_stack_add_view(view_stack, loading_get_view(loading)); } else { view_stack_remove_view(view_stack, loading_get_view(loading)); // Restore default timer priority - vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal); } } diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index fe680aa32d..9e0de8891b 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -411,15 +411,14 @@ bool nfc_load_from_file_select(NfcApp* instance) { void nfc_show_loading_popup(void* context, bool show) { NfcApp* nfc = context; - TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); if(show) { // Raise timer priority so that animations can play - vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewLoading); } else { // Restore default timer priority - vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal); } } diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index e1014b8110..23fa26c772 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -91,7 +91,7 @@ void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool loc SubGhzViewReceiverModel * model, { model->bar_show = SubGhzViewReceiverBarShowLock; }, true); - furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(1000)); + furi_timer_start(subghz_receiver->timer, 1000); } else { with_view_model( subghz_receiver->view, @@ -316,7 +316,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { { model->bar_show = SubGhzViewReceiverBarShowToUnlockPress; }, true); if(subghz_receiver->lock_count == 0) { - furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(1000)); + furi_timer_start(subghz_receiver->timer, 1000); } if(event->key == InputKeyBack && event->type == InputTypeShort) { subghz_receiver->lock_count++; @@ -330,7 +330,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { { model->bar_show = SubGhzViewReceiverBarShowUnlock; }, true); //subghz_receiver->lock = false; - furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650)); + furi_timer_start(subghz_receiver->timer, 650); } return true; diff --git a/applications/services/desktop/animations/animation_manager.c b/applications/services/desktop/animations/animation_manager.c index 873fb6aa2c..44c0c228c4 100644 --- a/applications/services/desktop/animations/animation_manager.c +++ b/applications/services/desktop/animations/animation_manager.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -450,7 +449,7 @@ void animation_manager_unload_and_stall_animation(AnimationManager* animation_ma animation_manager->state = AnimationManagerStateFreezedIdle; animation_manager->freezed_animation_time_left = - xTimerGetExpiryTime(animation_manager->idle_animation_timer) - xTaskGetTickCount(); + furi_timer_get_expire_time(animation_manager->idle_animation_timer) - furi_get_tick(); if(animation_manager->freezed_animation_time_left < 0) { animation_manager->freezed_animation_time_left = 0; } diff --git a/applications/services/desktop/animations/animation_storage.c b/applications/services/desktop/animations/animation_storage.c index 2c16cf726d..c99cc7b5d0 100644 --- a/applications/services/desktop/animations/animation_storage.c +++ b/applications/services/desktop/animations/animation_storage.c @@ -304,7 +304,7 @@ static bool animation_storage_load_frames( if(file_info.size > max_filesize) { FURI_LOG_E( TAG, - "Filesize %lld, max: %d (width %d, height %d)", + "Filesize %llu, max: %zu (width %u, height %u)", file_info.size, max_filesize, width, @@ -329,7 +329,7 @@ static bool animation_storage_load_frames( if(!frames_ok) { FURI_LOG_E( TAG, - "Load \'%s\' failed, %dx%d, size: %lld", + "Load \'%s\' failed, %ux%u, size: %llu", furi_string_get_cstr(filename), width, height, diff --git a/applications/services/desktop/animations/views/bubble_animation_view.c b/applications/services/desktop/animations/views/bubble_animation_view.c index 30a165087b..9585b2771e 100644 --- a/applications/services/desktop/animations/views/bubble_animation_view.c +++ b/applications/services/desktop/animations/views/bubble_animation_view.c @@ -23,7 +23,7 @@ typedef struct { uint8_t active_bubbles; uint8_t passive_bubbles; uint8_t active_shift; - TickType_t active_ended_at; + uint32_t active_ended_at; Icon* freeze_frame; } BubbleAnimationViewModel; @@ -154,7 +154,7 @@ static void bubble_animation_activate(BubbleAnimationView* view, bool force) { if(model->current != NULL) { if(!force) { if((model->active_ended_at + model->current->active_cooldown * 1000) > - xTaskGetTickCount()) { + furi_get_tick()) { activate = false; } else if(model->active_shift) { activate = false; @@ -215,7 +215,7 @@ static void bubble_animation_next_frame(BubbleAnimationViewModel* model) { model->active_cycle = 0; model->current_frame = 0; model->current_bubble = bubble_animation_pick_bubble(model, false); - model->active_ended_at = xTaskGetTickCount(); + model->active_ended_at = furi_get_tick(); } if(model->current_bubble) { @@ -355,7 +355,7 @@ void bubble_animation_view_set_animation( furi_assert(model); model->current = new_animation; - model->active_ended_at = xTaskGetTickCount() - (model->current->active_cooldown * 1000); + model->active_ended_at = furi_get_tick() - (model->current->active_cooldown * 1000); model->active_bubbles = 0; model->passive_bubbles = 0; for(int i = 0; i < new_animation->frame_bubble_sequences_count; ++i) { diff --git a/applications/services/desktop/animations/views/one_shot_animation_view.c b/applications/services/desktop/animations/views/one_shot_animation_view.c index 077f82d092..004fcde7b5 100644 --- a/applications/services/desktop/animations/views/one_shot_animation_view.c +++ b/applications/services/desktop/animations/views/one_shot_animation_view.c @@ -1,7 +1,6 @@ #include "one_shot_animation_view.h" #include -#include #include #include #include @@ -11,7 +10,7 @@ typedef void (*OneShotInteractCallback)(void*); struct OneShotView { View* view; - TimerHandle_t update_timer; + FuriTimer* update_timer; OneShotInteractCallback interact_callback; void* interact_callback_context; }; @@ -22,8 +21,8 @@ typedef struct { bool block_input; } OneShotViewModel; -static void one_shot_view_update_timer_callback(TimerHandle_t xTimer) { - OneShotView* view = (void*)pvTimerGetTimerID(xTimer); +static void one_shot_view_update_timer_callback(void* context) { + OneShotView* view = context; OneShotViewModel* model = view_get_model(view->view); if((model->index + 1) < model->icon->frame_count) { @@ -81,7 +80,7 @@ OneShotView* one_shot_view_alloc(void) { OneShotView* view = malloc(sizeof(OneShotView)); view->view = view_alloc(); view->update_timer = - xTimerCreate(NULL, 1000, pdTRUE, view, one_shot_view_update_timer_callback); + furi_timer_alloc(one_shot_view_update_timer_callback, FuriTimerTypePeriodic, view); view_allocate_model(view->view, ViewModelTypeLocking, sizeof(OneShotViewModel)); view_set_context(view->view, view); @@ -94,7 +93,7 @@ OneShotView* one_shot_view_alloc(void) { void one_shot_view_free(OneShotView* view) { furi_assert(view); - xTimerDelete(view->update_timer, portMAX_DELAY); + furi_timer_free(view->update_timer); view_free(view->view); view->view = NULL; free(view); @@ -120,7 +119,7 @@ void one_shot_view_start_animation(OneShotView* view, const Icon* icon) { model->icon = icon; model->block_input = true; view_commit_model(view->view, true); - xTimerChangePeriod(view->update_timer, 1000 / model->icon->frame_rate, portMAX_DELAY); + furi_timer_start(view->update_timer, 1000 / model->icon->frame_rate); } View* one_shot_view_get_view(OneShotView* view) { diff --git a/applications/services/desktop/scenes/desktop_scene_locked.c b/applications/services/desktop/scenes/desktop_scene_locked.c index bbed560015..034eedb8ac 100644 --- a/applications/services/desktop/scenes/desktop_scene_locked.c +++ b/applications/services/desktop/scenes/desktop_scene_locked.c @@ -3,7 +3,6 @@ #include #include #include -#include #include "../desktop.h" #include "../desktop_i.h" diff --git a/applications/services/desktop/scenes/desktop_scene_pin_input.c b/applications/services/desktop/scenes/desktop_scene_pin_input.c index e062c1b97d..0e248def60 100644 --- a/applications/services/desktop/scenes/desktop_scene_pin_input.c +++ b/applications/services/desktop/scenes/desktop_scene_pin_input.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -20,7 +19,7 @@ #define INPUT_PIN_VIEW_TIMEOUT 15000 typedef struct { - TimerHandle_t timer; + FuriTimer* timer; } DesktopScenePinInputState; static void desktop_scene_locked_light_red(bool value) { @@ -33,17 +32,16 @@ static void desktop_scene_locked_light_red(bool value) { furi_record_close(RECORD_NOTIFICATION); } -static void - desktop_scene_pin_input_set_timer(Desktop* desktop, bool enable, TickType_t new_period) { +static void desktop_scene_pin_input_set_timer(Desktop* desktop, bool enable, uint32_t new_period) { furi_assert(desktop); DesktopScenePinInputState* state = (DesktopScenePinInputState*)scene_manager_get_scene_state( desktop->scene_manager, DesktopScenePinInput); furi_assert(state); if(enable) { - xTimerChangePeriod(state->timer, new_period, portMAX_DELAY); + furi_timer_start(state->timer, new_period); } else { - xTimerStop(state->timer, portMAX_DELAY); + furi_timer_stop(state->timer); } } @@ -64,8 +62,8 @@ static void desktop_scene_pin_input_done_callback(const PinCode* pin_code, void* } } -static void desktop_scene_pin_input_timer_callback(TimerHandle_t timer) { - Desktop* desktop = pvTimerGetTimerID(timer); +static void desktop_scene_pin_input_timer_callback(void* context) { + Desktop* desktop = context; view_dispatcher_send_custom_event( desktop->view_dispatcher, DesktopPinInputEventResetWrongPinLabel); @@ -84,7 +82,7 @@ void desktop_scene_pin_input_on_enter(void* context) { DesktopScenePinInputState* state = malloc(sizeof(DesktopScenePinInputState)); state->timer = - xTimerCreate(NULL, 10000, pdFALSE, desktop, desktop_scene_pin_input_timer_callback); + furi_timer_alloc(desktop_scene_pin_input_timer_callback, FuriTimerTypeOnce, desktop); scene_manager_set_scene_state(desktop->scene_manager, DesktopScenePinInput, (uint32_t)state); desktop_view_pin_input_hide_pin(desktop->pin_input_view, true); @@ -149,10 +147,7 @@ void desktop_scene_pin_input_on_exit(void* context) { DesktopScenePinInputState* state = (DesktopScenePinInputState*)scene_manager_get_scene_state( desktop->scene_manager, DesktopScenePinInput); - xTimerStop(state->timer, portMAX_DELAY); - while(xTimerIsTimerActive(state->timer)) { - furi_delay_tick(1); - } - xTimerDelete(state->timer, portMAX_DELAY); + + furi_timer_free(state->timer); free(state); } diff --git a/applications/services/desktop/scenes/desktop_scene_pin_timeout.c b/applications/services/desktop/scenes/desktop_scene_pin_timeout.c index 2f009e7d2a..e3336ad76d 100644 --- a/applications/services/desktop/scenes/desktop_scene_pin_timeout.c +++ b/applications/services/desktop/scenes/desktop_scene_pin_timeout.c @@ -1,6 +1,5 @@ #include #include -#include #include #include "../desktop_i.h" diff --git a/applications/services/desktop/views/desktop_view_locked.c b/applications/services/desktop/views/desktop_view_locked.c index 3cee25425e..8df889dddd 100644 --- a/applications/services/desktop/views/desktop_view_locked.c +++ b/applications/services/desktop/views/desktop_view_locked.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "../desktop_i.h" @@ -29,7 +28,7 @@ struct DesktopViewLocked { DesktopViewLockedCallback callback; void* context; - TimerHandle_t timer; + FuriTimer* timer; uint8_t lock_count; uint32_t lock_lastpress; }; @@ -58,8 +57,8 @@ void desktop_view_locked_set_callback( locked_view->context = context; } -static void locked_view_timer_callback(TimerHandle_t timer) { - DesktopViewLocked* locked_view = pvTimerGetTimerID(timer); +static void locked_view_timer_callback(void* context) { + DesktopViewLocked* locked_view = context; locked_view->callback(DesktopLockedEventUpdate, locked_view->context); } @@ -90,7 +89,7 @@ static void desktop_view_locked_update_hint_icon_timeout(DesktopViewLocked* lock model->view_state = DesktopViewLockedStateLockedHintShown; } view_commit_model(locked_view->view, change_state); - xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(LOCKED_HINT_TIMEOUT_MS), portMAX_DELAY); + furi_timer_start(locked_view->timer, LOCKED_HINT_TIMEOUT_MS); } void desktop_view_locked_update(DesktopViewLocked* locked_view) { @@ -110,7 +109,7 @@ void desktop_view_locked_update(DesktopViewLocked* locked_view) { view_commit_model(locked_view->view, true); if(view_state != DesktopViewLockedStateDoorsClosing) { - xTimerStop(locked_view->timer, portMAX_DELAY); + furi_timer_stop(locked_view->timer); } } @@ -148,7 +147,7 @@ static bool desktop_view_locked_input(InputEvent* event, void* context) { furi_assert(context); bool is_changed = false; - const uint32_t press_time = xTaskGetTickCount(); + const uint32_t press_time = furi_get_tick(); DesktopViewLocked* locked_view = context; DesktopViewLockedModel* model = view_get_model(locked_view->view); if(model->view_state == DesktopViewLockedStateUnlockedHintShown && @@ -196,7 +195,7 @@ DesktopViewLocked* desktop_view_locked_alloc() { DesktopViewLocked* locked_view = malloc(sizeof(DesktopViewLocked)); locked_view->view = view_alloc(); locked_view->timer = - xTimerCreate(NULL, 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback); + furi_timer_alloc(locked_view_timer_callback, FuriTimerTypePeriodic, locked_view); view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopViewLockedModel)); view_set_context(locked_view->view, locked_view); @@ -219,7 +218,7 @@ void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) { model->view_state = DesktopViewLockedStateDoorsClosing; model->door_offset = DOOR_OFFSET_START; view_commit_model(locked_view->view, true); - xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(DOOR_MOVING_INTERVAL_MS), portMAX_DELAY); + furi_timer_start(locked_view->timer, DOOR_MOVING_INTERVAL_MS); } void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked) { @@ -236,7 +235,7 @@ void desktop_view_locked_unlock(DesktopViewLocked* locked_view) { model->view_state = DesktopViewLockedStateUnlockedHintShown; model->pin_locked = false; view_commit_model(locked_view->view, true); - xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(UNLOCKED_HINT_TIMEOUT_MS), portMAX_DELAY); + furi_timer_start(locked_view->timer, UNLOCKED_HINT_TIMEOUT_MS); } bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view) { diff --git a/applications/services/desktop/views/desktop_view_main.c b/applications/services/desktop/views/desktop_view_main.c index d323567e79..5e16f60862 100644 --- a/applications/services/desktop/views/desktop_view_main.c +++ b/applications/services/desktop/views/desktop_view_main.c @@ -13,14 +13,14 @@ struct DesktopMainView { View* view; DesktopMainViewCallback callback; void* context; - TimerHandle_t poweroff_timer; + FuriTimer* poweroff_timer; bool dummy_mode; }; #define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 5000 -static void desktop_main_poweroff_timer_callback(TimerHandle_t timer) { - DesktopMainView* main_view = pvTimerGetTimerID(timer); +static void desktop_main_poweroff_timer_callback(void* context) { + DesktopMainView* main_view = context; main_view->callback(DesktopMainEventOpenPowerOff, main_view->context); } @@ -90,12 +90,9 @@ bool desktop_main_input_callback(InputEvent* event, void* context) { if(event->key == InputKeyBack) { if(event->type == InputTypePress) { - xTimerChangePeriod( - main_view->poweroff_timer, - pdMS_TO_TICKS(DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT), - portMAX_DELAY); + furi_timer_start(main_view->poweroff_timer, DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT); } else if(event->type == InputTypeRelease) { - xTimerStop(main_view->poweroff_timer, portMAX_DELAY); + furi_timer_stop(main_view->poweroff_timer); } } @@ -109,12 +106,8 @@ DesktopMainView* desktop_main_alloc() { view_set_context(main_view->view, main_view); view_set_input_callback(main_view->view, desktop_main_input_callback); - main_view->poweroff_timer = xTimerCreate( - NULL, - pdMS_TO_TICKS(DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT), - pdFALSE, - main_view, - desktop_main_poweroff_timer_callback); + main_view->poweroff_timer = + furi_timer_alloc(desktop_main_poweroff_timer_callback, FuriTimerTypeOnce, main_view); return main_view; } diff --git a/applications/services/desktop/views/desktop_view_pin_input.c b/applications/services/desktop/views/desktop_view_pin_input.c index 93bbffedc6..0894bb776f 100644 --- a/applications/services/desktop/views/desktop_view_pin_input.c +++ b/applications/services/desktop/views/desktop_view_pin_input.c @@ -4,7 +4,6 @@ #include #include #include -#include #include "desktop_view_pin_input.h" #include @@ -21,7 +20,7 @@ struct DesktopViewPinInput { DesktopViewPinInputCallback timeout_callback; DesktopViewPinInputDoneCallback done_callback; void* context; - TimerHandle_t timer; + FuriTimer* timer; }; typedef struct { @@ -90,7 +89,7 @@ static bool desktop_view_pin_input_input(InputEvent* event, void* context) { pin_input->back_callback(pin_input->context); } - xTimerStart(pin_input->timer, 0); + furi_timer_start(pin_input->timer, NO_ACTIVITY_TIMEOUT); return true; } @@ -170,8 +169,8 @@ static void desktop_view_pin_input_draw(Canvas* canvas, void* context) { } } -void desktop_view_pin_input_timer_callback(TimerHandle_t timer) { - DesktopViewPinInput* pin_input = pvTimerGetTimerID(timer); +void desktop_view_pin_input_timer_callback(void* context) { + DesktopViewPinInput* pin_input = context; if(pin_input->timeout_callback) { pin_input->timeout_callback(pin_input->context); @@ -180,12 +179,12 @@ void desktop_view_pin_input_timer_callback(TimerHandle_t timer) { static void desktop_view_pin_input_enter(void* context) { DesktopViewPinInput* pin_input = context; - xTimerStart(pin_input->timer, portMAX_DELAY); + furi_timer_start(pin_input->timer, NO_ACTIVITY_TIMEOUT); } static void desktop_view_pin_input_exit(void* context) { DesktopViewPinInput* pin_input = context; - xTimerStop(pin_input->timer, portMAX_DELAY); + furi_timer_stop(pin_input->timer); } DesktopViewPinInput* desktop_view_pin_input_alloc(void) { @@ -195,12 +194,8 @@ DesktopViewPinInput* desktop_view_pin_input_alloc(void) { view_set_context(pin_input->view, pin_input); view_set_draw_callback(pin_input->view, desktop_view_pin_input_draw); view_set_input_callback(pin_input->view, desktop_view_pin_input_input); - pin_input->timer = xTimerCreate( - NULL, - pdMS_TO_TICKS(NO_ACTIVITY_TIMEOUT), - pdFALSE, - pin_input, - desktop_view_pin_input_timer_callback); + pin_input->timer = + furi_timer_alloc(desktop_view_pin_input_timer_callback, FuriTimerTypeOnce, pin_input); view_set_enter_callback(pin_input->view, desktop_view_pin_input_enter); view_set_exit_callback(pin_input->view, desktop_view_pin_input_exit); @@ -216,11 +211,7 @@ DesktopViewPinInput* desktop_view_pin_input_alloc(void) { void desktop_view_pin_input_free(DesktopViewPinInput* pin_input) { furi_assert(pin_input); - xTimerStop(pin_input->timer, portMAX_DELAY); - while(xTimerIsTimerActive(pin_input->timer)) { - furi_delay_tick(1); - } - xTimerDelete(pin_input->timer, portMAX_DELAY); + furi_timer_free(pin_input->timer); view_free(pin_input->view); free(pin_input); diff --git a/applications/services/desktop/views/desktop_view_pin_timeout.c b/applications/services/desktop/views/desktop_view_pin_timeout.c index e64c264ffd..f24ecc8ead 100644 --- a/applications/services/desktop/views/desktop_view_pin_timeout.c +++ b/applications/services/desktop/views/desktop_view_pin_timeout.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -13,7 +12,7 @@ struct DesktopViewPinTimeout { View* view; - TimerHandle_t timer; + FuriTimer* timer; DesktopViewPinTimeoutDoneCallback callback; void* context; }; @@ -32,8 +31,8 @@ void desktop_view_pin_timeout_set_callback( instance->context = context; } -static void desktop_view_pin_timeout_timer_callback(TimerHandle_t timer) { - DesktopViewPinTimeout* instance = pvTimerGetTimerID(timer); +static void desktop_view_pin_timeout_timer_callback(void* context) { + DesktopViewPinTimeout* instance = context; bool stop = false; DesktopViewPinTimeoutModel* model = view_get_model(instance->view); @@ -45,7 +44,7 @@ static void desktop_view_pin_timeout_timer_callback(TimerHandle_t timer) { view_commit_model(instance->view, true); if(stop) { - xTimerStop(instance->timer, portMAX_DELAY); + furi_timer_stop(instance->timer); instance->callback(instance->context); } } @@ -73,15 +72,15 @@ static void desktop_view_pin_timeout_draw(Canvas* canvas, void* _model) { void desktop_view_pin_timeout_free(DesktopViewPinTimeout* instance) { view_free(instance->view); - xTimerDelete(instance->timer, portMAX_DELAY); + furi_timer_free(instance->timer); free(instance); } DesktopViewPinTimeout* desktop_view_pin_timeout_alloc(void) { DesktopViewPinTimeout* instance = malloc(sizeof(DesktopViewPinTimeout)); - instance->timer = xTimerCreate( - NULL, pdMS_TO_TICKS(1000), pdTRUE, instance, desktop_view_pin_timeout_timer_callback); + instance->timer = + furi_timer_alloc(desktop_view_pin_timeout_timer_callback, FuriTimerTypePeriodic, instance); instance->view = view_alloc(); view_allocate_model(instance->view, ViewModelTypeLockFree, sizeof(DesktopViewPinTimeoutModel)); @@ -101,7 +100,7 @@ void desktop_view_pin_timeout_start(DesktopViewPinTimeout* instance, uint32_t ti model->time_left = time_left; view_commit_model(instance->view, true); - xTimerStart(instance->timer, portMAX_DELAY); + furi_timer_start(instance->timer, 1000); } View* desktop_view_pin_timeout_get_view(DesktopViewPinTimeout* instance) { diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index 579b400ad0..5b526ed3a6 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -1,7 +1,6 @@ #include "dolphin/dolphin.h" #include "dolphin/helpers/dolphin_state.h" #include "dolphin_i.h" -#include "portmacro.h" #include "projdefs.h" #include #include @@ -45,8 +44,8 @@ void dolphin_flush(Dolphin* dolphin) { dolphin_event_send_wait(dolphin, &event); } -void dolphin_butthurt_timer_callback(TimerHandle_t xTimer) { - Dolphin* dolphin = pvTimerGetTimerID(xTimer); +void dolphin_butthurt_timer_callback(void* context) { + Dolphin* dolphin = context; furi_assert(dolphin); DolphinEvent event; @@ -54,8 +53,8 @@ void dolphin_butthurt_timer_callback(TimerHandle_t xTimer) { dolphin_event_send_async(dolphin, &event); } -void dolphin_flush_timer_callback(TimerHandle_t xTimer) { - Dolphin* dolphin = pvTimerGetTimerID(xTimer); +void dolphin_flush_timer_callback(void* context) { + Dolphin* dolphin = context; furi_assert(dolphin); DolphinEvent event; @@ -63,11 +62,11 @@ void dolphin_flush_timer_callback(TimerHandle_t xTimer) { dolphin_event_send_async(dolphin, &event); } -void dolphin_clear_limits_timer_callback(TimerHandle_t xTimer) { - Dolphin* dolphin = pvTimerGetTimerID(xTimer); +void dolphin_clear_limits_timer_callback(void* context) { + Dolphin* dolphin = context; furi_assert(dolphin); - xTimerChangePeriod(dolphin->clear_limits_timer, HOURS_IN_TICKS(24), portMAX_DELAY); + furi_timer_start(dolphin->clear_limits_timer, HOURS_IN_TICKS(24)); DolphinEvent event; event.type = DolphinEventTypeClearLimits; @@ -80,12 +79,12 @@ Dolphin* dolphin_alloc() { dolphin->state = dolphin_state_alloc(); dolphin->event_queue = furi_message_queue_alloc(8, sizeof(DolphinEvent)); dolphin->pubsub = furi_pubsub_alloc(); - dolphin->butthurt_timer = xTimerCreate( - NULL, HOURS_IN_TICKS(2 * 24), pdTRUE, dolphin, dolphin_butthurt_timer_callback); + dolphin->butthurt_timer = + furi_timer_alloc(dolphin_butthurt_timer_callback, FuriTimerTypePeriodic, dolphin); dolphin->flush_timer = - xTimerCreate(NULL, 30 * 1000, pdFALSE, dolphin, dolphin_flush_timer_callback); - dolphin->clear_limits_timer = xTimerCreate( - NULL, HOURS_IN_TICKS(24), pdTRUE, dolphin, dolphin_clear_limits_timer_callback); + furi_timer_alloc(dolphin_flush_timer_callback, FuriTimerTypeOnce, dolphin); + dolphin->clear_limits_timer = + furi_timer_alloc(dolphin_clear_limits_timer_callback, FuriTimerTypePeriodic, dolphin); return dolphin; } @@ -125,14 +124,14 @@ FuriPubSub* dolphin_get_pubsub(Dolphin* dolphin) { static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin) { furi_assert(dolphin); - TickType_t now_ticks = xTaskGetTickCount(); - TickType_t timer_expires_at = xTimerGetExpiryTime(dolphin->clear_limits_timer); + uint32_t now_ticks = furi_get_tick(); + uint32_t timer_expires_at = furi_timer_get_expire_time(dolphin->clear_limits_timer); if((timer_expires_at - now_ticks) > HOURS_IN_TICKS(0.1)) { FuriHalRtcDateTime date; furi_hal_rtc_get_datetime(&date); - TickType_t now_time_in_ms = ((date.hour * 60 + date.minute) * 60 + date.second) * 1000; - TickType_t time_to_clear_limits = 0; + uint32_t now_time_in_ms = ((date.hour * 60 + date.minute) * 60 + date.second) * 1000; + uint32_t time_to_clear_limits = 0; if(date.hour < 5) { time_to_clear_limits = HOURS_IN_TICKS(5) - now_time_in_ms; @@ -140,7 +139,7 @@ static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin) { time_to_clear_limits = HOURS_IN_TICKS(24 + 5) - now_time_in_ms; } - xTimerChangePeriod(dolphin->clear_limits_timer, time_to_clear_limits, portMAX_DELAY); + furi_timer_start(dolphin->clear_limits_timer, time_to_clear_limits); } } @@ -156,9 +155,9 @@ int32_t dolphin_srv(void* p) { furi_record_create(RECORD_DOLPHIN, dolphin); dolphin_state_load(dolphin->state); - xTimerReset(dolphin->butthurt_timer, portMAX_DELAY); + furi_timer_stop(dolphin->butthurt_timer); dolphin_update_clear_limits_timer_period(dolphin); - xTimerReset(dolphin->clear_limits_timer, portMAX_DELAY); + furi_timer_stop(dolphin->clear_limits_timer); DolphinEvent event; while(1) { @@ -168,8 +167,8 @@ int32_t dolphin_srv(void* p) { dolphin_state_on_deed(dolphin->state, event.deed); DolphinPubsubEvent event = DolphinPubsubEventUpdate; furi_pubsub_publish(dolphin->pubsub, &event); - xTimerReset(dolphin->butthurt_timer, portMAX_DELAY); - xTimerReset(dolphin->flush_timer, portMAX_DELAY); + furi_timer_restart(dolphin->butthurt_timer); + furi_timer_restart(dolphin->flush_timer); } else if(event.type == DolphinEventTypeStats) { event.stats->icounter = dolphin->state->data.icounter; event.stats->butthurt = dolphin->state->data.butthurt; diff --git a/applications/services/dolphin/dolphin_i.h b/applications/services/dolphin/dolphin_i.h index ceeff1e1a9..2d716c1813 100644 --- a/applications/services/dolphin/dolphin_i.h +++ b/applications/services/dolphin/dolphin_i.h @@ -30,9 +30,9 @@ struct Dolphin { // Queue FuriMessageQueue* event_queue; FuriPubSub* pubsub; - TimerHandle_t butthurt_timer; - TimerHandle_t flush_timer; - TimerHandle_t clear_limits_timer; + FuriTimer* butthurt_timer; + FuriTimer* flush_timer; + FuriTimer* clear_limits_timer; }; Dolphin* dolphin_alloc(); diff --git a/applications/services/gui/icon_animation.c b/applications/services/gui/icon_animation.c index b63d233f3d..a39ef2e254 100644 --- a/applications/services/gui/icon_animation.c +++ b/applications/services/gui/icon_animation.c @@ -15,7 +15,6 @@ IconAnimation* icon_animation_alloc(const Icon* icon) { void icon_animation_free(IconAnimation* instance) { furi_assert(instance); icon_animation_stop(instance); - while(xTimerIsTimerActive(instance->timer) == pdTRUE) furi_delay_tick(1); furi_timer_free(instance->timer); free(instance); } @@ -67,10 +66,9 @@ void icon_animation_start(IconAnimation* instance) { instance->animating = true; furi_assert(instance->icon->frame_rate); furi_check( - xTimerChangePeriod( + furi_timer_start( instance->timer, - (furi_kernel_get_tick_frequency() / instance->icon->frame_rate), - portMAX_DELAY) == pdPASS); + (furi_kernel_get_tick_frequency() / instance->icon->frame_rate)) == FuriStatusOk); } } @@ -78,7 +76,7 @@ void icon_animation_stop(IconAnimation* instance) { furi_assert(instance); if(instance->animating) { instance->animating = false; - furi_check(xTimerStop(instance->timer, portMAX_DELAY) == pdPASS); + furi_timer_stop(instance->timer); instance->frame = 0; } } diff --git a/applications/services/input/input.c b/applications/services/input/input.c index 8da0a34003..216aa39b2e 100644 --- a/applications/services/input/input.c +++ b/applications/services/input/input.c @@ -6,20 +6,6 @@ static Input* input = NULL; -inline static void input_timer_start(FuriTimer* timer_id, uint32_t ticks) { - TimerHandle_t hTimer = (TimerHandle_t)timer_id; - furi_check(xTimerChangePeriod(hTimer, ticks, portMAX_DELAY) == pdPASS); -} - -inline static void input_timer_stop(FuriTimer* timer_id) { - TimerHandle_t hTimer = (TimerHandle_t)timer_id; - furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); - // xTimerStop is not actually stopping timer, - // Instead it places stop event into timer queue - // This code ensures that timer is stopped - while(xTimerIsTimerActive(hTimer) == pdTRUE) furi_delay_tick(1); -} - void input_press_timer_callback(void* arg) { InputPinState* input_pin = arg; InputEvent event; @@ -123,10 +109,12 @@ int32_t input_srv(void* p) { input->counter++; input->pin_states[i].counter = input->counter; event.sequence_counter = input->pin_states[i].counter; - input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); + furi_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS); } else { event.sequence_counter = input->pin_states[i].counter; - input_timer_stop(input->pin_states[i].press_timer); + furi_timer_stop(input->pin_states[i].press_timer); + while(furi_timer_is_running(input->pin_states[i].press_timer)) + furi_delay_tick(1); if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { event.type = InputTypeShort; furi_pubsub_publish(input->event_pubsub, &event); diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 3e9665ad8d..826f222537 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -6,7 +6,6 @@ #include #include -#include #include @@ -162,7 +161,7 @@ void rpc_session_set_terminated_callback( * odd: client sends close request and sends command after. */ size_t - rpc_session_feed(RpcSession* session, uint8_t* encoded_bytes, size_t size, TickType_t timeout) { + rpc_session_feed(RpcSession* session, uint8_t* encoded_bytes, size_t size, uint32_t timeout) { furi_assert(session); furi_assert(encoded_bytes); diff --git a/applications/services/rpc/rpc.h b/applications/services/rpc/rpc.h index d11fdc1624..863bca355b 100644 --- a/applications/services/rpc/rpc.h +++ b/applications/services/rpc/rpc.h @@ -124,7 +124,7 @@ void rpc_session_set_terminated_callback( * * @return actually consumed bytes */ -size_t rpc_session_feed(RpcSession* session, uint8_t* buffer, size_t size, TickType_t timeout); +size_t rpc_session_feed(RpcSession* session, uint8_t* buffer, size_t size, uint32_t timeout); /** Get available size of RPC buffer * diff --git a/applications/services/rpc/rpc_cli.c b/applications/services/rpc/rpc_cli.c index f1c139b5f9..4612752a83 100644 --- a/applications/services/rpc/rpc_cli.c +++ b/applications/services/rpc/rpc_cli.c @@ -2,7 +2,6 @@ #include #include #include -#include #define TAG "RpcCli" diff --git a/applications/system/updater/updater.c b/applications/system/updater/updater.c index e749f3ce6e..4c7fd29e9c 100644 --- a/applications/system/updater/updater.c +++ b/applications/system/updater/updater.c @@ -5,7 +5,6 @@ #include #include #include -#include #include static bool updater_custom_event_callback(void* context, uint32_t event) { diff --git a/furi/core/base.h b/furi/core/base.h index 29e8741920..642ff2b6cd 100644 --- a/furi/core/base.h +++ b/furi/core/base.h @@ -2,6 +2,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/furi/core/check.c b/furi/core/check.c index ea1de71425..b56db65637 100644 --- a/furi/core/check.c +++ b/furi/core/check.c @@ -55,8 +55,6 @@ PLACE_IN_SECTION("MB_MEM2") uint32_t __furi_check_registers[13] = {0}; : "memory"); extern size_t xPortGetTotalHeapSize(void); -extern size_t xPortGetFreeHeapSize(void); -extern size_t xPortGetMinimumEverFreeHeapSize(void); static void __furi_put_uint32_as_text(uint32_t data) { char tmp_str[] = "-2147483648"; diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index 5bd218d357..2b30c3b06d 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -2,8 +2,6 @@ #include "core_defines.h" #include -#include -#include #ifdef __cplusplus extern "C" { diff --git a/furi/core/critical.c b/furi/core/critical.c index 57fe2403be..3bef2be38e 100644 --- a/furi/core/critical.c +++ b/furi/core/critical.c @@ -1,5 +1,8 @@ #include "common_defines.h" +#include +#include + __FuriCriticalInfo __furi_critical_enter(void) { __FuriCriticalInfo info; diff --git a/furi/core/event_flag.c b/furi/core/event_flag.c index 9406a581f7..96b9591877 100644 --- a/furi/core/event_flag.c +++ b/furi/core/event_flag.c @@ -2,6 +2,7 @@ #include "common_defines.h" #include "check.h" +#include #include #define FURI_EVENT_FLAG_MAX_BITS_EVENT_GROUPS 24U diff --git a/furi/core/kernel.c b/furi/core/kernel.c index 7928ad11c3..89a50a9b52 100644 --- a/furi/core/kernel.c +++ b/furi/core/kernel.c @@ -5,6 +5,9 @@ #include +#include +#include + #include CMSIS_device_header bool furi_kernel_is_irq_or_masked() { @@ -31,6 +34,10 @@ bool furi_kernel_is_irq_or_masked() { return (irq); } +bool furi_kernel_is_running() { + return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING; +} + int32_t furi_kernel_lock() { furi_assert(!furi_kernel_is_irq_or_masked()); diff --git a/furi/core/kernel.h b/furi/core/kernel.h index 371f76c1f7..c962402efd 100644 --- a/furi/core/kernel.h +++ b/furi/core/kernel.h @@ -27,6 +27,12 @@ extern "C" { */ bool furi_kernel_is_irq_or_masked(); +/** Check if kernel is running + * + * @return true if running, false otherwise + */ +bool furi_kernel_is_running(); + /** Lock kernel, pause process scheduling * * @warning This should never be called in interrupt request context. diff --git a/furi/core/memmgr_heap.c b/furi/core/memmgr_heap.c index b8baf9c7c6..a3e127c3c1 100644 --- a/furi/core/memmgr_heap.c +++ b/furi/core/memmgr_heap.c @@ -47,8 +47,8 @@ all the API functions to use the MPU wrappers. That should only be done when task.h is included from an application file. */ #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE -#include "FreeRTOS.h" -#include "task.h" +#include +#include #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE diff --git a/furi/core/message_queue.c b/furi/core/message_queue.c index ddf56f0064..e20fa420a0 100644 --- a/furi/core/message_queue.c +++ b/furi/core/message_queue.c @@ -1,8 +1,9 @@ #include "kernel.h" #include "message_queue.h" +#include "check.h" + #include #include -#include "check.h" FuriMessageQueue* furi_message_queue_alloc(uint32_t msg_count, uint32_t msg_size) { furi_assert((furi_kernel_is_irq_or_masked() == 0U) && (msg_count > 0U) && (msg_size > 0U)); diff --git a/furi/core/mutex.c b/furi/core/mutex.c index 9fb964a1e5..8794e10dc3 100644 --- a/furi/core/mutex.c +++ b/furi/core/mutex.c @@ -2,6 +2,7 @@ #include "check.h" #include "common_defines.h" +#include #include FuriMutex* furi_mutex_alloc(FuriMutexType type) { diff --git a/furi/core/semaphore.c b/furi/core/semaphore.c index 8c99bfc541..1f1a07780c 100644 --- a/furi/core/semaphore.c +++ b/furi/core/semaphore.c @@ -2,6 +2,7 @@ #include "check.h" #include "common_defines.h" +#include #include FuriSemaphore* furi_semaphore_alloc(uint32_t max_count, uint32_t initial_count) { diff --git a/furi/core/stream_buffer.c b/furi/core/stream_buffer.c index bf483948be..a13d256b11 100644 --- a/furi/core/stream_buffer.c +++ b/furi/core/stream_buffer.c @@ -2,6 +2,7 @@ #include "check.h" #include "stream_buffer.h" #include "common_defines.h" + #include #include diff --git a/furi/core/thread.c b/furi/core/thread.c index de50bde7a4..db4feeb4e1 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -7,11 +7,13 @@ #include "mutex.h" #include "string.h" -#include #include "log.h" #include #include +#include +#include + #define TAG "FuriThread" #define THREAD_NOTIFY_INDEX 1 // Index 0 is used for stream buffers diff --git a/furi/core/thread.h b/furi/core/thread.h index 692f2a1008..44d66fb21a 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -8,6 +8,9 @@ #include "base.h" #include "common_defines.h" +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -28,7 +31,8 @@ typedef enum { FuriThreadPriorityNormal = 16, /**< Normal */ FuriThreadPriorityHigh = 17, /**< High */ FuriThreadPriorityHighest = 18, /**< Highest */ - FuriThreadPriorityIsr = (configMAX_PRIORITIES - 1), /**< Deferred ISR (highest possible) */ + FuriThreadPriorityIsr = + (FURI_CONFIG_THREAD_MAX_PRIORITIES - 1), /**< Deferred ISR (highest possible) */ } FuriThreadPriority; /** FuriThread anonymous structure */ diff --git a/furi/core/timer.c b/furi/core/timer.c index 7743ffe701..0a89b89201 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -97,6 +97,23 @@ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { return (stat); } +FuriStatus furi_timer_restart(FuriTimer* instance) { + furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(instance); + + TimerHandle_t hTimer = (TimerHandle_t)instance; + FuriStatus stat; + + if(xTimerReset(hTimer, portMAX_DELAY) == pdPASS) { + stat = FuriStatusOk; + } else { + stat = FuriStatusErrorResource; + } + + /* Return execution status */ + return (stat); +} + FuriStatus furi_timer_stop(FuriTimer* instance) { furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); @@ -125,6 +142,15 @@ uint32_t furi_timer_is_running(FuriTimer* instance) { return (uint32_t)xTimerIsTimerActive(hTimer); } +uint32_t furi_timer_get_expire_time(FuriTimer* instance) { + furi_assert(!furi_kernel_is_irq_or_masked()); + furi_assert(instance); + + TimerHandle_t hTimer = (TimerHandle_t)instance; + + return (uint32_t)xTimerGetExpiryTime(hTimer); +} + void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg) { BaseType_t ret = pdFAIL; if(furi_kernel_is_irq_or_masked()) { @@ -133,4 +159,17 @@ void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context ret = xTimerPendFunctionCall(callback, context, arg, FuriWaitForever); } furi_check(ret == pdPASS); +} + +void furi_timer_set_thread_priority(FuriTimerThreadPriority priority) { + furi_assert(!furi_kernel_is_irq_or_masked()); + TaskHandle_t task_handle = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + + if(priority == FuriTimerThreadPriorityNormal) { + vTaskPrioritySet(task_handle, configTIMER_TASK_PRIORITY); + } else if(priority == FuriTimerThreadPriorityElevated) { + vTaskPrioritySet(task_handle, configMAX_PRIORITIES - 1); + } else { + furi_crash(); + } } \ No newline at end of file diff --git a/furi/core/timer.h b/furi/core/timer.h index 3f43de5fd9..47b44c71a6 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -40,6 +40,14 @@ void furi_timer_free(FuriTimer* instance); */ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks); +/** Restart timer with previous timeout value + * + * @param instance The pointer to FuriTimer instance + * + * @return The furi status. + */ +FuriStatus furi_timer_restart(FuriTimer* instance); + /** Stop timer * * @param instance The pointer to FuriTimer instance @@ -56,10 +64,29 @@ FuriStatus furi_timer_stop(FuriTimer* instance); */ uint32_t furi_timer_is_running(FuriTimer* instance); +/** Get timer expire time + * + * @param instance The Timer instance + * + * @return expire tick + */ +uint32_t furi_timer_get_expire_time(FuriTimer* instance); + typedef void (*FuriTimerPendigCallback)(void* context, uint32_t arg); void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg); +typedef enum { + FuriTimerThreadPriorityNormal, /**< Lower then other threads */ + FuriTimerThreadPriorityElevated, /**< Same as other threads */ +} FuriTimerThreadPriority; + +/** Set Timer thread priority + * + * @param[in] priority The priority + */ +void furi_timer_set_thread_priority(FuriTimerThreadPriority priority); + #ifdef __cplusplus } #endif diff --git a/furi/flipper.c b/furi/flipper.c index 8806ce27fb..b29424a9f4 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -5,6 +5,8 @@ #include #include +#include + #define TAG "Flipper" static void flipper_print_version(const char* target, const Version* version) { diff --git a/furi/furi.c b/furi/furi.c index cc0e3f4f12..6247e259fb 100644 --- a/furi/furi.c +++ b/furi/furi.c @@ -1,6 +1,8 @@ #include "furi.h" #include -#include "queue.h" + +#include +#include void furi_init() { furi_assert(!furi_kernel_is_irq_or_masked()); diff --git a/furi/furi.h b/furi/furi.h index b1299c9a95..422509055f 100644 --- a/furi/furi.h +++ b/furi/furi.h @@ -21,9 +21,6 @@ #include -// FreeRTOS timer, REMOVE AFTER REFACTORING -#include - // Workaround for math.h leaking through HAL in older versions #include diff --git a/lib/infrared/worker/infrared_worker.c b/lib/infrared/worker/infrared_worker.c index 5e3257e260..38392fc06e 100644 --- a/lib/infrared/worker/infrared_worker.c +++ b/lib/infrared/worker/infrared_worker.c @@ -165,7 +165,7 @@ static int32_t infrared_worker_rx_thread(void* thread_context) { InfraredWorker* instance = thread_context; uint32_t events = 0; LevelDuration level_duration; - TickType_t last_blink_time = 0; + uint32_t last_blink_time = 0; while(1) { events = furi_thread_flags_wait(INFRARED_WORKER_ALL_RX_EVENTS, 0, FuriWaitForever); @@ -173,8 +173,8 @@ static int32_t infrared_worker_rx_thread(void* thread_context) { if(events & INFRARED_WORKER_RX_RECEIVED) { if(!instance->rx.overrun && instance->blink_enable && - ((xTaskGetTickCount() - last_blink_time) > 80)) { - last_blink_time = xTaskGetTickCount(); + ((furi_get_tick() - last_blink_time) > 80)) { + last_blink_time = furi_get_tick(); notification_message(instance->notification, &sequence_blink_blue_10); } if(instance->signal.timings_cnt == 0) diff --git a/lib/lfrfid/lfrfid_worker.c b/lib/lfrfid/lfrfid_worker.c index cbc7b02e37..ffaa8ee925 100644 --- a/lib/lfrfid/lfrfid_worker.c +++ b/lib/lfrfid/lfrfid_worker.c @@ -1,7 +1,7 @@ +#include "lfrfid_worker_i.h" + #include #include -#include -#include "lfrfid_worker_i.h" typedef enum { LFRFIDEventStopThread = (1 << 0), diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index 1113d381c2..ce878cb40a 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -43,8 +43,6 @@ struct Iso14443_4aPoller { void* context; }; -Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error); - const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance); Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance); diff --git a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h index 4df00adcf1..bd55c61882 100644 --- a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h +++ b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h @@ -40,8 +40,6 @@ struct Iso14443_4bPoller { void* context; }; -Iso14443_4bError iso14443_4b_process_error(Iso14443_3bError error); - const Iso14443_4bData* iso14443_4b_poller_get_data(Iso14443_4bPoller* instance); Iso14443_4bError iso14443_4b_poller_halt(Iso14443_4bPoller* instance); diff --git a/lib/print/wrappers.h b/lib/print/wrappers.h index b6f0f004b6..7c0d1f92eb 100644 --- a/lib/print/wrappers.h +++ b/lib/print/wrappers.h @@ -1,3 +1,5 @@ +#pragma once + #include #include #include @@ -6,7 +8,6 @@ extern "C" { #endif -void _putchar(char character); int __wrap_printf(const char* format, ...); int __wrap_vsnprintf(char* str, size_t size, const char* format, va_list args); int __wrap_puts(const char* str); diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 82c925c1a3..35850aa83e 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -12,6 +12,7 @@ env.Append( File("subghz_tx_rx_worker.h"), File("transmitter.h"), File("protocols/raw.h"), + File("protocols/public_api.h"), File("blocks/const.h"), File("blocks/decoder.h"), File("blocks/encoder.h"), diff --git a/lib/subghz/protocols/bin_raw.h b/lib/subghz/protocols/bin_raw.h index 82775e5759..26cc6ec3a2 100644 --- a/lib/subghz/protocols/bin_raw.h +++ b/lib/subghz/protocols/bin_raw.h @@ -1,6 +1,7 @@ #pragma once #include "base.h" +#include "public_api.h" #define SUBGHZ_PROTOCOL_BIN_RAW_NAME "BinRAW" @@ -80,10 +81,6 @@ void subghz_protocol_decoder_bin_raw_feed(void* context, bool level, uint32_t du */ uint8_t subghz_protocol_decoder_bin_raw_get_hash_data(void* context); -void subghz_protocol_decoder_bin_raw_data_input_rssi( - SubGhzProtocolDecoderBinRAW* instance, - float rssi); - /** * Serialize data SubGhzProtocolDecoderBinRAW. * @param context Pointer to a SubGhzProtocolDecoderBinRAW instance diff --git a/lib/subghz/protocols/keeloq.h b/lib/subghz/protocols/keeloq.h index 59cd9cf986..4abd14413b 100644 --- a/lib/subghz/protocols/keeloq.h +++ b/lib/subghz/protocols/keeloq.h @@ -1,6 +1,7 @@ #pragma once #include "base.h" +#include "public_api.h" #define SUBGHZ_PROTOCOL_KEELOQ_NAME "KeeLoq" @@ -24,26 +25,6 @@ void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment); */ void subghz_protocol_encoder_keeloq_free(void* context); -/** - * Key generation from simple data. - * @param context Pointer to a SubGhzProtocolEncoderKeeloq instance - * @param flipper_format Pointer to a FlipperFormat instance - * @param serial Serial number, 28 bit - * @param btn Button number, 4 bit - * @param cnt Container value, 16 bit - * @param manufacture_name Name of manufacturer's key - * @param preset Modulation, SubGhzRadioPreset - * @return true On success - */ -bool subghz_protocol_keeloq_create_data( - void* context, - FlipperFormat* flipper_format, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - const char* manufacture_name, - SubGhzRadioPreset* preset); - /** * Deserialize and generating an upload to send. * @param context Pointer to a SubGhzProtocolEncoderKeeloq instance diff --git a/lib/subghz/protocols/public_api.h b/lib/subghz/protocols/public_api.h new file mode 100644 index 0000000000..174f175cdf --- /dev/null +++ b/lib/subghz/protocols/public_api.h @@ -0,0 +1,63 @@ +#pragma once + +#include "../types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderSecPlus_v2 instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 32 bit + * @param btn Button number, 8 bit + * @param cnt Container value, 28 bit + * @param manufacture_name Name of manufacturer's key + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_secplus_v2_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint32_t cnt, + SubGhzRadioPreset* preset); + +/** + * Key generation from simple data. + * @param context Pointer to a SubGhzProtocolEncoderKeeloq instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param serial Serial number, 28 bit + * @param btn Button number, 4 bit + * @param cnt Container value, 16 bit + * @param manufacture_name Name of manufacturer's key + * @param preset Modulation, SubGhzRadioPreset + * @return true On success + */ +bool subghz_protocol_keeloq_create_data( + void* context, + FlipperFormat* flipper_format, + uint32_t serial, + uint8_t btn, + uint16_t cnt, + const char* manufacture_name, + SubGhzRadioPreset* preset); + +typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW; + +void subghz_protocol_decoder_bin_raw_data_input_rssi( + SubGhzProtocolDecoderBinRAW* instance, + float rssi); + +/** + * Validation of fixed parts SubGhzProtocolDecoderSecPlus_v1. + * @param fixed fixed parts + * @return true On success + */ +bool subghz_protocol_secplus_v1_check_fixed(uint32_t fixed); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/protocols/secplus_v1.h b/lib/subghz/protocols/secplus_v1.h index 3490f2ca54..e01f8bcdaa 100644 --- a/lib/subghz/protocols/secplus_v1.h +++ b/lib/subghz/protocols/secplus_v1.h @@ -1,5 +1,7 @@ #pragma once + #include "base.h" +#include "public_api.h" #define SUBGHZ_PROTOCOL_SECPLUS_V1_NAME "Security+ 1.0" @@ -100,13 +102,6 @@ SubGhzProtocolStatus subghz_protocol_decoder_secplus_v1_serialize( SubGhzProtocolStatus subghz_protocol_decoder_secplus_v1_deserialize(void* context, FlipperFormat* flipper_format); -/** - * Validation of fixed parts SubGhzProtocolDecoderSecPlus_v1. - * @param fixed fixed parts - * @return true On success - */ -bool subghz_protocol_secplus_v1_check_fixed(uint32_t fixed); - /** * Getting a textual representation of the received data. * @param context Pointer to a SubGhzProtocolDecoderSecPlus_v1 instance diff --git a/lib/subghz/protocols/secplus_v2.h b/lib/subghz/protocols/secplus_v2.h index 0eea732af1..9eb912a27e 100644 --- a/lib/subghz/protocols/secplus_v2.h +++ b/lib/subghz/protocols/secplus_v2.h @@ -1,5 +1,7 @@ #pragma once + #include "base.h" +#include "public_api.h" #define SUBGHZ_PROTOCOL_SECPLUS_V2_NAME "Security+ 2.0" @@ -45,25 +47,6 @@ void subghz_protocol_encoder_secplus_v2_stop(void* context); */ LevelDuration subghz_protocol_encoder_secplus_v2_yield(void* context); -/** - * Key generation from simple data. - * @param context Pointer to a SubGhzProtocolEncoderSecPlus_v2 instance - * @param flipper_format Pointer to a FlipperFormat instance - * @param serial Serial number, 32 bit - * @param btn Button number, 8 bit - * @param cnt Container value, 28 bit - * @param manufacture_name Name of manufacturer's key - * @param preset Modulation, SubGhzRadioPreset - * @return true On success - */ -bool subghz_protocol_secplus_v2_create_data( - void* context, - FlipperFormat* flipper_format, - uint32_t serial, - uint8_t btn, - uint32_t cnt, - SubGhzRadioPreset* preset); - /** * Allocate SubGhzProtocolDecoderSecPlus_v2. * @param environment Pointer to a SubGhzEnvironment instance diff --git a/lib/subghz/subghz_protocol_registry.h b/lib/subghz/subghz_protocol_registry.h index 8e80071b51..2dfa9ce8b6 100644 --- a/lib/subghz/subghz_protocol_registry.h +++ b/lib/subghz/subghz_protocol_registry.h @@ -10,29 +10,6 @@ extern const SubGhzProtocolRegistry subghz_protocol_registry; typedef struct SubGhzProtocolDecoderBinRAW SubGhzProtocolDecoderBinRAW; -bool subghz_protocol_secplus_v2_create_data( - void* context, - FlipperFormat* flipper_format, - uint32_t serial, - uint8_t btn, - uint32_t cnt, - SubGhzRadioPreset* preset); - -bool subghz_protocol_keeloq_create_data( - void* context, - FlipperFormat* flipper_format, - uint32_t serial, - uint8_t btn, - uint16_t cnt, - const char* manufacture_name, - SubGhzRadioPreset* preset); - -void subghz_protocol_decoder_bin_raw_data_input_rssi( - SubGhzProtocolDecoderBinRAW* instance, - float rssi); - -bool subghz_protocol_secplus_v1_check_fixed(uint32_t fixed); - #ifdef __cplusplus } #endif diff --git a/lib/toolbox/buffer_stream.c b/lib/toolbox/buffer_stream.c index 37b2514ef3..e8cb334d51 100644 --- a/lib/toolbox/buffer_stream.c +++ b/lib/toolbox/buffer_stream.c @@ -112,7 +112,7 @@ bool buffer_stream_send_from_isr(BufferStream* buffer_stream, const uint8_t* dat return result; } -Buffer* buffer_stream_receive(BufferStream* buffer_stream, TickType_t timeout) { +Buffer* buffer_stream_receive(BufferStream* buffer_stream, uint32_t timeout) { Buffer* buffer; size_t size = furi_stream_buffer_receive(buffer_stream->stream, &buffer, sizeof(Buffer*), timeout); diff --git a/lib/toolbox/buffer_stream.h b/lib/toolbox/buffer_stream.h index 9db5477532..5c3dc0a340 100644 --- a/lib/toolbox/buffer_stream.h +++ b/lib/toolbox/buffer_stream.h @@ -69,7 +69,7 @@ bool buffer_stream_send_from_isr(BufferStream* buffer_stream, const uint8_t* dat * @param timeout * @return Buffer* */ -Buffer* buffer_stream_receive(BufferStream* buffer_stream, TickType_t timeout); +Buffer* buffer_stream_receive(BufferStream* buffer_stream, uint32_t timeout); /** * @brief Get stream overrun count diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index cb62b40c40..3a2abc9b65 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,41.0,, +Version,+,43.2,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -417,7 +417,6 @@ Function,-,_perror_r,void,"_reent*, const char*" Function,-,_printf_r,int,"_reent*, const char*, ..." Function,-,_putc_r,int,"_reent*, int, FILE*" Function,-,_putc_unlocked_r,int,"_reent*, int, FILE*" -Function,-,_putchar,void,char Function,-,_putchar_r,int,"_reent*, int" Function,-,_putchar_unlocked_r,int,"_reent*, int" Function,-,_putenv_r,int,"_reent*, char*" @@ -751,8 +750,6 @@ Function,-,dprintf,int,"int, const char*, ..." Function,-,drand48,double, Function,-,drem,double,"double, double" Function,-,dremf,float,"float, float" -Function,-,eTaskConfirmSleepModeStatus,eSleepModeStatus, -Function,-,eTaskGetState,eTaskState,TaskHandle_t Function,+,elements_bold_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_bubble,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_bubble_str,void,"Canvas*, uint8_t, uint8_t, const char*, Align, Align" @@ -1342,6 +1339,7 @@ Function,+,furi_hal_vibro_on,void,_Bool Function,-,furi_init,void, Function,+,furi_kernel_get_tick_frequency,uint32_t, Function,+,furi_kernel_is_irq_or_masked,_Bool, +Function,+,furi_kernel_is_running,_Bool, Function,+,furi_kernel_lock,int32_t, Function,+,furi_kernel_restore_lock,int32_t,int32_t Function,+,furi_kernel_unlock,int32_t, @@ -1452,7 +1450,6 @@ Function,+,furi_string_utf8_push,void,"FuriString*, FuriStringUnicodeValue" Function,+,furi_string_vprintf,int,"FuriString*, const char[], va_list" Function,+,furi_thread_alloc,FuriThread*, Function,+,furi_thread_alloc_ex,FuriThread*,"const char*, uint32_t, FuriThreadCallback, void*" -Function,+,furi_thread_catch,void, Function,-,furi_thread_disable_heap_trace,void,FuriThread* Function,+,furi_thread_enable_heap_trace,void,FuriThread* Function,+,furi_thread_enumerate,uint32_t,"FuriThreadId*, uint32_t" @@ -1493,8 +1490,11 @@ Function,+,furi_thread_suspend,void,FuriThreadId Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* +Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" +Function,+,furi_timer_restart,FuriStatus,FuriTimer* +Function,+,furi_timer_set_thread_priority,void,FuriTimerThreadPriority Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" @@ -1838,8 +1838,6 @@ Function,+,pb_read,_Bool,"pb_istream_t*, pb_byte_t*, size_t" Function,+,pb_release,void,"const pb_msgdesc_t*, void*" Function,+,pb_skip_field,_Bool,"pb_istream_t*, pb_wire_type_t" Function,+,pb_write,_Bool,"pb_ostream_t*, const pb_byte_t*, size_t" -Function,-,pcTaskGetName,char*,TaskHandle_t -Function,-,pcTimerGetName,const char*,TimerHandle_t Function,-,pclose,int,FILE* Function,-,perror,void,const char* Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*" @@ -1914,12 +1912,6 @@ Function,-,putchar_unlocked,int,int Function,-,putenv,int,char* Function,-,puts,int,const char* Function,-,putw,int,"int, FILE*" -Function,-,pvPortCalloc,void*,"size_t, size_t" -Function,-,pvPortMalloc,void*,size_t -Function,-,pvTaskGetThreadLocalStoragePointer,void*,"TaskHandle_t, BaseType_t" -Function,-,pvTaskIncrementMutexHeldCount,TaskHandle_t, -Function,-,pvTimerGetTimerID,void*,const TimerHandle_t -Function,-,pxPortInitialiseStack,StackType_t*,"StackType_t*, TaskFunction_t, void*" Function,-,qsort,void,"void*, size_t, size_t, __compar_fn_t" Function,-,qsort_r,void,"void*, size_t, size_t, int (*)(const void*, const void*, void*), void*" Function,-,quick_exit,void,int @@ -1949,7 +1941,7 @@ Function,-,round,double,double Function,+,roundf,float,float Function,-,roundl,long double,long double Function,+,rpc_session_close,void,RpcSession* -Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" +Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, uint32_t" Function,+,rpc_session_get_available_size,size_t,RpcSession* Function,+,rpc_session_get_owner,RpcOwner,RpcSession* Function,+,rpc_session_open,RpcSession*,"Rpc*, RpcOwner" @@ -2281,67 +2273,10 @@ Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve" Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve" Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int" -Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t" -Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t" -Function,-,ulTaskGetIdleRunTimeCounter,uint32_t, -Function,-,ulTaskGetIdleRunTimePercent,uint32_t, Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* Function,-,usbd_poll,void,usbd_device* Function,-,utoa,char*,"unsigned, char*, int" -Function,-,uxListRemove,UBaseType_t,ListItem_t* -Function,-,uxTaskGetNumberOfTasks,UBaseType_t, -Function,-,uxTaskGetStackHighWaterMark,UBaseType_t,TaskHandle_t -Function,-,uxTaskGetStackHighWaterMark2,uint16_t,TaskHandle_t -Function,-,uxTaskGetSystemState,UBaseType_t,"TaskStatus_t*, const UBaseType_t, uint32_t*" -Function,-,uxTaskGetTaskNumber,UBaseType_t,TaskHandle_t -Function,-,uxTaskPriorityGet,UBaseType_t,const TaskHandle_t -Function,-,uxTaskPriorityGetFromISR,UBaseType_t,const TaskHandle_t -Function,-,uxTaskResetEventItemValue,TickType_t, -Function,-,uxTimerGetReloadMode,UBaseType_t,TimerHandle_t -Function,-,uxTimerGetTimerNumber,UBaseType_t,TimerHandle_t -Function,-,vApplicationGetIdleTaskMemory,void,"StaticTask_t**, StackType_t**, uint32_t*" -Function,-,vApplicationGetTimerTaskMemory,void,"StaticTask_t**, StackType_t**, uint32_t*" -Function,-,vListInitialise,void,List_t* -Function,-,vListInitialiseItem,void,ListItem_t* -Function,-,vListInsert,void,"List_t*, ListItem_t*" -Function,-,vListInsertEnd,void,"List_t*, ListItem_t*" -Function,-,vPortDefineHeapRegions,void,const HeapRegion_t* -Function,-,vPortEndScheduler,void, -Function,+,vPortEnterCritical,void, -Function,+,vPortExitCritical,void, -Function,-,vPortFree,void,void* -Function,-,vPortGetHeapStats,void,HeapStats_t* -Function,-,vPortInitialiseBlocks,void, -Function,-,vPortSuppressTicksAndSleep,void,TickType_t -Function,-,vTaskAllocateMPURegions,void,"TaskHandle_t, const MemoryRegion_t*" -Function,-,vTaskDelay,void,const TickType_t -Function,-,vTaskDelete,void,TaskHandle_t -Function,-,vTaskEndScheduler,void, -Function,-,vTaskGenericNotifyGiveFromISR,void,"TaskHandle_t, UBaseType_t, BaseType_t*" -Function,-,vTaskGetInfo,void,"TaskHandle_t, TaskStatus_t*, BaseType_t, eTaskState" -Function,-,vTaskGetRunTimeStats,void,char* -Function,-,vTaskInternalSetTimeOutState,void,TimeOut_t* -Function,-,vTaskList,void,char* -Function,-,vTaskMissedYield,void, -Function,-,vTaskPlaceOnEventList,void,"List_t*, const TickType_t" -Function,-,vTaskPlaceOnEventListRestricted,void,"List_t*, TickType_t, const BaseType_t" -Function,-,vTaskPlaceOnUnorderedEventList,void,"List_t*, const TickType_t, const TickType_t" -Function,-,vTaskPriorityDisinheritAfterTimeout,void,"const TaskHandle_t, UBaseType_t" -Function,+,vTaskPrioritySet,void,"TaskHandle_t, UBaseType_t" -Function,-,vTaskRemoveFromUnorderedEventList,void,"ListItem_t*, const TickType_t" -Function,-,vTaskResume,void,TaskHandle_t -Function,-,vTaskSetTaskNumber,void,"TaskHandle_t, const UBaseType_t" -Function,-,vTaskSetThreadLocalStoragePointer,void,"TaskHandle_t, BaseType_t, void*" -Function,-,vTaskSetTimeOutState,void,TimeOut_t* -Function,-,vTaskStartScheduler,void, -Function,-,vTaskStepTick,void,TickType_t -Function,-,vTaskSuspend,void,TaskHandle_t -Function,-,vTaskSuspendAll,void, -Function,-,vTaskSwitchContext,void, -Function,-,vTimerSetReloadMode,void,"TimerHandle_t, const BaseType_t" -Function,-,vTimerSetTimerID,void,"TimerHandle_t, void*" -Function,-,vTimerSetTimerNumber,void,"TimerHandle_t, UBaseType_t" Function,+,validator_is_file_alloc_init,ValidatorIsFile*,"const char*, const char*, const char*" Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*" Function,+,validator_is_file_free,void,ValidatorIsFile* @@ -2456,43 +2391,6 @@ Function,+,widget_alloc,Widget*, Function,+,widget_free,void,Widget* Function,+,widget_get_view,View*,Widget* Function,+,widget_reset,void,Widget* -Function,-,xPortGetFreeHeapSize,size_t, -Function,-,xPortGetMinimumEverFreeHeapSize,size_t, -Function,-,xPortStartScheduler,BaseType_t, -Function,-,xTaskAbortDelay,BaseType_t,TaskHandle_t -Function,-,xTaskCallApplicationTaskHook,BaseType_t,"TaskHandle_t, void*" -Function,-,xTaskCatchUpTicks,BaseType_t,TickType_t -Function,-,xTaskCheckForTimeOut,BaseType_t,"TimeOut_t*, TickType_t*" -Function,-,xTaskCreate,BaseType_t,"TaskFunction_t, const char*, const uint16_t, void*, UBaseType_t, TaskHandle_t*" -Function,-,xTaskCreateStatic,TaskHandle_t,"TaskFunction_t, const char*, const uint32_t, void*, UBaseType_t, StackType_t*, StaticTask_t*" -Function,-,xTaskDelayUntil,BaseType_t,"TickType_t*, const TickType_t" -Function,-,xTaskGenericNotify,BaseType_t,"TaskHandle_t, UBaseType_t, uint32_t, eNotifyAction, uint32_t*" -Function,-,xTaskGenericNotifyFromISR,BaseType_t,"TaskHandle_t, UBaseType_t, uint32_t, eNotifyAction, uint32_t*, BaseType_t*" -Function,-,xTaskGenericNotifyStateClear,BaseType_t,"TaskHandle_t, UBaseType_t" -Function,-,xTaskGenericNotifyWait,BaseType_t,"UBaseType_t, uint32_t, uint32_t, uint32_t*, TickType_t" -Function,-,xTaskGetCurrentTaskHandle,TaskHandle_t, -Function,+,xTaskGetHandle,TaskHandle_t,const char* -Function,-,xTaskGetIdleTaskHandle,TaskHandle_t, -Function,+,xTaskGetSchedulerState,BaseType_t, -Function,+,xTaskGetTickCount,TickType_t, -Function,-,xTaskGetTickCountFromISR,TickType_t, -Function,-,xTaskIncrementTick,BaseType_t, -Function,-,xTaskPriorityDisinherit,BaseType_t,const TaskHandle_t -Function,-,xTaskPriorityInherit,BaseType_t,const TaskHandle_t -Function,-,xTaskRemoveFromEventList,BaseType_t,const List_t* -Function,-,xTaskResumeAll,BaseType_t, -Function,-,xTaskResumeFromISR,BaseType_t,TaskHandle_t -Function,-,xTimerCreate,TimerHandle_t,"const char*, const TickType_t, const BaseType_t, void*, TimerCallbackFunction_t" -Function,-,xTimerCreateStatic,TimerHandle_t,"const char*, const TickType_t, const BaseType_t, void*, TimerCallbackFunction_t, StaticTimer_t*" -Function,-,xTimerCreateTimerTask,BaseType_t, -Function,-,xTimerGenericCommand,BaseType_t,"TimerHandle_t, const BaseType_t, const TickType_t, BaseType_t*, const TickType_t" -Function,-,xTimerGetExpiryTime,TickType_t,TimerHandle_t -Function,-,xTimerGetPeriod,TickType_t,TimerHandle_t -Function,-,xTimerGetReloadMode,BaseType_t,TimerHandle_t -Function,-,xTimerGetTimerDaemonTaskHandle,TaskHandle_t, -Function,-,xTimerIsTimerActive,BaseType_t,TimerHandle_t -Function,-,xTimerPendFunctionCall,BaseType_t,"PendedFunction_t, void*, uint32_t, TickType_t" -Function,-,xTimerPendFunctionCallFromISR,BaseType_t,"PendedFunction_t, void*, uint32_t, BaseType_t*" Function,-,y0,double,double Function,-,y0f,float,float Function,-,y1,double,double diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 9d9c1a01b3..0f81f11911 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,41.0,, +Version,+,43.2,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -179,6 +179,7 @@ Header,+,lib/subghz/blocks/math.h,, Header,+,lib/subghz/devices/cc1101_configs.h,, Header,+,lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h,, Header,+,lib/subghz/environment.h,, +Header,+,lib/subghz/protocols/public_api.h,, Header,+,lib/subghz/protocols/raw.h,, Header,+,lib/subghz/receiver.h,, Header,+,lib/subghz/registry.h,, @@ -485,7 +486,6 @@ Function,-,_perror_r,void,"_reent*, const char*" Function,-,_printf_r,int,"_reent*, const char*, ..." Function,-,_putc_r,int,"_reent*, int, FILE*" Function,-,_putc_unlocked_r,int,"_reent*, int, FILE*" -Function,-,_putchar,void,char Function,-,_putchar_r,int,"_reent*, int" Function,-,_putchar_unlocked_r,int,"_reent*, int" Function,-,_putenv_r,int,"_reent*, char*" @@ -839,8 +839,6 @@ Function,-,dprintf,int,"int, const char*, ..." Function,-,drand48,double, Function,-,drem,double,"double, double" Function,-,dremf,float,"float, float" -Function,-,eTaskConfirmSleepModeStatus,eSleepModeStatus, -Function,-,eTaskGetState,eTaskState,TaskHandle_t Function,+,elements_bold_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_bubble,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_bubble_str,void,"Canvas*, uint8_t, uint8_t, const char*, Align, Align" @@ -1536,6 +1534,7 @@ Function,+,furi_hal_vibro_on,void,_Bool Function,-,furi_init,void, Function,+,furi_kernel_get_tick_frequency,uint32_t, Function,+,furi_kernel_is_irq_or_masked,_Bool, +Function,+,furi_kernel_is_running,_Bool, Function,+,furi_kernel_lock,int32_t, Function,+,furi_kernel_restore_lock,int32_t,int32_t Function,+,furi_kernel_unlock,int32_t, @@ -1646,7 +1645,6 @@ Function,+,furi_string_utf8_push,void,"FuriString*, FuriStringUnicodeValue" Function,+,furi_string_vprintf,int,"FuriString*, const char[], va_list" Function,+,furi_thread_alloc,FuriThread*, Function,+,furi_thread_alloc_ex,FuriThread*,"const char*, uint32_t, FuriThreadCallback, void*" -Function,+,furi_thread_catch,void, Function,-,furi_thread_disable_heap_trace,void,FuriThread* Function,+,furi_thread_enable_heap_trace,void,FuriThread* Function,+,furi_thread_enumerate,uint32_t,"FuriThreadId*, uint32_t" @@ -1687,8 +1685,11 @@ Function,+,furi_thread_suspend,void,FuriThreadId Function,+,furi_thread_yield,void, Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" Function,+,furi_timer_free,void,FuriTimer* +Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" +Function,+,furi_timer_restart,FuriStatus,FuriTimer* +Function,+,furi_timer_set_thread_priority,void,FuriTimerThreadPriority Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" @@ -2380,8 +2381,6 @@ Function,+,pb_read,_Bool,"pb_istream_t*, pb_byte_t*, size_t" Function,+,pb_release,void,"const pb_msgdesc_t*, void*" Function,+,pb_skip_field,_Bool,"pb_istream_t*, pb_wire_type_t" Function,+,pb_write,_Bool,"pb_ostream_t*, const pb_byte_t*, size_t" -Function,-,pcTaskGetName,char*,TaskHandle_t -Function,-,pcTimerGetName,const char*,TimerHandle_t Function,-,pclose,int,FILE* Function,-,perror,void,const char* Function,+,plugin_manager_alloc,PluginManager*,"const char*, uint32_t, const ElfApiInterface*" @@ -2456,12 +2455,6 @@ Function,-,putchar_unlocked,int,int Function,-,putenv,int,char* Function,-,puts,int,const char* Function,-,putw,int,"int, FILE*" -Function,-,pvPortCalloc,void*,"size_t, size_t" -Function,-,pvPortMalloc,void*,size_t -Function,-,pvTaskGetThreadLocalStoragePointer,void*,"TaskHandle_t, BaseType_t" -Function,-,pvTaskIncrementMutexHeldCount,TaskHandle_t, -Function,-,pvTimerGetTimerID,void*,const TimerHandle_t -Function,-,pxPortInitialiseStack,StackType_t*,"StackType_t*, TaskFunction_t, void*" Function,-,qsort,void,"void*, size_t, size_t, __compar_fn_t" Function,-,qsort_r,void,"void*, size_t, size_t, int (*)(const void*, const void*, void*), void*" Function,-,quick_exit,void,int @@ -2491,7 +2484,7 @@ Function,-,round,double,double Function,+,roundf,float,float Function,-,roundl,long double,long double Function,+,rpc_session_close,void,RpcSession* -Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, TickType_t" +Function,+,rpc_session_feed,size_t,"RpcSession*, uint8_t*, size_t, uint32_t" Function,+,rpc_session_get_available_size,size_t,RpcSession* Function,+,rpc_session_get_owner,RpcOwner,RpcSession* Function,+,rpc_session_open,RpcSession*,"Rpc*, RpcOwner" @@ -3011,67 +3004,10 @@ Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve" Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve" Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int" -Function,-,ulTaskGenericNotifyTake,uint32_t,"UBaseType_t, BaseType_t, TickType_t" -Function,-,ulTaskGenericNotifyValueClear,uint32_t,"TaskHandle_t, UBaseType_t, uint32_t" -Function,-,ulTaskGetIdleRunTimeCounter,uint32_t, -Function,-,ulTaskGetIdleRunTimePercent,uint32_t, Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* Function,-,usbd_poll,void,usbd_device* Function,-,utoa,char*,"unsigned, char*, int" -Function,-,uxListRemove,UBaseType_t,ListItem_t* -Function,-,uxTaskGetNumberOfTasks,UBaseType_t, -Function,-,uxTaskGetStackHighWaterMark,UBaseType_t,TaskHandle_t -Function,-,uxTaskGetStackHighWaterMark2,uint16_t,TaskHandle_t -Function,-,uxTaskGetSystemState,UBaseType_t,"TaskStatus_t*, const UBaseType_t, uint32_t*" -Function,-,uxTaskGetTaskNumber,UBaseType_t,TaskHandle_t -Function,-,uxTaskPriorityGet,UBaseType_t,const TaskHandle_t -Function,-,uxTaskPriorityGetFromISR,UBaseType_t,const TaskHandle_t -Function,-,uxTaskResetEventItemValue,TickType_t, -Function,-,uxTimerGetReloadMode,UBaseType_t,TimerHandle_t -Function,-,uxTimerGetTimerNumber,UBaseType_t,TimerHandle_t -Function,-,vApplicationGetIdleTaskMemory,void,"StaticTask_t**, StackType_t**, uint32_t*" -Function,-,vApplicationGetTimerTaskMemory,void,"StaticTask_t**, StackType_t**, uint32_t*" -Function,-,vListInitialise,void,List_t* -Function,-,vListInitialiseItem,void,ListItem_t* -Function,-,vListInsert,void,"List_t*, ListItem_t*" -Function,-,vListInsertEnd,void,"List_t*, ListItem_t*" -Function,-,vPortDefineHeapRegions,void,const HeapRegion_t* -Function,-,vPortEndScheduler,void, -Function,+,vPortEnterCritical,void, -Function,+,vPortExitCritical,void, -Function,-,vPortFree,void,void* -Function,-,vPortGetHeapStats,void,HeapStats_t* -Function,-,vPortInitialiseBlocks,void, -Function,-,vPortSuppressTicksAndSleep,void,TickType_t -Function,-,vTaskAllocateMPURegions,void,"TaskHandle_t, const MemoryRegion_t*" -Function,-,vTaskDelay,void,const TickType_t -Function,-,vTaskDelete,void,TaskHandle_t -Function,-,vTaskEndScheduler,void, -Function,-,vTaskGenericNotifyGiveFromISR,void,"TaskHandle_t, UBaseType_t, BaseType_t*" -Function,-,vTaskGetInfo,void,"TaskHandle_t, TaskStatus_t*, BaseType_t, eTaskState" -Function,-,vTaskGetRunTimeStats,void,char* -Function,-,vTaskInternalSetTimeOutState,void,TimeOut_t* -Function,-,vTaskList,void,char* -Function,-,vTaskMissedYield,void, -Function,-,vTaskPlaceOnEventList,void,"List_t*, const TickType_t" -Function,-,vTaskPlaceOnEventListRestricted,void,"List_t*, TickType_t, const BaseType_t" -Function,-,vTaskPlaceOnUnorderedEventList,void,"List_t*, const TickType_t, const TickType_t" -Function,-,vTaskPriorityDisinheritAfterTimeout,void,"const TaskHandle_t, UBaseType_t" -Function,+,vTaskPrioritySet,void,"TaskHandle_t, UBaseType_t" -Function,-,vTaskRemoveFromUnorderedEventList,void,"ListItem_t*, const TickType_t" -Function,-,vTaskResume,void,TaskHandle_t -Function,-,vTaskSetTaskNumber,void,"TaskHandle_t, const UBaseType_t" -Function,-,vTaskSetThreadLocalStoragePointer,void,"TaskHandle_t, BaseType_t, void*" -Function,-,vTaskSetTimeOutState,void,TimeOut_t* -Function,-,vTaskStartScheduler,void, -Function,-,vTaskStepTick,void,TickType_t -Function,-,vTaskSuspend,void,TaskHandle_t -Function,-,vTaskSuspendAll,void, -Function,-,vTaskSwitchContext,void, -Function,-,vTimerSetReloadMode,void,"TimerHandle_t, const BaseType_t" -Function,-,vTimerSetTimerID,void,"TimerHandle_t, void*" -Function,-,vTimerSetTimerNumber,void,"TimerHandle_t, UBaseType_t" Function,+,validator_is_file_alloc_init,ValidatorIsFile*,"const char*, const char*, const char*" Function,+,validator_is_file_callback,_Bool,"const char*, FuriString*, void*" Function,+,validator_is_file_free,void,ValidatorIsFile* @@ -3186,43 +3122,6 @@ Function,+,widget_alloc,Widget*, Function,+,widget_free,void,Widget* Function,+,widget_get_view,View*,Widget* Function,+,widget_reset,void,Widget* -Function,-,xPortGetFreeHeapSize,size_t, -Function,-,xPortGetMinimumEverFreeHeapSize,size_t, -Function,-,xPortStartScheduler,BaseType_t, -Function,-,xTaskAbortDelay,BaseType_t,TaskHandle_t -Function,-,xTaskCallApplicationTaskHook,BaseType_t,"TaskHandle_t, void*" -Function,-,xTaskCatchUpTicks,BaseType_t,TickType_t -Function,-,xTaskCheckForTimeOut,BaseType_t,"TimeOut_t*, TickType_t*" -Function,-,xTaskCreate,BaseType_t,"TaskFunction_t, const char*, const uint16_t, void*, UBaseType_t, TaskHandle_t*" -Function,-,xTaskCreateStatic,TaskHandle_t,"TaskFunction_t, const char*, const uint32_t, void*, UBaseType_t, StackType_t*, StaticTask_t*" -Function,-,xTaskDelayUntil,BaseType_t,"TickType_t*, const TickType_t" -Function,-,xTaskGenericNotify,BaseType_t,"TaskHandle_t, UBaseType_t, uint32_t, eNotifyAction, uint32_t*" -Function,-,xTaskGenericNotifyFromISR,BaseType_t,"TaskHandle_t, UBaseType_t, uint32_t, eNotifyAction, uint32_t*, BaseType_t*" -Function,-,xTaskGenericNotifyStateClear,BaseType_t,"TaskHandle_t, UBaseType_t" -Function,-,xTaskGenericNotifyWait,BaseType_t,"UBaseType_t, uint32_t, uint32_t, uint32_t*, TickType_t" -Function,-,xTaskGetCurrentTaskHandle,TaskHandle_t, -Function,+,xTaskGetHandle,TaskHandle_t,const char* -Function,-,xTaskGetIdleTaskHandle,TaskHandle_t, -Function,+,xTaskGetSchedulerState,BaseType_t, -Function,+,xTaskGetTickCount,TickType_t, -Function,-,xTaskGetTickCountFromISR,TickType_t, -Function,-,xTaskIncrementTick,BaseType_t, -Function,-,xTaskPriorityDisinherit,BaseType_t,const TaskHandle_t -Function,-,xTaskPriorityInherit,BaseType_t,const TaskHandle_t -Function,-,xTaskRemoveFromEventList,BaseType_t,const List_t* -Function,-,xTaskResumeAll,BaseType_t, -Function,-,xTaskResumeFromISR,BaseType_t,TaskHandle_t -Function,-,xTimerCreate,TimerHandle_t,"const char*, const TickType_t, const BaseType_t, void*, TimerCallbackFunction_t" -Function,-,xTimerCreateStatic,TimerHandle_t,"const char*, const TickType_t, const BaseType_t, void*, TimerCallbackFunction_t, StaticTimer_t*" -Function,-,xTimerCreateTimerTask,BaseType_t, -Function,-,xTimerGenericCommand,BaseType_t,"TimerHandle_t, const BaseType_t, const TickType_t, BaseType_t*, const TickType_t" -Function,-,xTimerGetExpiryTime,TickType_t,TimerHandle_t -Function,-,xTimerGetPeriod,TickType_t,TimerHandle_t -Function,-,xTimerGetReloadMode,BaseType_t,TimerHandle_t -Function,-,xTimerGetTimerDaemonTaskHandle,TaskHandle_t, -Function,-,xTimerIsTimerActive,BaseType_t,TimerHandle_t -Function,-,xTimerPendFunctionCall,BaseType_t,"PendedFunction_t, void*, uint32_t, TickType_t" -Function,-,xTimerPendFunctionCallFromISR,BaseType_t,"PendedFunction_t, void*, uint32_t, BaseType_t*" Function,-,y0,double,double Function,-,y0f,float,float Function,-,y1,double,double diff --git a/targets/f7/ble_glue/gap.c b/targets/f7/ble_glue/gap.c index 360c1f6b68..f0533567ea 100644 --- a/targets/f7/ble_glue/gap.c +++ b/targets/f7/ble_glue/gap.c @@ -532,8 +532,6 @@ void gap_thread_stop() { // Free resources furi_mutex_free(gap->state_mutex); furi_message_queue_free(gap->command_queue); - furi_timer_stop(gap->advertise_timer); - while(xTimerIsTimerActive(gap->advertise_timer) == pdTRUE) furi_delay_tick(1); furi_timer_free(gap->advertise_timer); free(gap); gap = NULL; diff --git a/targets/f7/furi_hal/furi_hal_flash.c b/targets/f7/furi_hal/furi_hal_flash.c index bc65b29eb6..284d48bf53 100644 --- a/targets/f7/furi_hal/furi_hal_flash.c +++ b/targets/f7/furi_hal/furi_hal_flash.c @@ -11,6 +11,9 @@ #include +#include +#include + #define TAG "FuriHalFlash" #define FURI_HAL_CRITICAL_MSG "Critical flash operation fail" diff --git a/targets/f7/furi_hal/furi_hal_os.c b/targets/f7/furi_hal/furi_hal_os.c index 046cf79dc1..ea835b95fb 100644 --- a/targets/f7/furi_hal/furi_hal_os.c +++ b/targets/f7/furi_hal/furi_hal_os.c @@ -10,6 +10,9 @@ #include +#include +#include + #define TAG "FuriHalOs" #define FURI_HAL_IDLE_TIMER_CLK_HZ 32768 diff --git a/targets/f7/furi_hal/furi_hal_power.c b/targets/f7/furi_hal/furi_hal_power.c index 0eb93e664b..119dee81f9 100644 --- a/targets/f7/furi_hal/furi_hal_power.c +++ b/targets/f7/furi_hal/furi_hal_power.c @@ -459,10 +459,10 @@ void furi_hal_power_disable_external_3_3v() { } void furi_hal_power_suppress_charge_enter() { - vTaskSuspendAll(); + FURI_CRITICAL_ENTER(); bool disable_charging = furi_hal_power.suppress_charge == 0; furi_hal_power.suppress_charge++; - xTaskResumeAll(); + FURI_CRITICAL_EXIT(); if(disable_charging) { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); @@ -472,10 +472,10 @@ void furi_hal_power_suppress_charge_enter() { } void furi_hal_power_suppress_charge_exit() { - vTaskSuspendAll(); + FURI_CRITICAL_ENTER(); furi_hal_power.suppress_charge--; bool enable_charging = furi_hal_power.suppress_charge == 0; - xTaskResumeAll(); + FURI_CRITICAL_EXIT(); if(enable_charging) { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); diff --git a/targets/f7/furi_hal/furi_hal_spi.c b/targets/f7/furi_hal/furi_hal_spi.c index 5c33760ea1..98ca71af35 100644 --- a/targets/f7/furi_hal/furi_hal_spi.c +++ b/targets/f7/furi_hal/furi_hal_spi.c @@ -200,7 +200,7 @@ bool furi_hal_spi_bus_trx_dma( furi_assert(size > 0); // If scheduler is not running, use blocking mode - if(xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { + if(furi_kernel_is_running()) { return furi_hal_spi_bus_trx(handle, tx_buffer, rx_buffer, size, timeout_ms); } diff --git a/targets/f7/inc/FreeRTOSConfig.h b/targets/f7/inc/FreeRTOSConfig.h index 024d43a6de..3bc57f8f3b 100644 --- a/targets/f7/inc/FreeRTOSConfig.h +++ b/targets/f7/inc/FreeRTOSConfig.h @@ -3,13 +3,14 @@ #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) #include #pragma GCC diagnostic ignored "-Wredundant-decls" -extern uint32_t SystemCoreClock; #endif #ifndef CMSIS_device_header #define CMSIS_device_header "stm32wbxx.h" #endif /* CMSIS_device_header */ +#include CMSIS_device_header + #define configENABLE_FPU 1 #define configENABLE_MPU 0 diff --git a/targets/f7/inc/furi_config.h b/targets/f7/inc/furi_config.h new file mode 100644 index 0000000000..c935611ab7 --- /dev/null +++ b/targets/f7/inc/furi_config.h @@ -0,0 +1,3 @@ +#pragma once + +#define FURI_CONFIG_THREAD_MAX_PRIORITIES (32) \ No newline at end of file diff --git a/targets/f7/src/main.c b/targets/f7/src/main.c index 2c353f52b2..ca705fe5e4 100644 --- a/targets/f7/src/main.c +++ b/targets/f7/src/main.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #define TAG "Main" From 47cc05dab4beee6c1a7620c45b15abfb48b9916e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 2 Nov 2023 00:23:02 +0900 Subject: [PATCH 13/40] [FL-3655] Dolphin: Extreme butthurt loop fix (#3184) * Furi: change timer restart function signature, explicitly require timer time. Dolphin: fix incorrect timer usage caused by refactoring. * Format Sources * Furi: update timer documentation --- applications/services/dolphin/dolphin.c | 8 ++++---- furi/core/timer.c | 13 +++++++++---- furi/core/timer.h | 5 +++-- targets/f18/api_symbols.csv | 4 ++-- targets/f7/api_symbols.csv | 4 ++-- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index 5b526ed3a6..bef7c4a285 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -155,9 +155,9 @@ int32_t dolphin_srv(void* p) { furi_record_create(RECORD_DOLPHIN, dolphin); dolphin_state_load(dolphin->state); - furi_timer_stop(dolphin->butthurt_timer); + furi_timer_restart(dolphin->butthurt_timer, HOURS_IN_TICKS(2 * 24)); dolphin_update_clear_limits_timer_period(dolphin); - furi_timer_stop(dolphin->clear_limits_timer); + furi_timer_restart(dolphin->clear_limits_timer, HOURS_IN_TICKS(24)); DolphinEvent event; while(1) { @@ -167,8 +167,8 @@ int32_t dolphin_srv(void* p) { dolphin_state_on_deed(dolphin->state, event.deed); DolphinPubsubEvent event = DolphinPubsubEventUpdate; furi_pubsub_publish(dolphin->pubsub, &event); - furi_timer_restart(dolphin->butthurt_timer); - furi_timer_restart(dolphin->flush_timer); + furi_timer_restart(dolphin->butthurt_timer, HOURS_IN_TICKS(2 * 24)); + furi_timer_restart(dolphin->flush_timer, 30 * 1000); } else if(event.type == DolphinEventTypeStats) { event.stats->icounter = dolphin->state->data.icounter; event.stats->butthurt = dolphin->state->data.butthurt; diff --git a/furi/core/timer.c b/furi/core/timer.c index 0a89b89201..17347e5c7d 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -51,7 +51,7 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co callb = (TimerCallback_t*)((uint32_t)callb | 1U); // TimerCallback function is always provided as a callback and is used to call application // specified function with its context both stored in structure callb. - hTimer = xTimerCreate(NULL, 1, reload, callb, TimerCallback); + hTimer = xTimerCreate(NULL, portMAX_DELAY, reload, callb, TimerCallback); furi_check(hTimer); /* Return timer ID */ @@ -83,6 +83,7 @@ void furi_timer_free(FuriTimer* instance) { FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); + furi_assert(ticks < portMAX_DELAY); TimerHandle_t hTimer = (TimerHandle_t)instance; FuriStatus stat; @@ -97,14 +98,16 @@ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks) { return (stat); } -FuriStatus furi_timer_restart(FuriTimer* instance) { +FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks) { furi_assert(!furi_kernel_is_irq_or_masked()); furi_assert(instance); + furi_assert(ticks < portMAX_DELAY); TimerHandle_t hTimer = (TimerHandle_t)instance; FuriStatus stat; - if(xTimerReset(hTimer, portMAX_DELAY) == pdPASS) { + if(xTimerChangePeriod(hTimer, ticks, portMAX_DELAY) == pdPASS && + xTimerReset(hTimer, portMAX_DELAY) == pdPASS) { stat = FuriStatusOk; } else { stat = FuriStatusErrorResource; @@ -163,7 +166,9 @@ void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context void furi_timer_set_thread_priority(FuriTimerThreadPriority priority) { furi_assert(!furi_kernel_is_irq_or_masked()); - TaskHandle_t task_handle = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + + TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle(); + furi_check(task_handle); // Don't call this method before timer task start if(priority == FuriTimerThreadPriorityNormal) { vTaskPrioritySet(task_handle, configTIMER_TASK_PRIORITY); diff --git a/furi/core/timer.h b/furi/core/timer.h index 47b44c71a6..d27ef5025e 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -34,7 +34,7 @@ void furi_timer_free(FuriTimer* instance); /** Start timer * * @param instance The pointer to FuriTimer instance - * @param[in] ticks The ticks + * @param[in] ticks The interval in ticks * * @return The furi status. */ @@ -43,10 +43,11 @@ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks); /** Restart timer with previous timeout value * * @param instance The pointer to FuriTimer instance + * @param[in] ticks The interval in ticks * * @return The furi status. */ -FuriStatus furi_timer_restart(FuriTimer* instance); +FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks); /** Stop timer * diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 3a2abc9b65..5f8e836c00 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,43.2,, +Version,+,44.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1493,7 +1493,7 @@ Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" -Function,+,furi_timer_restart,FuriStatus,FuriTimer* +Function,+,furi_timer_restart,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_set_thread_priority,void,FuriTimerThreadPriority Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 0f81f11911..57adf96aec 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,43.2,, +Version,+,44.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -1688,7 +1688,7 @@ Function,+,furi_timer_free,void,FuriTimer* Function,+,furi_timer_get_expire_time,uint32_t,FuriTimer* Function,+,furi_timer_is_running,uint32_t,FuriTimer* Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" -Function,+,furi_timer_restart,FuriStatus,FuriTimer* +Function,+,furi_timer_restart,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_set_thread_priority,void,FuriTimerThreadPriority Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" Function,+,furi_timer_stop,FuriStatus,FuriTimer* From 0131eb3aa29568d593d8a581d6d7d2c0bd10c2df Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:10:16 +0300 Subject: [PATCH 14/40] [FL-3656] Fix crash when exiting write mode (#3191) --- .../main/ibutton/ibutton_custom_event.h | 8 +++-- .../main/ibutton/scenes/ibutton_scene_write.c | 29 ++++++++++++++----- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/applications/main/ibutton/ibutton_custom_event.h b/applications/main/ibutton/ibutton_custom_event.h index 28bcb94a0d..1ac50ee3cf 100644 --- a/applications/main/ibutton/ibutton_custom_event.h +++ b/applications/main/ibutton/ibutton_custom_event.h @@ -1,6 +1,6 @@ #pragma once -enum iButtonCustomEvent { +typedef enum { // Reserve first 100 events for button types and indexes, starting from 0 iButtonCustomEventReserved = 100, @@ -10,8 +10,12 @@ enum iButtonCustomEvent { iButtonCustomEventByteEditResult, iButtonCustomEventWorkerEmulated, iButtonCustomEventWorkerRead, + iButtonCustomEventWorkerWriteOK, + iButtonCustomEventWorkerWriteSameKey, + iButtonCustomEventWorkerWriteNoDetect, + iButtonCustomEventWorkerWriteCannotWrite, iButtonCustomEventRpcLoad, iButtonCustomEventRpcExit, iButtonCustomEventRpcSessionClose, -}; +} iButtonCustomEvent; diff --git a/applications/main/ibutton/scenes/ibutton_scene_write.c b/applications/main/ibutton/scenes/ibutton_scene_write.c index 541aa1c52b..63be635069 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_write.c +++ b/applications/main/ibutton/scenes/ibutton_scene_write.c @@ -5,9 +5,26 @@ typedef enum { iButtonSceneWriteStateBlinkYellow, } iButtonSceneWriteState; +static inline iButtonCustomEvent + ibutton_scene_write_to_custom_event(iButtonWorkerWriteResult result) { + switch(result) { + case iButtonWorkerWriteOK: + return iButtonCustomEventWorkerWriteOK; + case iButtonWorkerWriteSameKey: + return iButtonCustomEventWorkerWriteSameKey; + case iButtonWorkerWriteNoDetect: + return iButtonCustomEventWorkerWriteNoDetect; + case iButtonWorkerWriteCannotWrite: + return iButtonCustomEventWorkerWriteCannotWrite; + default: + furi_crash(); + } +} + static void ibutton_scene_write_callback(void* context, iButtonWorkerWriteResult result) { iButton* ibutton = context; - view_dispatcher_send_custom_event(ibutton->view_dispatcher, result); + view_dispatcher_send_custom_event( + ibutton->view_dispatcher, ibutton_scene_write_to_custom_event(result)); } void ibutton_scene_write_on_enter(void* context) { @@ -61,16 +78,14 @@ bool ibutton_scene_write_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { consumed = true; - if((event.event == iButtonWorkerWriteOK) || (event.event == iButtonWorkerWriteSameKey)) { + if((event.event == iButtonCustomEventWorkerWriteOK) || + (event.event == iButtonCustomEventWorkerWriteSameKey)) { scene_manager_next_scene(scene_manager, iButtonSceneWriteSuccess); - } else if(event.event == iButtonWorkerWriteNoDetect) { + } else if(event.event == iButtonCustomEventWorkerWriteNoDetect) { ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateBlink); - } else if(event.event == iButtonWorkerWriteCannotWrite) { + } else if(event.event == iButtonCustomEventWorkerWriteCannotWrite) { ibutton_notification_message(ibutton, iButtonNotificationMessageYellowBlink); } - - } else if(event.type == SceneManagerEventTypeTick) { - consumed = true; } return consumed; From 0d94abf85693c0eb9eee53f8d0a83692e6390ff8 Mon Sep 17 00:00:00 2001 From: hedger Date: Thu, 2 Nov 2023 17:28:39 +0400 Subject: [PATCH 15/40] fbt: dist improvements (#3186) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fbt: MENUEXTERNAL apps now respect build configuration; fixed `fap_deploy` * fbt, ufbt: better message for missing app manifests (shows real paths) Co-authored-by: あく --- SConstruct | 1 + scripts/fbt/appmanifest.py | 22 +++++++++++++--------- scripts/fbt_tools/fbt_apps.py | 7 ++++++- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/SConstruct b/SConstruct index faccdfa5b3..97d7e5e5e2 100644 --- a/SConstruct +++ b/SConstruct @@ -185,6 +185,7 @@ fap_deploy = distenv.PhonyTarget( ], source=firmware_env.Dir(("${RESOURCES_ROOT}/apps")), ) +Depends(fap_deploy, firmware_env["FW_RESOURCES_MANIFEST"]) # Target for bundling core2 package for qFlipper diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 3a3640d425..bef4eb02b1 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -240,12 +240,12 @@ class AppBuildset: FlipperAppType.SETTINGS, FlipperAppType.STARTUP, ) - EXTERNAL_APP_TYPES = ( - FlipperAppType.EXTERNAL, - FlipperAppType.MENUEXTERNAL, - FlipperAppType.PLUGIN, - FlipperAppType.DEBUG, - ) + EXTERNAL_APP_TYPES_MAP = { + FlipperAppType.EXTERNAL: True, + FlipperAppType.PLUGIN: True, + FlipperAppType.DEBUG: True, + FlipperAppType.MENUEXTERNAL: False, + } @staticmethod def print_writer(message): @@ -318,8 +318,8 @@ class AppBuildset: def _process_ext_apps(self): extapps = [ app - for apptype in self.EXTERNAL_APP_TYPES - for app in self.get_apps_of_type(apptype, True) + for (apptype, global_lookup) in self.EXTERNAL_APP_TYPES_MAP.items() + for app in self.get_apps_of_type(apptype, global_lookup) ] extapps.extend(map(self.appmgr.get, self._extra_ext_appnames)) @@ -407,10 +407,14 @@ class AppBuildset: return sdk_headers def get_apps_of_type(self, apptype: FlipperAppType, all_known: bool = False): + """Looks up apps of given type in current app set. If all_known is true, + ignores app set and checks all loaded apps' manifests.""" return sorted( filter( lambda app: app.apptype == apptype, - self.appmgr.known_apps.values() if all_known else self._apps, + self.appmgr.known_apps.values() + if all_known + else map(self.appmgr.get, self.appnames), ), key=lambda app: app.order, ) diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index 9a07180552..edce194f07 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -21,8 +21,13 @@ def LoadAppManifest(env, entry): APP_MANIFEST_NAME = "application.fam" manifest_glob = entry.glob(APP_MANIFEST_NAME) if len(manifest_glob) == 0: + try: + disk_node = next(filter(lambda d: d.exists(), entry.get_all_rdirs())) + except Exception: + disk_node = entry + raise FlipperManifestException( - f"Folder {entry}: manifest {APP_MANIFEST_NAME} is missing" + f"App folder '{disk_node.abspath}': missing manifest ({APP_MANIFEST_NAME})" ) app_manifest_file_path = manifest_glob[0].rfile().abspath From 085c90af40f66350af26038342b3c3f2fe6e64d6 Mon Sep 17 00:00:00 2001 From: DerSkythe <31771569+derskythe@users.noreply.github.com> Date: Sun, 5 Nov 2023 17:59:22 +0400 Subject: [PATCH 16/40] fix: invariant format of log time data #3195 (#3202) --- scripts/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/version.py b/scripts/version.py index e68f7b41d7..4b1c739bc5 100755 --- a/scripts/version.py +++ b/scripts/version.py @@ -46,7 +46,7 @@ class GitVersion: ) else: commit_date = datetime.strptime( - self._exec_git("log -1 --format=%cd").strip(), + self._exec_git("log -1 --format=%cd --date=default").strip(), "%a %b %d %H:%M:%S %Y %z", ) From 16ffa2bf75e6acbecc0b0d48f792a630525c0db2 Mon Sep 17 00:00:00 2001 From: gornekich Date: Thu, 9 Nov 2023 10:18:36 +0400 Subject: [PATCH 17/40] [FL-3657] Fix NFC unit tests (#3192) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/nfc/helpers/nfc_data_generator.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 2783051622..011f9f6db7 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -28,6 +28,7 @@ static const uint8_t default_config_ntag_i2c[] = {0x01, 0x00, 0xF8, 0x48, 0x08, static void nfc_generate_mf_ul_uid(uint8_t* uid) { uid[0] = NXP_MANUFACTURER_ID; furi_hal_random_fill_buf(&uid[1], 6); + uid[3] |= 0x01; // To avoid forbidden 0x88 value // I'm not sure how this is generated, but the upper nybble always seems to be 8 uid[6] &= 0x0F; uid[6] |= 0x80; @@ -322,6 +323,7 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDevice* nfc_device) { static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { uid[0] = NXP_MANUFACTURER_ID; furi_hal_random_fill_buf(&uid[1], length - 1); + uid[3] |= 0x01; // To avoid forbidden 0x88 value } static void From 49dcf81743859c17ee332f882e838500206f8039 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Fri, 10 Nov 2023 10:22:34 +0300 Subject: [PATCH 18/40] [FL-3618] Infrared remote button index support (#3180) * Do not load all signals at once (Draft) * Minor cleanup * Refactor remote renaming * Improve function signatures * Rename infrared_remote functions * Optimise signal loading * Implement adding signals to remote * Add read_name() method * Deprecate a function * Partially implement deleting signals (draft) * Use m-array instead of m-list for signal name directory * Use plain C strings instead of furi_string * Implement deleting signals * Implement deleting signals via generalised callback * Implement renaming signals * Rename some types * Some more renaming * Remove unused type * Implement inserting signals (internal use) * Improve InfraredMoveView * Send an event to move a signal * Remove unused type * Implement moving signals * Implement creating new remotes with one signal * Un-deprecate and rename a function * Add InfraredRemote API docs * Add InfraredSignal API docs * Better error messages * Show progress pop-up when moving buttons in a remote * Copy labels to the InfraredMoveView to avoid pointer invalidation * Improve file selection scene * Show progress pop-up when renaming buttons in a remote * Refactor a scene * Show progress when deleting a button from remote * Use a random name for temp files * Add docs to infrared_brute_force.h * Rename Infrared type to InfraredApp * Add docs to infrared_app_i.h * Deliver event data via a callback * Bundle event data together with event type * Change DataExchange behaviour * Adapt RPC debug app to new API * Remove rogue output * Add Doxygen comments to rpc_app.h * Simplify rpc_app.c code * Remove superflous parameter * Do not allocate protobuf messages on the stack * Fix GetError response * Support for button indices * Comment out shallow submodules * Fix F18 api * Fix logical error and add more debug output * fbt: testing unshallow for protobuf * github: lint&checks: unshallow prior to checks * Fix a TODO * github: do not unshallow the unshallowed * fbt: assets: only attempt to unshallow if cannot describe * Do not use the name when loading a signal by index (duh) * Simplify loading infrared signals by name * Sync with protobuf release * Infrared: use compact furi_crash macros Co-authored-by: hedger Co-authored-by: hedger Co-authored-by: Aleksandr Kutuzov --- .../workflows/lint_and_submodule_check.yml | 2 +- .../debug/rpc_debug_app/rpc_debug_app.c | 39 +- ...pc_debug_app_scene_receive_data_exchange.c | 39 +- applications/main/ibutton/ibutton.c | 14 +- .../main/ibutton/ibutton_custom_event.h | 2 +- .../main/ibutton/scenes/ibutton_scene_rpc.c | 23 +- applications/main/infrared/infrared_app.c | 34 +- applications/main/infrared/infrared_app_i.h | 1 + .../main/infrared/infrared_brute_force.c | 2 +- .../main/infrared/infrared_custom_event.h | 5 +- applications/main/infrared/infrared_remote.c | 7 +- applications/main/infrared/infrared_signal.c | 36 +- applications/main/infrared/infrared_signal.h | 21 +- .../infrared/scenes/infrared_scene_remote.c | 6 +- .../main/infrared/scenes/infrared_scene_rpc.c | 45 +- applications/main/lfrfid/lfrfid.c | 12 +- .../main/lfrfid/scenes/lfrfid_scene_rpc.c | 8 +- .../main/nfc/helpers/nfc_custom_event.h | 2 +- .../protocol_support/nfc_protocol_support.c | 16 +- applications/main/nfc/nfc_app.c | 14 +- .../main/subghz/scenes/subghz_scene_rpc.c | 16 +- applications/main/subghz/subghz.c | 16 +- applications/services/rpc/rpc.c | 3 + applications/services/rpc/rpc_app.c | 463 +++++++++--------- applications/services/rpc/rpc_app.h | 202 +++++++- assets/protobuf | 2 +- scripts/fbt_tools/fbt_assets.py | 43 +- targets/f18/api_symbols.csv | 4 +- targets/f7/api_symbols.csv | 4 +- 29 files changed, 668 insertions(+), 413 deletions(-) diff --git a/.github/workflows/lint_and_submodule_check.yml b/.github/workflows/lint_and_submodule_check.yml index 51e2593ecc..3f4d8c79bd 100644 --- a/.github/workflows/lint_and_submodule_check.yml +++ b/.github/workflows/lint_and_submodule_check.yml @@ -23,7 +23,7 @@ jobs: - name: 'Check protobuf branch' run: | - git submodule update --init + git submodule update --init; SUB_PATH="assets/protobuf"; SUB_BRANCH="dev"; SUB_COMMITS_MIN=40; diff --git a/applications/debug/rpc_debug_app/rpc_debug_app.c b/applications/debug/rpc_debug_app/rpc_debug_app.c index 314be5e722..2a0756383c 100644 --- a/applications/debug/rpc_debug_app/rpc_debug_app.c +++ b/applications/debug/rpc_debug_app/rpc_debug_app.c @@ -21,22 +21,51 @@ static void rpc_debug_app_tick_event_callback(void* context) { scene_manager_handle_tick_event(app->scene_manager); } -static void rpc_debug_app_rpc_command_callback(RpcAppSystemEvent event, void* context) { +static void + rpc_debug_app_format_hex(const uint8_t* data, size_t data_size, char* buf, size_t buf_size) { + if(data == NULL || data_size == 0) { + strncpy(buf, "", buf_size); + return; + } + + const size_t byte_width = 3; + const size_t line_width = 7; + + data_size = MIN(data_size, buf_size / (byte_width + 1)); + + for(size_t i = 0; i < data_size; ++i) { + char* p = buf + (i * byte_width); + char sep = !((i + 1) % line_width) ? '\n' : ' '; + snprintf(p, byte_width + 1, "%02X%c", data[i], sep); + } + + buf[buf_size - 1] = '\0'; +} + +static void rpc_debug_app_rpc_command_callback(const RpcAppSystemEvent* event, void* context) { furi_assert(context); RpcDebugApp* app = context; furi_assert(app->rpc); - if(event == RpcAppEventSessionClose) { + if(event->type == RpcAppEventTypeSessionClose) { scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); rpc_system_app_set_callback(app->rpc, NULL, NULL); app->rpc = NULL; - } else if(event == RpcAppEventAppExit) { + } else if(event->type == RpcAppEventTypeAppExit) { scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); - rpc_system_app_confirm(app->rpc, RpcAppEventAppExit, true); + rpc_system_app_confirm(app->rpc, true); + } else if(event->type == RpcAppEventTypeDataExchange) { + furi_assert(event->data.type == RpcAppSystemEventDataTypeBytes); + + rpc_debug_app_format_hex( + event->data.bytes.ptr, event->data.bytes.size, app->text_store, TEXT_STORE_SIZE); + + view_dispatcher_send_custom_event( + app->view_dispatcher, RpcDebugAppCustomEventRpcDataExchange); } else { - rpc_system_app_confirm(app->rpc, event, false); + rpc_system_app_confirm(app->rpc, false); } } diff --git a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_receive_data_exchange.c b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_receive_data_exchange.c index 98bafff8a7..10d5e36f62 100644 --- a/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_receive_data_exchange.c +++ b/applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_receive_data_exchange.c @@ -1,40 +1,5 @@ #include "../rpc_debug_app.h" -static void rpc_debug_app_scene_start_format_hex( - const uint8_t* data, - size_t data_size, - char* buf, - size_t buf_size) { - furi_assert(data); - furi_assert(buf); - - const size_t byte_width = 3; - const size_t line_width = 7; - - data_size = MIN(data_size, buf_size / (byte_width + 1)); - - for(size_t i = 0; i < data_size; ++i) { - char* p = buf + (i * byte_width); - char sep = !((i + 1) % line_width) ? '\n' : ' '; - snprintf(p, byte_width + 1, "%02X%c", data[i], sep); - } - - buf[buf_size - 1] = '\0'; -} - -static void rpc_debug_app_scene_receive_data_exchange_callback( - const uint8_t* data, - size_t data_size, - void* context) { - RpcDebugApp* app = context; - if(data) { - rpc_debug_app_scene_start_format_hex(data, data_size, app->text_store, TEXT_STORE_SIZE); - } else { - strncpy(app->text_store, "", TEXT_STORE_SIZE); - } - view_dispatcher_send_custom_event(app->view_dispatcher, RpcDebugAppCustomEventRpcDataExchange); -} - void rpc_debug_app_scene_receive_data_exchange_on_enter(void* context) { RpcDebugApp* app = context; strncpy(app->text_store, "Received data will appear here...", TEXT_STORE_SIZE); @@ -42,8 +7,6 @@ void rpc_debug_app_scene_receive_data_exchange_on_enter(void* context) { text_box_set_text(app->text_box, app->text_store); text_box_set_font(app->text_box, TextBoxFontHex); - rpc_system_app_set_data_exchange_callback( - app->rpc, rpc_debug_app_scene_receive_data_exchange_callback, app); view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewTextBox); } @@ -53,6 +16,7 @@ bool rpc_debug_app_scene_receive_data_exchange_on_event(void* context, SceneMana if(event.type == SceneManagerEventTypeCustom) { if(event.event == RpcDebugAppCustomEventRpcDataExchange) { + rpc_system_app_confirm(app->rpc, true); notification_message(app->notifications, &sequence_blink_cyan_100); notification_message(app->notifications, &sequence_display_backlight_on); text_box_set_text(app->text_box, app->text_store); @@ -66,5 +30,4 @@ bool rpc_debug_app_scene_receive_data_exchange_on_event(void* context, SceneMana void rpc_debug_app_scene_receive_data_exchange_on_exit(void* context) { RpcDebugApp* app = context; text_box_reset(app->text_box); - rpc_system_app_set_data_exchange_callback(app->rpc, NULL, NULL); } diff --git a/applications/main/ibutton/ibutton.c b/applications/main/ibutton/ibutton.c index 760918097f..fb6d9dcb52 100644 --- a/applications/main/ibutton/ibutton.c +++ b/applications/main/ibutton/ibutton.c @@ -39,21 +39,23 @@ static void ibutton_make_app_folder(iButton* ibutton) { furi_record_close(RECORD_STORAGE); } -static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) { +static void ibutton_rpc_command_callback(const RpcAppSystemEvent* event, void* context) { furi_assert(context); iButton* ibutton = context; - if(event == RpcAppEventSessionClose) { + if(event->type == RpcAppEventTypeSessionClose) { view_dispatcher_send_custom_event( ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose); rpc_system_app_set_callback(ibutton->rpc, NULL, NULL); ibutton->rpc = NULL; - } else if(event == RpcAppEventAppExit) { + } else if(event->type == RpcAppEventTypeAppExit) { view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); - } else if(event == RpcAppEventLoadFile) { - view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcLoad); + } else if(event->type == RpcAppEventTypeLoadFile) { + furi_assert(event->data.type == RpcAppSystemEventDataTypeString); + furi_string_set(ibutton->file_path, event->data.string); + view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcLoadFile); } else { - rpc_system_app_confirm(ibutton->rpc, event, false); + rpc_system_app_confirm(ibutton->rpc, false); } } diff --git a/applications/main/ibutton/ibutton_custom_event.h b/applications/main/ibutton/ibutton_custom_event.h index 1ac50ee3cf..b0246d3109 100644 --- a/applications/main/ibutton/ibutton_custom_event.h +++ b/applications/main/ibutton/ibutton_custom_event.h @@ -15,7 +15,7 @@ typedef enum { iButtonCustomEventWorkerWriteNoDetect, iButtonCustomEventWorkerWriteCannotWrite, - iButtonCustomEventRpcLoad, + iButtonCustomEventRpcLoadFile, iButtonCustomEventRpcExit, iButtonCustomEventRpcSessionClose, } iButtonCustomEvent; diff --git a/applications/main/ibutton/scenes/ibutton_scene_rpc.c b/applications/main/ibutton/scenes/ibutton_scene_rpc.c index 9205eb4b46..7106fefaa2 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_rpc.c +++ b/applications/main/ibutton/scenes/ibutton_scene_rpc.c @@ -23,28 +23,23 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { consumed = true; - if(event.event == iButtonCustomEventRpcLoad) { + if(event.event == iButtonCustomEventRpcLoadFile) { bool result = false; - const char* file_path = rpc_system_app_get_data(ibutton->rpc); - if(file_path && (furi_string_empty(ibutton->file_path))) { - furi_string_set(ibutton->file_path, file_path); + if(ibutton_load_key(ibutton)) { + popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop); + view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); - if(ibutton_load_key(ibutton)) { - popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop); - view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); + ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); + ibutton_worker_emulate_start(ibutton->worker, ibutton->key); - ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); - ibutton_worker_emulate_start(ibutton->worker, ibutton->key); - - result = true; - } + result = true; } - rpc_system_app_confirm(ibutton->rpc, RpcAppEventLoadFile, result); + rpc_system_app_confirm(ibutton->rpc, result); } else if(event.event == iButtonCustomEventRpcExit) { - rpc_system_app_confirm(ibutton->rpc, RpcAppEventAppExit, true); + rpc_system_app_confirm(ibutton->rpc, true); scene_manager_stop(ibutton->scene_manager); view_dispatcher_stop(ibutton->view_dispatcher); diff --git a/applications/main/infrared/infrared_app.c b/applications/main/infrared/infrared_app.c index 7abb4e4eb6..645659bbc5 100644 --- a/applications/main/infrared/infrared_app.c +++ b/applications/main/infrared/infrared_app.c @@ -44,30 +44,42 @@ static void infrared_tick_event_callback(void* context) { scene_manager_handle_tick_event(infrared->scene_manager); } -static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context) { +static void infrared_rpc_command_callback(const RpcAppSystemEvent* event, void* context) { furi_assert(context); InfraredApp* infrared = context; furi_assert(infrared->rpc_ctx); - if(event == RpcAppEventSessionClose) { + if(event->type == RpcAppEventTypeSessionClose) { view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeRpcSessionClose); rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL); infrared->rpc_ctx = NULL; - } else if(event == RpcAppEventAppExit) { + } else if(event->type == RpcAppEventTypeAppExit) { view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeRpcExit); - } else if(event == RpcAppEventLoadFile) { + } else if(event->type == RpcAppEventTypeLoadFile) { + furi_assert(event->data.type == RpcAppSystemEventDataTypeString); + furi_string_set(infrared->file_path, event->data.string); view_dispatcher_send_custom_event( - infrared->view_dispatcher, InfraredCustomEventTypeRpcLoad); - } else if(event == RpcAppEventButtonPress) { - view_dispatcher_send_custom_event( - infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPress); - } else if(event == RpcAppEventButtonRelease) { + infrared->view_dispatcher, InfraredCustomEventTypeRpcLoadFile); + } else if(event->type == RpcAppEventTypeButtonPress) { + furi_assert( + event->data.type == RpcAppSystemEventDataTypeString || + event->data.type == RpcAppSystemEventDataTypeInt32); + if(event->data.type == RpcAppSystemEventDataTypeString) { + furi_string_set(infrared->button_name, event->data.string); + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressName); + } else { + infrared->app_state.current_button_index = event->data.i32; + view_dispatcher_send_custom_event( + infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPressIndex); + } + } else if(event->type == RpcAppEventTypeButtonRelease) { view_dispatcher_send_custom_event( infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonRelease); } else { - rpc_system_app_confirm(infrared->rpc_ctx, event, false); + rpc_system_app_confirm(infrared->rpc_ctx, false); } } @@ -117,6 +129,7 @@ static InfraredApp* infrared_alloc() { InfraredApp* infrared = malloc(sizeof(InfraredApp)); infrared->file_path = furi_string_alloc(); + infrared->button_name = furi_string_alloc(); InfraredAppState* app_state = &infrared->app_state; app_state->is_learning_new_remote = false; @@ -247,6 +260,7 @@ static void infrared_free(InfraredApp* infrared) { infrared->gui = NULL; furi_string_free(infrared->file_path); + furi_string_free(infrared->button_name); free(infrared); } diff --git a/applications/main/infrared/infrared_app_i.h b/applications/main/infrared/infrared_app_i.h index c9dfe3ab86..c35d3fa410 100644 --- a/applications/main/infrared/infrared_app_i.h +++ b/applications/main/infrared/infrared_app_i.h @@ -121,6 +121,7 @@ struct InfraredApp { InfraredProgressView* progress; /**< Custom view for showing brute force progress. */ FuriString* file_path; /**< Full path to the currently loaded file. */ + FuriString* button_name; /** Name of the button requested in RPC mode. */ /** Arbitrary text storage for various inputs. */ char text_store[INFRARED_TEXT_STORE_NUM][INFRARED_TEXT_STORE_SIZE + 1]; InfraredAppState app_state; /**< Application state. */ diff --git a/applications/main/infrared/infrared_brute_force.c b/applications/main/infrared/infrared_brute_force.c index bb7992ae61..373c7270f5 100644 --- a/applications/main/infrared/infrared_brute_force.c +++ b/applications/main/infrared/infrared_brute_force.c @@ -128,7 +128,7 @@ void infrared_brute_force_stop(InfraredBruteForce* brute_force) { bool infrared_brute_force_send_next(InfraredBruteForce* brute_force) { furi_assert(brute_force->is_started); - const bool success = infrared_signal_search_and_read( + const bool success = infrared_signal_search_by_name_and_read( brute_force->current_signal, brute_force->ff, furi_string_get_cstr(brute_force->current_record_name)); diff --git a/applications/main/infrared/infrared_custom_event.h b/applications/main/infrared/infrared_custom_event.h index 09440ddec1..30bb0f729c 100644 --- a/applications/main/infrared/infrared_custom_event.h +++ b/applications/main/infrared/infrared_custom_event.h @@ -15,9 +15,10 @@ enum InfraredCustomEventType { InfraredCustomEventTypeButtonSelected, InfraredCustomEventTypeBackPressed, - InfraredCustomEventTypeRpcLoad, + InfraredCustomEventTypeRpcLoadFile, InfraredCustomEventTypeRpcExit, - InfraredCustomEventTypeRpcButtonPress, + InfraredCustomEventTypeRpcButtonPressName, + InfraredCustomEventTypeRpcButtonPressIndex, InfraredCustomEventTypeRpcButtonRelease, InfraredCustomEventTypeRpcSessionClose, }; diff --git a/applications/main/infrared/infrared_remote.c b/applications/main/infrared/infrared_remote.c index 5b241fe9f6..cab241c125 100644 --- a/applications/main/infrared/infrared_remote.c +++ b/applications/main/infrared/infrared_remote.c @@ -95,10 +95,9 @@ bool infrared_remote_load_signal( const char* path = furi_string_get_cstr(remote->path); if(!flipper_format_buffered_file_open_existing(ff, path)) break; - const char* name = infrared_remote_get_signal_name(remote, index); - - if(!infrared_signal_search_and_read(signal, ff, name)) { - FURI_LOG_E(TAG, "Failed to load signal '%s' from file '%s'", name, path); + if(!infrared_signal_search_by_index_and_read(signal, ff, index)) { + const char* signal_name = infrared_remote_get_signal_name(remote, index); + FURI_LOG_E(TAG, "Failed to load signal '%s' from file '%s'", signal_name, path); break; } diff --git a/applications/main/infrared/infrared_signal.c b/applications/main/infrared/infrared_signal.c index c73e4db98d..2b0d347911 100644 --- a/applications/main/infrared/infrared_signal.c +++ b/applications/main/infrared/infrared_signal.c @@ -266,19 +266,37 @@ bool infrared_signal_read_name(FlipperFormat* ff, FuriString* name) { return flipper_format_read_string(ff, INFRARED_SIGNAL_NAME_KEY, name); } -bool infrared_signal_search_and_read(InfraredSignal* signal, FlipperFormat* ff, const char* name) { +bool infrared_signal_search_by_name_and_read( + InfraredSignal* signal, + FlipperFormat* ff, + const char* name) { bool success = false; FuriString* tmp = furi_string_alloc(); - do { - bool is_name_found = false; - while(!is_name_found && infrared_signal_read_name(ff, tmp)) { //-V560 - is_name_found = furi_string_equal(tmp, name); + while(infrared_signal_read_name(ff, tmp)) { + if(furi_string_equal(tmp, name)) { + success = infrared_signal_read_body(signal, ff); + break; } - if(!is_name_found) break; //-V547 - if(!infrared_signal_read_body(signal, ff)) break; //-V779 - success = true; - } while(false); + } + + furi_string_free(tmp); + return success; +} + +bool infrared_signal_search_by_index_and_read( + InfraredSignal* signal, + FlipperFormat* ff, + size_t index) { + bool success = false; + FuriString* tmp = furi_string_alloc(); + + for(uint32_t i = 0; infrared_signal_read_name(ff, tmp); ++i) { + if(i == index) { + success = infrared_signal_read_body(signal, ff); + break; + } + } furi_string_free(tmp); return success; diff --git a/applications/main/infrared/infrared_signal.h b/applications/main/infrared/infrared_signal.h index fcbb3c8739..cfa4cfa94e 100644 --- a/applications/main/infrared/infrared_signal.h +++ b/applications/main/infrared/infrared_signal.h @@ -162,7 +162,26 @@ bool infrared_signal_read_name(FlipperFormat* ff, FuriString* name); * @param[in] name pointer to a zero-terminated string containing the requested signal name. * @returns true if a signal was found and successfully read, false otherwise (e.g. the signal was not found). */ -bool infrared_signal_search_and_read(InfraredSignal* signal, FlipperFormat* ff, const char* name); +bool infrared_signal_search_by_name_and_read( + InfraredSignal* signal, + FlipperFormat* ff, + const char* name); + +/** + * @brief Read a signal with a particular index from a FlipperFormat file into an InfraredSignal instance. + * + * This function will look for a signal with the given index and if found, attempt to read it. + * Same considerations apply as to infrared_signal_read(). + * + * @param[in,out] signal pointer to the instance to be read into. + * @param[in,out] ff pointer to the FlipperFormat file instance to read from. + * @param[in] index the requested signal index. + * @returns true if a signal was found and successfully read, false otherwise (e.g. the signal was not found). + */ +bool infrared_signal_search_by_index_and_read( + InfraredSignal* signal, + FlipperFormat* ff, + size_t index); /** * @brief Save a signal contained in an InfraredSignal instance to a FlipperFormat file. diff --git a/applications/main/infrared/scenes/infrared_scene_remote.c b/applications/main/infrared/scenes/infrared_scene_remote.c index 5974acbfec..6c1d1ec4e3 100644 --- a/applications/main/infrared/scenes/infrared_scene_remote.c +++ b/applications/main/infrared/scenes/infrared_scene_remote.c @@ -1,7 +1,7 @@ #include "../infrared_app_i.h" typedef enum { - ButtonIndexPlus = -2, + ButtonIndexLearn = -2, ButtonIndexEdit = -1, ButtonIndexNA = 0, } ButtonIndex; @@ -44,7 +44,7 @@ void infrared_scene_remote_on_enter(void* context) { button_menu_add_item( button_menu, "+", - ButtonIndexPlus, + ButtonIndexLearn, infrared_scene_remote_button_menu_callback, ButtonMenuItemTypeControl, context); @@ -95,7 +95,7 @@ bool infrared_scene_remote_on_event(void* context, SceneManagerEvent event) { if(is_transmitter_idle) { scene_manager_set_scene_state( scene_manager, InfraredSceneRemote, (unsigned)button_index); - if(button_index == ButtonIndexPlus) { + if(button_index == ButtonIndexLearn) { infrared->app_state.is_learning_new_remote = false; scene_manager_next_scene(scene_manager, InfraredSceneLearn); consumed = true; diff --git a/applications/main/infrared/scenes/infrared_scene_rpc.c b/applications/main/infrared/scenes/infrared_scene_rpc.c index fa5a599afa..f3408fba4d 100644 --- a/applications/main/infrared/scenes/infrared_scene_rpc.c +++ b/applications/main/infrared/scenes/infrared_scene_rpc.c @@ -1,6 +1,8 @@ #include "../infrared_app_i.h" #include +#define TAG "InfraredApp" + typedef enum { InfraredRpcStateIdle, InfraredRpcStateLoaded, @@ -38,11 +40,9 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { view_dispatcher_stop(infrared->view_dispatcher); } else if(event.event == InfraredCustomEventTypePopupClosed) { view_dispatcher_stop(infrared->view_dispatcher); - } else if(event.event == InfraredCustomEventTypeRpcLoad) { + } else if(event.event == InfraredCustomEventTypeRpcLoadFile) { bool result = false; - const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); - if(arg && (state == InfraredRpcStateIdle)) { - furi_string_set(infrared->file_path, arg); + if(state == InfraredRpcStateIdle) { result = infrared_remote_load( infrared->remote, furi_string_get_cstr(infrared->file_path)); if(result) { @@ -56,20 +56,35 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { popup_set_text( infrared->popup, infrared->text_store[0], 89, 44, AlignCenter, AlignTop); - rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventLoadFile, result); - } else if(event.event == InfraredCustomEventTypeRpcButtonPress) { + rpc_system_app_confirm(infrared->rpc_ctx, result); + } else if( + event.event == InfraredCustomEventTypeRpcButtonPressName || + event.event == InfraredCustomEventTypeRpcButtonPressIndex) { bool result = false; - const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); - if(arg && (state == InfraredRpcStateLoaded)) { - size_t button_index = 0; - if(infrared_remote_get_signal_index(infrared->remote, arg, &button_index)) { - infrared_tx_start_button_index(infrared, button_index); - result = true; + if(state == InfraredRpcStateLoaded) { + if(event.event == InfraredCustomEventTypeRpcButtonPressName) { + const char* button_name = furi_string_get_cstr(infrared->button_name); + size_t index; + const bool index_found = + infrared_remote_get_signal_index(infrared->remote, button_name, &index); + infrared->app_state.current_button_index = + index_found ? (signed)index : InfraredButtonIndexNone; + FURI_LOG_D(TAG, "Sending signal with name \"%s\"", button_name); + } else { + FURI_LOG_D( + TAG, + "Sending signal with index \"%ld\"", + infrared->app_state.current_button_index); + } + if(infrared->app_state.current_button_index != InfraredButtonIndexNone) { + infrared_tx_start_button_index( + infrared, infrared->app_state.current_button_index); scene_manager_set_scene_state( infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateSending); + result = true; } } - rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result); + rpc_system_app_confirm(infrared->rpc_ctx, result); } else if(event.event == InfraredCustomEventTypeRpcButtonRelease) { bool result = false; if(state == InfraredRpcStateSending) { @@ -78,11 +93,11 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state( infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateLoaded); } - rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result); + rpc_system_app_confirm(infrared->rpc_ctx, result); } else if(event.event == InfraredCustomEventTypeRpcExit) { scene_manager_stop(infrared->scene_manager); view_dispatcher_stop(infrared->view_dispatcher); - rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventAppExit, true); + rpc_system_app_confirm(infrared->rpc_ctx, true); } else if(event.event == InfraredCustomEventTypeRpcSessionClose) { scene_manager_stop(infrared->scene_manager); view_dispatcher_stop(infrared->view_dispatcher); diff --git a/applications/main/lfrfid/lfrfid.c b/applications/main/lfrfid/lfrfid.c index 2bef08df21..cd0613861f 100644 --- a/applications/main/lfrfid/lfrfid.c +++ b/applications/main/lfrfid/lfrfid.c @@ -13,21 +13,23 @@ static bool lfrfid_debug_back_event_callback(void* context) { return scene_manager_handle_back_event(app->scene_manager); } -static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { +static void rpc_command_callback(const RpcAppSystemEvent* event, void* context) { furi_assert(context); LfRfid* app = (LfRfid*)context; - if(rpc_event == RpcAppEventSessionClose) { + if(event->type == RpcAppEventTypeSessionClose) { view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcSessionClose); // Detach RPC rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); app->rpc_ctx = NULL; - } else if(rpc_event == RpcAppEventAppExit) { + } else if(event->type == RpcAppEventTypeAppExit) { view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventExit); - } else if(rpc_event == RpcAppEventLoadFile) { + } else if(event->type == RpcAppEventTypeLoadFile) { + furi_assert(event->data.type == RpcAppSystemEventDataTypeString); + furi_string_set(app->file_path, event->data.string); view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcLoadFile); } else { - rpc_system_app_confirm(app->rpc_ctx, rpc_event, false); + rpc_system_app_confirm(app->rpc_ctx, false); } } diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c b/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c index 156dd97afa..906218d74f 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_rpc.c @@ -24,17 +24,15 @@ bool lfrfid_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { consumed = true; if(event.event == LfRfidEventExit) { - rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); + rpc_system_app_confirm(app->rpc_ctx, true); scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); } else if(event.event == LfRfidEventRpcSessionClose) { scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); } else if(event.event == LfRfidEventRpcLoadFile) { - const char* arg = rpc_system_app_get_data(app->rpc_ctx); bool result = false; - if(arg && (app->rpc_state == LfRfidRpcStateIdle)) { - furi_string_set(app->file_path, arg); + if(app->rpc_state == LfRfidRpcStateIdle) { if(lfrfid_load_key_data(app, app->file_path, false)) { lfrfid_worker_start_thread(app->lfworker); lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id); @@ -48,7 +46,7 @@ bool lfrfid_scene_rpc_on_event(void* context, SceneManagerEvent event) { result = true; } } - rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result); + rpc_system_app_confirm(app->rpc_ctx, result); } } return consumed; diff --git a/applications/main/nfc/helpers/nfc_custom_event.h b/applications/main/nfc/helpers/nfc_custom_event.h index 2a3b13e1a4..16fbc47492 100644 --- a/applications/main/nfc/helpers/nfc_custom_event.h +++ b/applications/main/nfc/helpers/nfc_custom_event.h @@ -21,7 +21,7 @@ typedef enum { NfcCustomEventTextInputDone, NfcCustomEventDictAttackDone, - NfcCustomEventRpcLoad, + NfcCustomEventRpcLoadFile, NfcCustomEventRpcExit, NfcCustomEventRpcSessionClose, diff --git a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c index bf6c0842fe..87fbe9f082 100644 --- a/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c +++ b/applications/main/nfc/helpers/protocol_support/nfc_protocol_support.c @@ -694,15 +694,17 @@ static bool nfc_protocol_support_scene_rpc_on_event(NfcApp* instance, SceneManag bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == NfcCustomEventRpcLoad && instance->rpc_state == NfcRpcStateIdle) { - furi_string_set(instance->file_path, rpc_system_app_get_data(instance->rpc_ctx)); - const bool load_success = nfc_load_file(instance, instance->file_path, false); - if(load_success) { - nfc_protocol_support_scene_rpc_setup_ui_and_emulate(instance); + if(event.event == NfcCustomEventRpcLoadFile) { + bool success = false; + if(instance->rpc_state == NfcRpcStateIdle) { + if(nfc_load_file(instance, instance->file_path, false)) { + nfc_protocol_support_scene_rpc_setup_ui_and_emulate(instance); + success = true; + } } - rpc_system_app_confirm(instance->rpc_ctx, RpcAppEventLoadFile, load_success); + rpc_system_app_confirm(instance->rpc_ctx, success); } else if(event.event == NfcCustomEventRpcExit) { - rpc_system_app_confirm(instance->rpc_ctx, RpcAppEventAppExit, true); + rpc_system_app_confirm(instance->rpc_ctx, true); scene_manager_stop(instance->scene_manager); view_dispatcher_stop(instance->view_dispatcher); } else if(event.event == NfcCustomEventRpcSessionClose) { diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 9e0de8891b..141a67e5cb 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -14,22 +14,24 @@ bool nfc_back_event_callback(void* context) { return scene_manager_handle_back_event(nfc->scene_manager); } -static void nfc_app_rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { +static void nfc_app_rpc_command_callback(const RpcAppSystemEvent* event, void* context) { furi_assert(context); NfcApp* nfc = (NfcApp*)context; furi_assert(nfc->rpc_ctx); - if(rpc_event == RpcAppEventSessionClose) { + if(event->type == RpcAppEventTypeSessionClose) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose); rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); nfc->rpc_ctx = NULL; - } else if(rpc_event == RpcAppEventAppExit) { + } else if(event->type == RpcAppEventTypeAppExit) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcExit); - } else if(rpc_event == RpcAppEventLoadFile) { - view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad); + } else if(event->type == RpcAppEventTypeLoadFile) { + furi_assert(event->data.type == RpcAppSystemEventDataTypeString); + furi_string_set(nfc->file_path, event->data.string); + view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoadFile); } else { - rpc_system_app_confirm(nfc->rpc_ctx, rpc_event, false); + rpc_system_app_confirm(nfc->rpc_ctx, false); } } diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index d4bf3e808e..f8bf066d54 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -33,13 +33,13 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(event.event == SubGhzCustomEventSceneExit) { scene_manager_stop(subghz->scene_manager); view_dispatcher_stop(subghz->view_dispatcher); - rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventAppExit, true); + rpc_system_app_confirm(subghz->rpc_ctx, true); } else if(event.event == SubGhzCustomEventSceneRpcSessionClose) { scene_manager_stop(subghz->scene_manager); view_dispatcher_stop(subghz->view_dispatcher); } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { bool result = false; - if((state == SubGhzRpcStateLoaded)) { + if(state == SubGhzRpcStateLoaded) { switch( subghz_txrx_tx_start(subghz->txrx, subghz_txrx_get_fff_data(subghz->txrx))) { case SubGhzTxRxStartTxStateErrorOnlyRx: @@ -61,7 +61,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { break; } } - rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result); + rpc_system_app_confirm(subghz->rpc_ctx, result); } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { bool result = false; if(state == SubGhzRpcStateTx) { @@ -70,15 +70,13 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { result = true; } state = SubGhzRpcStateIdle; - rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result); + rpc_system_app_confirm(subghz->rpc_ctx, result); } else if(event.event == SubGhzCustomEventSceneRpcLoad) { bool result = false; - const char* arg = rpc_system_app_get_data(subghz->rpc_ctx); - if(arg && (state == SubGhzRpcStateIdle)) { - if(subghz_key_load(subghz, arg, false)) { + if(state == SubGhzRpcStateIdle) { + if(subghz_key_load(subghz, furi_string_get_cstr(subghz->file_path), false)) { scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneRpc, SubGhzRpcStateLoaded); - furi_string_set(subghz->file_path, arg); result = true; FuriString* file_name; file_name = furi_string_alloc(); @@ -97,7 +95,7 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { rpc_system_app_set_error_text(subghz->rpc_ctx, "Cannot parse file"); } } - rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventLoadFile, result); + rpc_system_app_confirm(subghz->rpc_ctx, result); } } return consumed; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index e8148798ef..69a72e95d6 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -20,29 +20,31 @@ void subghz_tick_event_callback(void* context) { scene_manager_handle_tick_event(subghz->scene_manager); } -static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context) { +static void subghz_rpc_command_callback(const RpcAppSystemEvent* event, void* context) { furi_assert(context); SubGhz* subghz = context; furi_assert(subghz->rpc_ctx); - if(event == RpcAppEventSessionClose) { + if(event->type == RpcAppEventTypeSessionClose) { view_dispatcher_send_custom_event( subghz->view_dispatcher, SubGhzCustomEventSceneRpcSessionClose); rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL); subghz->rpc_ctx = NULL; - } else if(event == RpcAppEventAppExit) { + } else if(event->type == RpcAppEventTypeAppExit) { view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); - } else if(event == RpcAppEventLoadFile) { + } else if(event->type == RpcAppEventTypeLoadFile) { + furi_assert(event->data.type == RpcAppSystemEventDataTypeString); + furi_string_set(subghz->file_path, event->data.string); view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneRpcLoad); - } else if(event == RpcAppEventButtonPress) { + } else if(event->type == RpcAppEventTypeButtonPress) { view_dispatcher_send_custom_event( subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonPress); - } else if(event == RpcAppEventButtonRelease) { + } else if(event->type == RpcAppEventTypeButtonRelease) { view_dispatcher_send_custom_event( subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonRelease); } else { - rpc_system_app_confirm(subghz->rpc_ctx, event, false); + rpc_system_app_confirm(subghz->rpc_ctx, false); } } diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 826f222537..5880e7d9f9 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -477,12 +477,15 @@ void rpc_send_and_release(RpcSession* session, PB_Main* message) { } void rpc_send_and_release_empty(RpcSession* session, uint32_t command_id, PB_CommandStatus status) { + furi_assert(session); + PB_Main message = { .command_id = command_id, .command_status = status, .has_next = false, .which_content = PB_Main_empty_tag, }; + rpc_send_and_release(session, &message); pb_release(&PB_Main_msg, &message); } diff --git a/applications/services/rpc/rpc_app.c b/applications/services/rpc/rpc_app.c index e86eaa493d..9af652dae1 100644 --- a/applications/services/rpc/rpc_app.c +++ b/applications/services/rpc/rpc_app.c @@ -10,49 +10,85 @@ struct RpcAppSystem { RpcSession* session; - RpcAppSystemCallback app_callback; - void* app_context; + RpcAppSystemCallback callback; + void* callback_context; - RpcAppSystemDataExchangeCallback data_exchange_callback; - void* data_exchange_context; + uint32_t error_code; + char* error_text; - PB_Main* state_msg; - PB_Main* error_msg; - - uint32_t last_id; - char* last_data; + uint32_t last_command_id; + RpcAppSystemEventType last_event_type; }; #define RPC_SYSTEM_APP_TEMP_ARGS_SIZE 16 +static void rpc_system_app_send_state_response( + RpcAppSystem* rpc_app, + PB_App_AppState state, + const char* name) { + PB_Main* response = malloc(sizeof(PB_Main)); + + response->which_content = PB_Main_app_state_response_tag; + response->content.app_state_response.state = state; + + FURI_LOG_D(TAG, "%s", name); + rpc_send(rpc_app->session, response); + + free(response); +} + +static void rpc_system_app_send_error_response( + RpcAppSystem* rpc_app, + uint32_t command_id, + PB_CommandStatus status, + const char* name) { + // Not describing all possible errors as only APP_NOT_RUNNING is used + const char* status_str = status == PB_CommandStatus_ERROR_APP_NOT_RUNNING ? "APP_NOT_RUNNING" : + "UNKNOWN"; + FURI_LOG_E(TAG, "%s: %s, id %lu, status: %d", name, status_str, command_id, status); + rpc_send_and_release_empty(rpc_app->session, command_id, status); +} + +static void rpc_system_app_set_last_command( + RpcAppSystem* rpc_app, + uint32_t command_id, + const RpcAppSystemEvent* event) { + furi_assert(rpc_app->last_command_id == 0); + furi_assert(rpc_app->last_event_type == RpcAppEventTypeInvalid); + + rpc_app->last_command_id = command_id; + rpc_app->last_event_type = event->type; +} + static void rpc_system_app_start_process(const PB_Main* request, void* context) { furi_assert(request); - furi_assert(context); - furi_assert(request->which_content == PB_Main_app_start_request_tag); - RpcAppSystem* rpc_app = context; - RpcSession* session = rpc_app->session; - rpc_system_app_error_reset(rpc_app); - furi_assert(session); - char args_temp[RPC_SYSTEM_APP_TEMP_ARGS_SIZE]; - furi_assert(!rpc_app->last_id); - furi_assert(!rpc_app->last_data); + RpcAppSystem* rpc_app = context; + furi_assert(rpc_app); + furi_assert(rpc_app->last_command_id == 0); + furi_assert(rpc_app->last_event_type == RpcAppEventTypeInvalid); FURI_LOG_D(TAG, "StartProcess: id %lu", request->command_id); - PB_CommandStatus result; - Loader* loader = furi_record_open(RECORD_LOADER); const char* app_name = request->content.app_start_request.name; + + PB_CommandStatus result; + if(app_name) { + rpc_system_app_error_reset(rpc_app); + + char app_args_temp[RPC_SYSTEM_APP_TEMP_ARGS_SIZE]; const char* app_args = request->content.app_start_request.args; + if(app_args && strcmp(app_args, "RPC") == 0) { // If app is being started in RPC mode - pass RPC context via args string - snprintf(args_temp, RPC_SYSTEM_APP_TEMP_ARGS_SIZE, "RPC %08lX", (uint32_t)rpc_app); - app_args = args_temp; + snprintf(app_args_temp, RPC_SYSTEM_APP_TEMP_ARGS_SIZE, "RPC %08lX", (uint32_t)rpc_app); + app_args = app_args_temp; } - LoaderStatus status = loader_start(loader, app_name, app_args, NULL); + + const LoaderStatus status = loader_start(loader, app_name, app_args, NULL); if(status == LoaderStatusErrorAppStarted) { result = PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED; } else if(status == LoaderStatusErrorInternal) { @@ -71,266 +107,271 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context) furi_record_close(RECORD_LOADER); FURI_LOG_D(TAG, "StartProcess: response id %lu, result %d", request->command_id, result); - rpc_send_and_release_empty(session, request->command_id, result); + rpc_send_and_release_empty(rpc_app->session, request->command_id, result); } static void rpc_system_app_lock_status_process(const PB_Main* request, void* context) { furi_assert(request); - furi_assert(context); - furi_assert(request->which_content == PB_Main_app_lock_status_request_tag); + RpcAppSystem* rpc_app = context; + furi_assert(rpc_app); + rpc_system_app_error_reset(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); FURI_LOG_D(TAG, "LockStatus"); + PB_Main* response = malloc(sizeof(PB_Main)); + + response->command_id = request->command_id; + response->which_content = PB_Main_app_lock_status_response_tag; + Loader* loader = furi_record_open(RECORD_LOADER); - - PB_Main response = { - .has_next = false, - .command_status = PB_CommandStatus_OK, - .command_id = request->command_id, - .which_content = PB_Main_app_lock_status_response_tag, - }; - - response.content.app_lock_status_response.locked = loader_is_locked(loader); - + response->content.app_lock_status_response.locked = loader_is_locked(loader); furi_record_close(RECORD_LOADER); FURI_LOG_D(TAG, "LockStatus: response"); - rpc_send_and_release(session, &response); - pb_release(&PB_Main_msg, &response); + rpc_send_and_release(rpc_app->session, response); + + free(response); } static void rpc_system_app_exit_request(const PB_Main* request, void* context) { furi_assert(request); - furi_assert(context); - furi_assert(request->which_content == PB_Main_app_exit_request_tag); + RpcAppSystem* rpc_app = context; - rpc_system_app_error_reset(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); + furi_assert(rpc_app); - PB_CommandStatus status; - - if(rpc_app->app_callback) { + if(rpc_app->callback) { FURI_LOG_D(TAG, "ExitRequest: id %lu", request->command_id); - furi_assert(!rpc_app->last_id); - furi_assert(!rpc_app->last_data); - rpc_app->last_id = request->command_id; - rpc_app->app_callback(RpcAppEventAppExit, rpc_app->app_context); + + const RpcAppSystemEvent event = { + .type = RpcAppEventTypeAppExit, + .data = + { + .type = RpcAppSystemEventDataTypeNone, + {0}, + }, + }; + + rpc_system_app_error_reset(rpc_app); + rpc_system_app_set_last_command(rpc_app, request->command_id, &event); + + rpc_app->callback(&event, rpc_app->callback_context); + } else { - status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; - FURI_LOG_E( - TAG, "ExitRequest: APP_NOT_RUNNING, id %lu, status: %d", request->command_id, status); - rpc_send_and_release_empty(session, request->command_id, status); + rpc_system_app_send_error_response( + rpc_app, request->command_id, PB_CommandStatus_ERROR_APP_NOT_RUNNING, "ExitRequest"); } } static void rpc_system_app_load_file(const PB_Main* request, void* context) { furi_assert(request); - furi_assert(context); - furi_assert(request->which_content == PB_Main_app_load_file_request_tag); - RpcAppSystem* rpc_app = context; - rpc_system_app_error_reset(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); - PB_CommandStatus status; - if(rpc_app->app_callback) { + RpcAppSystem* rpc_app = context; + furi_assert(rpc_app); + + if(rpc_app->callback) { FURI_LOG_D(TAG, "LoadFile: id %lu", request->command_id); - furi_assert(!rpc_app->last_id); - furi_assert(!rpc_app->last_data); - rpc_app->last_id = request->command_id; - rpc_app->last_data = strdup(request->content.app_load_file_request.path); - rpc_app->app_callback(RpcAppEventLoadFile, rpc_app->app_context); + + const RpcAppSystemEvent event = { + .type = RpcAppEventTypeLoadFile, + .data = + { + .type = RpcAppSystemEventDataTypeString, + .string = request->content.app_load_file_request.path, + }, + }; + + rpc_system_app_error_reset(rpc_app); + rpc_system_app_set_last_command(rpc_app, request->command_id, &event); + + rpc_app->callback(&event, rpc_app->callback_context); + } else { - status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; - FURI_LOG_E( - TAG, "LoadFile: APP_NOT_RUNNING, id %lu, status: %d", request->command_id, status); - rpc_send_and_release_empty(session, request->command_id, status); + rpc_system_app_send_error_response( + rpc_app, request->command_id, PB_CommandStatus_ERROR_APP_NOT_RUNNING, "LoadFile"); } } static void rpc_system_app_button_press(const PB_Main* request, void* context) { furi_assert(request); - furi_assert(context); - furi_assert(request->which_content == PB_Main_app_button_press_request_tag); - RpcAppSystem* rpc_app = context; - rpc_system_app_error_reset(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); - PB_CommandStatus status; - if(rpc_app->app_callback) { + RpcAppSystem* rpc_app = context; + furi_assert(rpc_app); + + if(rpc_app->callback) { FURI_LOG_D(TAG, "ButtonPress"); - furi_assert(!rpc_app->last_id); - furi_assert(!rpc_app->last_data); - rpc_app->last_id = request->command_id; - rpc_app->last_data = strdup(request->content.app_button_press_request.args); - rpc_app->app_callback(RpcAppEventButtonPress, rpc_app->app_context); + + RpcAppSystemEvent event; + event.type = RpcAppEventTypeButtonPress; + + if(strlen(request->content.app_button_press_request.args) != 0) { + event.data.type = RpcAppSystemEventDataTypeString; + event.data.string = request->content.app_button_press_request.args; + } else { + event.data.type = RpcAppSystemEventDataTypeInt32; + event.data.i32 = request->content.app_button_press_request.index; + } + + rpc_system_app_error_reset(rpc_app); + rpc_system_app_set_last_command(rpc_app, request->command_id, &event); + + rpc_app->callback(&event, rpc_app->callback_context); + } else { - status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; - FURI_LOG_E( - TAG, "ButtonPress: APP_NOT_RUNNING, id %lu, status: %d", request->command_id, status); - rpc_send_and_release_empty(session, request->command_id, status); + rpc_system_app_send_error_response( + rpc_app, request->command_id, PB_CommandStatus_ERROR_APP_NOT_RUNNING, "ButtonPress"); } } static void rpc_system_app_button_release(const PB_Main* request, void* context) { furi_assert(request); furi_assert(request->which_content == PB_Main_app_button_release_request_tag); - furi_assert(context); RpcAppSystem* rpc_app = context; - rpc_system_app_error_reset(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); + furi_assert(rpc_app); - PB_CommandStatus status; - if(rpc_app->app_callback) { + if(rpc_app->callback) { FURI_LOG_D(TAG, "ButtonRelease"); - furi_assert(!rpc_app->last_id); - furi_assert(!rpc_app->last_data); - rpc_app->last_id = request->command_id; - rpc_app->app_callback(RpcAppEventButtonRelease, rpc_app->app_context); + + const RpcAppSystemEvent event = { + .type = RpcAppEventTypeButtonRelease, + .data = + { + .type = RpcAppSystemEventDataTypeNone, + {0}, + }, + }; + + rpc_system_app_error_reset(rpc_app); + rpc_system_app_set_last_command(rpc_app, request->command_id, &event); + + rpc_app->callback(&event, rpc_app->callback_context); + } else { - status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; - FURI_LOG_E( - TAG, "ButtonRelease: APP_NOT_RUNNING, id %lu, status: %d", request->command_id, status); - rpc_send_and_release_empty(session, request->command_id, status); + rpc_system_app_send_error_response( + rpc_app, request->command_id, PB_CommandStatus_ERROR_APP_NOT_RUNNING, "ButtonRelease"); } } static void rpc_system_app_get_error_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(request->which_content == PB_Main_app_get_error_request_tag); - furi_assert(context); RpcAppSystem* rpc_app = context; - RpcSession* session = rpc_app->session; - furi_assert(session); + furi_assert(rpc_app); - rpc_app->error_msg->command_id = request->command_id; + PB_Main* response = malloc(sizeof(PB_Main)); + + response->command_id = request->command_id; + response->which_content = PB_Main_app_get_error_response_tag; + response->content.app_get_error_response.code = rpc_app->error_code; + response->content.app_get_error_response.text = rpc_app->error_text; FURI_LOG_D(TAG, "GetError"); - rpc_send(session, rpc_app->error_msg); + rpc_send(rpc_app->session, response); + + free(response); } static void rpc_system_app_data_exchange_process(const PB_Main* request, void* context) { furi_assert(request); furi_assert(request->which_content == PB_Main_app_data_exchange_request_tag); - furi_assert(context); RpcAppSystem* rpc_app = context; - rpc_system_app_error_reset(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); + furi_assert(rpc_app); - PB_CommandStatus command_status; - pb_bytes_array_t* data = request->content.app_data_exchange_request.data; + if(rpc_app->callback) { + FURI_LOG_D(TAG, "DataExchange"); - if(rpc_app->data_exchange_callback) { - uint8_t* data_bytes = NULL; - size_t data_size = 0; - if(data) { - data_bytes = data->bytes; - data_size = data->size; - } - rpc_app->data_exchange_callback(data_bytes, data_size, rpc_app->data_exchange_context); - command_status = PB_CommandStatus_OK; + const pb_bytes_array_t* data = request->content.app_data_exchange_request.data; + + const RpcAppSystemEvent event = { + .type = RpcAppEventTypeDataExchange, + .data = + { + .type = RpcAppSystemEventDataTypeBytes, + .bytes = + { + .ptr = data ? data->bytes : NULL, + .size = data ? data->size : 0, + }, + }, + }; + + rpc_system_app_error_reset(rpc_app); + rpc_system_app_set_last_command(rpc_app, request->command_id, &event); + + rpc_app->callback(&event, rpc_app->callback_context); } else { - command_status = PB_CommandStatus_ERROR_APP_CMD_ERROR; + rpc_system_app_send_error_response( + rpc_app, request->command_id, PB_CommandStatus_ERROR_APP_NOT_RUNNING, "DataExchange"); } - - FURI_LOG_D(TAG, "DataExchange"); - rpc_send_and_release_empty(session, request->command_id, command_status); } void rpc_system_app_send_started(RpcAppSystem* rpc_app) { furi_assert(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); - - rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_STARTED; - - FURI_LOG_D(TAG, "SendStarted"); - rpc_send(session, rpc_app->state_msg); + rpc_system_app_send_state_response(rpc_app, PB_App_AppState_APP_STARTED, "SendStarted"); } void rpc_system_app_send_exited(RpcAppSystem* rpc_app) { furi_assert(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); - - rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_CLOSED; - - FURI_LOG_D(TAG, "SendExit"); - rpc_send(session, rpc_app->state_msg); + rpc_system_app_send_state_response(rpc_app, PB_App_AppState_APP_CLOSED, "SendExit"); } -const char* rpc_system_app_get_data(RpcAppSystem* rpc_app) { +void rpc_system_app_confirm(RpcAppSystem* rpc_app, bool result) { furi_assert(rpc_app); - furi_assert(rpc_app->last_data); - return rpc_app->last_data; -} + furi_assert(rpc_app->last_command_id != 0); + /* Ensure that only commands of these types can be confirmed */ + furi_assert( + rpc_app->last_event_type == RpcAppEventTypeAppExit || + rpc_app->last_event_type == RpcAppEventTypeLoadFile || + rpc_app->last_event_type == RpcAppEventTypeButtonPress || + rpc_app->last_event_type == RpcAppEventTypeButtonRelease || + rpc_app->last_event_type == RpcAppEventTypeDataExchange); -void rpc_system_app_confirm(RpcAppSystem* rpc_app, RpcAppSystemEvent event, bool result) { - furi_assert(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); - furi_assert(rpc_app->last_id); + const uint32_t last_command_id = rpc_app->last_command_id; + const RpcAppSystemEventType last_event_type = rpc_app->last_event_type; - PB_CommandStatus status = result ? PB_CommandStatus_OK : PB_CommandStatus_ERROR_APP_CMD_ERROR; + rpc_app->last_command_id = 0; + rpc_app->last_event_type = RpcAppEventTypeInvalid; - uint32_t last_id = 0; - switch(event) { - case RpcAppEventAppExit: - case RpcAppEventLoadFile: - case RpcAppEventButtonPress: - case RpcAppEventButtonRelease: - last_id = rpc_app->last_id; - rpc_app->last_id = 0; - if(rpc_app->last_data) { - free(rpc_app->last_data); - rpc_app->last_data = NULL; - } - FURI_LOG_D(TAG, "AppConfirm: event %d last_id %lu status %d", event, last_id, status); - rpc_send_and_release_empty(session, last_id, status); - break; - default: - furi_crash("RPC App state programming Error"); - break; - } + const PB_CommandStatus status = result ? PB_CommandStatus_OK : + PB_CommandStatus_ERROR_APP_CMD_ERROR; + FURI_LOG_D( + TAG, + "AppConfirm: event %d last_id %lu status %d", + last_event_type, + last_command_id, + status); + + rpc_send_and_release_empty(rpc_app->session, last_command_id, status); } void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx) { furi_assert(rpc_app); - rpc_app->app_callback = callback; - rpc_app->app_context = ctx; + rpc_app->callback = callback; + rpc_app->callback_context = ctx; } void rpc_system_app_set_error_code(RpcAppSystem* rpc_app, uint32_t error_code) { furi_assert(rpc_app); - PB_App_GetErrorResponse* content = &rpc_app->error_msg->content.app_get_error_response; - content->code = error_code; + rpc_app->error_code = error_code; } void rpc_system_app_set_error_text(RpcAppSystem* rpc_app, const char* error_text) { furi_assert(rpc_app); - PB_App_GetErrorResponse* content = &rpc_app->error_msg->content.app_get_error_response; - if(content->text) { - free(content->text); + if(rpc_app->error_text) { + free(rpc_app->error_text); } - content->text = error_text ? strdup(error_text) : NULL; + rpc_app->error_text = error_text ? strdup(error_text) : NULL; } void rpc_system_app_error_reset(RpcAppSystem* rpc_app) { @@ -340,29 +381,13 @@ void rpc_system_app_error_reset(RpcAppSystem* rpc_app) { rpc_system_app_set_error_text(rpc_app, NULL); } -void rpc_system_app_set_data_exchange_callback( - RpcAppSystem* rpc_app, - RpcAppSystemDataExchangeCallback callback, - void* ctx) { - furi_assert(rpc_app); - - rpc_app->data_exchange_callback = callback; - rpc_app->data_exchange_context = ctx; -} - void rpc_system_app_exchange_data(RpcAppSystem* rpc_app, const uint8_t* data, size_t data_size) { furi_assert(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); - PB_Main message = { - .command_id = 0, - .command_status = PB_CommandStatus_OK, - .has_next = false, - .which_content = PB_Main_app_data_exchange_request_tag, - }; + PB_Main* request = malloc(sizeof(PB_Main)); - PB_App_DataExchangeRequest* content = &message.content.app_data_exchange_request; + request->which_content = PB_Main_app_data_exchange_request_tag; + PB_App_DataExchangeRequest* content = &request->content.app_data_exchange_request; if(data && data_size) { content->data = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data_size)); @@ -372,7 +397,9 @@ void rpc_system_app_exchange_data(RpcAppSystem* rpc_app, const uint8_t* data, si content->data = NULL; } - rpc_send_and_release(session, &message); + rpc_send_and_release(rpc_app->session, request); + + free(request); } void* rpc_system_app_alloc(RpcSession* session) { @@ -381,18 +408,6 @@ void* rpc_system_app_alloc(RpcSession* session) { RpcAppSystem* rpc_app = malloc(sizeof(RpcAppSystem)); rpc_app->session = session; - // App exit message - rpc_app->state_msg = malloc(sizeof(PB_Main)); - rpc_app->state_msg->which_content = PB_Main_app_state_response_tag; - rpc_app->state_msg->command_status = PB_CommandStatus_OK; - - // App error message - rpc_app->error_msg = malloc(sizeof(PB_Main)); - rpc_app->error_msg->which_content = PB_Main_app_get_error_response_tag; - rpc_app->error_msg->command_status = PB_CommandStatus_OK; - rpc_app->error_msg->content.app_get_error_response.code = 0; - rpc_app->error_msg->content.app_get_error_response.text = NULL; - RpcHandler rpc_handler = { .message_handler = NULL, .decode_submessage = NULL, @@ -429,24 +444,24 @@ void* rpc_system_app_alloc(RpcSession* session) { void rpc_system_app_free(void* context) { RpcAppSystem* rpc_app = context; furi_assert(rpc_app); - RpcSession* session = rpc_app->session; - furi_assert(session); + furi_assert(rpc_app->session); - if(rpc_app->app_callback) { - rpc_app->app_callback(RpcAppEventSessionClose, rpc_app->app_context); + if(rpc_app->callback) { + const RpcAppSystemEvent event = { + .type = RpcAppEventTypeSessionClose, + .data = + { + .type = RpcAppSystemEventDataTypeNone, + {0}, + }, + }; + + rpc_app->callback(&event, rpc_app->callback_context); } - while(rpc_app->app_callback) { + while(rpc_app->callback) { furi_delay_tick(1); } - furi_assert(!rpc_app->data_exchange_callback); - - if(rpc_app->last_data) free(rpc_app->last_data); - - pb_release(&PB_Main_msg, rpc_app->error_msg); - - free(rpc_app->error_msg); - free(rpc_app->state_msg); free(rpc_app); } diff --git a/applications/services/rpc/rpc_app.h b/applications/services/rpc/rpc_app.h index d5c6fee962..4ee5a24d37 100644 --- a/applications/services/rpc/rpc_app.h +++ b/applications/services/rpc/rpc_app.h @@ -1,45 +1,213 @@ +/** + * @file rpc_app.h + * @brief Application RPC subsystem interface. + * + * The application RPC subsystem provides facilities for interacting with applications, + * such as starting/stopping, passing parameters, sending commands and exchanging arbitrary data. + * + * All commands are handled asynchronously via a user-settable callback. + * + * For a complete description of message types handled in this subsystem, + * see https://github.com/flipperdevices/flipperzero-protobuf/blob/dev/application.proto + */ #pragma once + #include "rpc.h" #ifdef __cplusplus extern "C" { #endif +/** + * @brief Enumeration of possible event data types. + */ typedef enum { - RpcAppEventSessionClose, - RpcAppEventAppExit, - RpcAppEventLoadFile, - RpcAppEventButtonPress, - RpcAppEventButtonRelease, + RpcAppSystemEventDataTypeNone, /**< No data is provided by the event. */ + RpcAppSystemEventDataTypeString, /**< Event data contains a zero-terminated string. */ + RpcAppSystemEventDataTypeInt32, /**< Event data contains a signed 32-bit integer. */ + RpcAppSystemEventDataTypeBytes, /**< Event data contains zero or more bytes. */ +} RpcAppSystemEventDataType; + +/** + * @brief Event data structure, containing the type and associated data. + * + * All below fields except for type are valid only if the respective type is set. + */ +typedef struct { + RpcAppSystemEventDataType + type; /**< Type of the data. The meaning of other fields depends on this one. */ + union { + const char* string; /**< Pointer to a zero-terminated character string. */ + int32_t i32; /**< Signed 32-bit integer value. */ + struct { + const uint8_t* ptr; /**< Pointer to the byte array data. */ + size_t size; /**< Size of the byte array, in bytes. */ + } bytes; /**< Byte array of arbitrary length. */ + }; +} RpcAppSystemEventData; + +/** + * @brief Enumeration of possible event types. + */ +typedef enum { + /** + * @brief Denotes an invalid state. + * + * An event of this type shall never be passed into the callback. + */ + RpcAppEventTypeInvalid, + /** + * @brief The client side has closed the session. + * + * After receiving this event, the RPC context is no more valid. + */ + RpcAppEventTypeSessionClose, + /** + * @brief The client has requested the application to exit. + * + * The application must exit after receiving this command. + */ + RpcAppEventTypeAppExit, + /** + * @brief The client has requested the application to load a file. + * + * This command's meaning is application-specific, i.e. the application might or + * might not require additional commands after loading a file to do anything useful. + */ + RpcAppEventTypeLoadFile, + /** + * @brief The client has informed the application that a button has been pressed. + * + * This command's meaning is application-specific, e.g. to select a part of the + * previously loaded file or to invoke a particular function within the application. + */ + RpcAppEventTypeButtonPress, + /** + * @brief The client has informed the application that a button has been released. + * + * This command's meaning is application-specific, e.g. to cease + * all activities to be conducted while a button is being pressed. + */ + RpcAppEventTypeButtonRelease, + /** + * @brief The client has sent a byte array of arbitrary size. + * + * This command's purpose is bi-directional exchange of arbitrary raw data. + * Useful for implementing higher-level protocols while using the RPC as a transport layer. + */ + RpcAppEventTypeDataExchange, +} RpcAppSystemEventType; + +/** + * @brief RPC application subsystem event structure. + */ +typedef struct { + RpcAppSystemEventType type; /**< Type of the event. */ + RpcAppSystemEventData data; /**< Data associated with the event. */ } RpcAppSystemEvent; -typedef void (*RpcAppSystemCallback)(RpcAppSystemEvent event, void* context); -typedef void ( - *RpcAppSystemDataExchangeCallback)(const uint8_t* data, size_t data_size, void* context); +/** + * @brief Callback function type. + * + * A function of this type must be passed to rpc_system_app_set_callback() by the user code. + * + * @warning The event pointer is valid ONLY inside the callback function. + * + * @param[in] event pointer to the event object. Valid only inside the callback function. + * @param[in,out] context pointer to the user-defined context object. + */ +typedef void (*RpcAppSystemCallback)(const RpcAppSystemEvent* event, void* context); +/** + * @brief RPC application subsystem opaque type declaration. + */ typedef struct RpcAppSystem RpcAppSystem; -void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx); +/** + * @brief Set the callback function for use by an RpcAppSystem instance. + * + * @param[in,out] rpc_app pointer to the instance to be configured. + * @param[in] callback pointer to the function to be called upon message reception. + * @param[in,out] context pointer to the user-defined context object. Will be passed to the callback. + */ +void rpc_system_app_set_callback( + RpcAppSystem* rpc_app, + RpcAppSystemCallback callback, + void* context); +/** + * @brief Send a notification that an RpcAppSystem instance has been started and is ready. + * + * Call this function once right after acquiring an RPC context and setting the callback. + * + * @param[in,out] rpc_app pointer to the instance to be used. + */ void rpc_system_app_send_started(RpcAppSystem* rpc_app); +/** + * @brief Send a notification that the application using an RpcAppSystem instance is about to exit. + * + * Call this function when the application is about to exit (usually in the *_free() function). + * + * @param[in,out] rpc_app pointer to the instance to be used. + */ void rpc_system_app_send_exited(RpcAppSystem* rpc_app); -const char* rpc_system_app_get_data(RpcAppSystem* rpc_app); - -void rpc_system_app_confirm(RpcAppSystem* rpc_app, RpcAppSystemEvent event, bool result); +/** + * @brief Send a confirmation that the application using an RpcAppSystem instance has handled the event. + * + * An explicit confirmation is required for the following event types: + * - RpcAppEventTypeAppExit + * - RpcAppEventTypeLoadFile + * - RpcAppEventTypeButtonPress + * - RpcAppEventTypeButtonRelease + * - RpcAppEventTypeDataExchange + * + * Not confirming these events will result in a client-side timeout. + * + * @param[in,out] rpc_app pointer to the instance to be used. + * @param[in] result whether the command was successfully handled or not (true for success). + */ +void rpc_system_app_confirm(RpcAppSystem* rpc_app, bool result); +/** + * @brief Set the error code stored in an RpcAppSystem instance. + * + * The error code can be retrieved by the client at any time by using the GetError request. + * The error code value has no meaning within the subsystem, i.e. it is only passed through to the client. + * + * @param[in,out] rpc_app pointer to the instance to be modified. + * @param[in] error_code arbitrary error code to be set. + */ void rpc_system_app_set_error_code(RpcAppSystem* rpc_app, uint32_t error_code); +/** + * @brief Set the error text stored in an RpcAppSystem instance. + * + * The error text can be retrieved by the client at any time by using the GetError request. + * The text has no meaning within the subsystem, i.e. it is only passed through to the client. + * + * @param[in,out] rpc_app pointer to the instance to be modified. + * @param[in] error_text Pointer to a zero-terminated string containing the error text. + */ void rpc_system_app_set_error_text(RpcAppSystem* rpc_app, const char* error_text); +/** + * @brief Reset the error code and text stored in an RpcAppSystem instance. + * + * Resets the error code to 0 and error text to "" (empty string). + * + * @param[in,out] rpc_app pointer to the instance to be reset. + */ void rpc_system_app_error_reset(RpcAppSystem* rpc_app); -void rpc_system_app_set_data_exchange_callback( - RpcAppSystem* rpc_app, - RpcAppSystemDataExchangeCallback callback, - void* ctx); - +/** + * @brief Send a byte array of arbitrary data to the client using an RpcAppSystem instance. + * + * @param[in,out] rpc_app pointer to the instance to be used. + * @param[in] data pointer to the data buffer to be sent. + * @param[in] data_size size of the data buffer, in bytes. + */ void rpc_system_app_exchange_data(RpcAppSystem* rpc_app, const uint8_t* data, size_t data_size); #ifdef __cplusplus diff --git a/assets/protobuf b/assets/protobuf index 327163d586..23ad19a756 160000 --- a/assets/protobuf +++ b/assets/protobuf @@ -1 +1 @@ -Subproject commit 327163d5867c7aa3051334c93ced718d15bfe4da +Subproject commit 23ad19a756649ed9f6677b598e5361c5cce6847b diff --git a/scripts/fbt_tools/fbt_assets.py b/scripts/fbt_tools/fbt_assets.py index 5c32ae1a98..492a66b665 100644 --- a/scripts/fbt_tools/fbt_assets.py +++ b/scripts/fbt_tools/fbt_assets.py @@ -80,22 +80,35 @@ def __invoke_git(args, source_dir): def _proto_ver_generator(target, source, env): target_file = target[0] src_dir = source[0].dir.abspath - try: - __invoke_git( - ["fetch", "--tags"], - source_dir=src_dir, - ) - except (subprocess.CalledProcessError, EnvironmentError): - # Not great, not terrible - print(fg.boldred("Git: fetch failed")) - try: - git_describe = __invoke_git( - ["describe", "--tags", "--abbrev=0"], - source_dir=src_dir, - ) - except (subprocess.CalledProcessError, EnvironmentError): - raise StopError("Git: describe failed") + def fetch(unshallow=False): + git_args = ["fetch", "--tags"] + if unshallow: + git_args.append("--unshallow") + + try: + __invoke_git(git_args, source_dir=src_dir) + except (subprocess.CalledProcessError, EnvironmentError): + # Not great, not terrible + print(fg.boldred("Git: fetch failed")) + + def describe(): + try: + return __invoke_git( + ["describe", "--tags", "--abbrev=0"], + source_dir=src_dir, + ) + except (subprocess.CalledProcessError, EnvironmentError): + return None + + fetch() + git_describe = describe() + if not git_describe: + fetch(unshallow=True) + git_describe = describe() + + if not git_describe: + raise StopError("Failed to process git tags for protobuf versioning") git_major, git_minor = git_describe.split(".") version_file_data = ( diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 5f8e836c00..0eadd799d4 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1950,14 +1950,12 @@ Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCal Function,+,rpc_session_set_context,void,"RpcSession*, void*" Function,+,rpc_session_set_send_bytes_callback,void,"RpcSession*, RpcSendBytesCallback" Function,+,rpc_session_set_terminated_callback,void,"RpcSession*, RpcSessionTerminatedCallback" -Function,+,rpc_system_app_confirm,void,"RpcAppSystem*, RpcAppSystemEvent, _Bool" +Function,+,rpc_system_app_confirm,void,"RpcAppSystem*, _Bool" Function,+,rpc_system_app_error_reset,void,RpcAppSystem* Function,+,rpc_system_app_exchange_data,void,"RpcAppSystem*, const uint8_t*, size_t" -Function,+,rpc_system_app_get_data,const char*,RpcAppSystem* Function,+,rpc_system_app_send_exited,void,RpcAppSystem* Function,+,rpc_system_app_send_started,void,RpcAppSystem* Function,+,rpc_system_app_set_callback,void,"RpcAppSystem*, RpcAppSystemCallback, void*" -Function,+,rpc_system_app_set_data_exchange_callback,void,"RpcAppSystem*, RpcAppSystemDataExchangeCallback, void*" Function,+,rpc_system_app_set_error_code,void,"RpcAppSystem*, uint32_t" Function,+,rpc_system_app_set_error_text,void,"RpcAppSystem*, const char*" Function,-,rpmatch,int,const char* diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 57adf96aec..9834531953 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -2493,14 +2493,12 @@ Function,+,rpc_session_set_close_callback,void,"RpcSession*, RpcSessionClosedCal Function,+,rpc_session_set_context,void,"RpcSession*, void*" Function,+,rpc_session_set_send_bytes_callback,void,"RpcSession*, RpcSendBytesCallback" Function,+,rpc_session_set_terminated_callback,void,"RpcSession*, RpcSessionTerminatedCallback" -Function,+,rpc_system_app_confirm,void,"RpcAppSystem*, RpcAppSystemEvent, _Bool" +Function,+,rpc_system_app_confirm,void,"RpcAppSystem*, _Bool" Function,+,rpc_system_app_error_reset,void,RpcAppSystem* Function,+,rpc_system_app_exchange_data,void,"RpcAppSystem*, const uint8_t*, size_t" -Function,+,rpc_system_app_get_data,const char*,RpcAppSystem* Function,+,rpc_system_app_send_exited,void,RpcAppSystem* Function,+,rpc_system_app_send_started,void,RpcAppSystem* Function,+,rpc_system_app_set_callback,void,"RpcAppSystem*, RpcAppSystemCallback, void*" -Function,+,rpc_system_app_set_data_exchange_callback,void,"RpcAppSystem*, RpcAppSystemDataExchangeCallback, void*" Function,+,rpc_system_app_set_error_code,void,"RpcAppSystem*, uint32_t" Function,+,rpc_system_app_set_error_text,void,"RpcAppSystem*, const char*" Function,-,rpmatch,int,const char* From dc246ddb0958b17707b4dad9e8e1609f3517d662 Mon Sep 17 00:00:00 2001 From: Tobias Jost Date: Wed, 15 Nov 2023 08:39:29 +0100 Subject: [PATCH 19/40] Fix limited_credit_value having wrong value in mf_desfire_file_settings_parse (#3204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: hedger Co-authored-by: あく --- lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index 30313ae2bc..129dcdf5e1 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -201,7 +201,7 @@ bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer data->value.lo_limit = layout.value.lo_limit; data->value.hi_limit = layout.value.hi_limit; - data->value.limited_credit_value = layout.value.hi_limit; + data->value.limited_credit_value = layout.value.limited_credit_value; data->value.limited_credit_enabled = layout.value.limited_credit_enabled; } else if( From d0b9a3a4ae7abbb1a0e97616226d2b77d86f08e7 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:02:35 +0300 Subject: [PATCH 20/40] [NFC] MF Ultralight no pwd polling adjustment (#3207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Listener log level changed to Trace * Show pages count without pwd pages in case of no auth success * Fixed unit tests Co-authored-by: gornekich Co-authored-by: あく --- applications/debug/unit_tests/nfc/nfc_test.c | 19 +++++++++--- .../mf_ultralight/mf_ultralight_listener.c | 30 +++++++++---------- .../mf_ultralight/mf_ultralight_poller.c | 4 +++ 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index 2d647f8ef5..ce5a9cb9cc 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -203,10 +203,21 @@ static void mf_ultralight_reader_test(const char* path) { NfcDevice* nfc_device = nfc_device_alloc(); mu_assert(nfc_device_load(nfc_device, path), "nfc_device_load() failed\r\n"); - NfcListener* mfu_listener = nfc_listener_alloc( - listener, - NfcProtocolMfUltralight, - nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)); + MfUltralightData* data = + (MfUltralightData*)nfc_device_get_data(nfc_device, NfcProtocolMfUltralight); + + uint32_t features = mf_ultralight_get_feature_support_set(data->type); + bool pwd_supported = + mf_ultralight_support_feature(features, MfUltralightFeatureSupportPasswordAuth); + uint8_t pwd_num = mf_ultralight_get_pwd_page_num(data->type); + const uint8_t zero_pwd[4] = {0, 0, 0, 0}; + + if(pwd_supported && !memcmp(data->page[pwd_num].data, zero_pwd, sizeof(zero_pwd))) { + data->pages_read -= 2; + } + + NfcListener* mfu_listener = nfc_listener_alloc(listener, NfcProtocolMfUltralight, data); + nfc_listener_start(mfu_listener, NULL, NULL); MfUltralightData* mfu_data = mf_ultralight_alloc(); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c index 70c6f6de2a..5bef2a354c 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_listener.c @@ -122,7 +122,7 @@ static MfUltralightCommand uint16_t pages_total = instance->data->pages_total; MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_READ: %d", start_page); + FURI_LOG_T(TAG, "CMD_READ: %d", start_page); do { bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type); @@ -154,7 +154,7 @@ static MfUltralightCommand static MfUltralightCommand mf_ultralight_listener_fast_read_handler(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; - FURI_LOG_D(TAG, "CMD_FAST_READ"); + FURI_LOG_T(TAG, "CMD_FAST_READ"); do { if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportFastRead)) @@ -206,7 +206,7 @@ static MfUltralightCommand uint16_t pages_total = instance->data->pages_total; MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_WRITE"); + FURI_LOG_T(TAG, "CMD_WRITE"); do { bool do_i2c_check = mf_ultralight_is_i2c_tag(instance->data->type); @@ -235,7 +235,7 @@ static MfUltralightCommand static MfUltralightCommand mf_ultralight_listener_fast_write_handler(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; - FURI_LOG_D(TAG, "CMD_FAST_WRITE"); + FURI_LOG_T(TAG, "CMD_FAST_WRITE"); do { if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportFastWrite)) @@ -261,7 +261,7 @@ static MfUltralightCommand UNUSED(buffer); MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; - FURI_LOG_D(TAG, "CMD_GET_VERSION"); + FURI_LOG_T(TAG, "CMD_GET_VERSION"); if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadVersion)) { bit_buffer_copy_bytes( @@ -280,7 +280,7 @@ static MfUltralightCommand mf_ultralight_listener_read_signature_handler( UNUSED(buffer); MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; - FURI_LOG_D(TAG, "CMD_READ_SIG"); + FURI_LOG_T(TAG, "CMD_READ_SIG"); if(mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportReadSignature)) { bit_buffer_copy_bytes( @@ -297,7 +297,7 @@ static MfUltralightCommand mf_ultralight_listener_read_counter_handler(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_READ_CNT"); + FURI_LOG_T(TAG, "CMD_READ_CNT"); do { uint8_t counter_num = bit_buffer_get_byte(buffer, 1); @@ -338,7 +338,7 @@ static MfUltralightCommand mf_ultralight_listener_increase_counter_handler( BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_INCR_CNT"); + FURI_LOG_T(TAG, "CMD_INCR_CNT"); do { if(!mf_ultralight_support_feature( @@ -374,7 +374,7 @@ static MfUltralightCommand mf_ultralight_listener_check_tearing_handler( BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_CHECK_TEARING"); + FURI_LOG_T(TAG, "CMD_CHECK_TEARING"); do { uint8_t tearing_flag_num = bit_buffer_get_byte(buffer, 1); @@ -410,7 +410,7 @@ static MfUltralightCommand MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; UNUSED(instance); UNUSED(buffer); - FURI_LOG_D(TAG, "CMD_VCSL"); + FURI_LOG_T(TAG, "CMD_VCSL"); do { if(!mf_ultralight_support_feature(instance->features, MfUltralightFeatureSupportVcsl)) break; @@ -432,7 +432,7 @@ static MfUltralightCommand mf_ultralight_listener_auth_handler(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_AUTH"); + FURI_LOG_T(TAG, "CMD_AUTH"); do { if(!mf_ultralight_support_feature( @@ -474,7 +474,7 @@ static MfUltralightCommand static MfUltralightCommand mf_ultralight_comp_write_handler_p2(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; - FURI_LOG_D(TAG, "CMD_CM_WR_2"); + FURI_LOG_T(TAG, "CMD_CM_WR_2"); do { if(bit_buffer_get_size_bytes(buffer) != 16) break; @@ -492,7 +492,7 @@ static MfUltralightCommand mf_ultralight_comp_write_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedSilent; - FURI_LOG_D(TAG, "CMD_CM_WR_1"); + FURI_LOG_T(TAG, "CMD_CM_WR_1"); do { if(!mf_ultralight_support_feature( @@ -532,7 +532,7 @@ static MfUltralightCommand MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; UNUSED(instance); UNUSED(buffer); - FURI_LOG_D(TAG, "CMD_SEC_SEL_2"); + FURI_LOG_T(TAG, "CMD_SEC_SEL_2"); do { if(bit_buffer_get_size_bytes(buffer) != 4) break; @@ -550,7 +550,7 @@ static MfUltralightCommand mf_ultralight_sector_select_handler_p1(MfUltralightListener* instance, BitBuffer* buffer) { MfUltralightCommand command = MfUltralightCommandNotProcessedNAK; UNUSED(buffer); - FURI_LOG_D(TAG, "CMD_SEC_SEL_1"); + FURI_LOG_T(TAG, "CMD_SEC_SEL_1"); do { if(!mf_ultralight_support_feature( diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index bf0ced38d0..4ad7bc147d 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -487,6 +487,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll sizeof(MfUltralightAuthPassword), config->password.data); config->pack = instance->auth_context.pack; + instance->auth_context.auth_success = true; } } @@ -496,6 +497,9 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll // original card config->auth0 = instance->pages_read; config->access.prot = true; + } else if(!instance->auth_context.auth_success) { + instance->pages_read -= 2; + instance->data->pages_read -= 2; } } while(false); From c00776ca2279a86a62c253cfd2c3a910dabd7795 Mon Sep 17 00:00:00 2001 From: gornekich Date: Wed, 15 Nov 2023 12:32:45 +0400 Subject: [PATCH 21/40] [FL-3666] NFC API improvements (#3214) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * drivers: expose st25r3916 driver API * nfc poller: add start with custom callback * mf classic: rework sync API with poller custom start * mf ultralight: rework sync API with poller custom start * iso14443_3a poller: remove unused col res state * nfc: rework nfc poller custom start * mf ultralight: rename sync API * mf classic: rename sync API * iso14443-3a: rename sync API * nfc: remove async prefix in internal functions * nfc: expose internal API * nfc: fix sync api include and docs * targets: fix f18 build * nfc: rework NfcGenericEventEx type * nfc poller: add documentation * iso14443-3a poller: add documentation * felica poller: add documentation * iso14443_3b poller: add documentation * so14443_4a poller: add documentation * iso14443_4b poller: add documentation * iso15693 poller: add documentation * slix poller: add documentation * mf desfire poller: add documentation * mf ultralight poller: fix API and add documentation * mf classic poller: add documentation Co-authored-by: あく --- applications/debug/unit_tests/nfc/nfc_test.c | 44 +-- .../nfc/plugins/supported_cards/plantain.c | 8 +- .../main/nfc/plugins/supported_cards/troika.c | 8 +- .../nfc/plugins/supported_cards/two_cities.c | 8 +- lib/drivers/SConscript | 2 + lib/nfc/SConscript | 6 +- lib/nfc/nfc_poller.c | 72 +++++ lib/nfc/nfc_poller.h | 37 +++ lib/nfc/protocols/felica/felica_poller.c | 4 +- lib/nfc/protocols/felica/felica_poller.h | 40 ++- lib/nfc/protocols/felica/felica_poller_i.c | 6 +- lib/nfc/protocols/felica/felica_poller_i.h | 4 +- .../iso14443_3a/iso14443_3a_poller.c | 4 +- .../iso14443_3a/iso14443_3a_poller.h | 115 ++++++- .../iso14443_3a/iso14443_3a_poller_i.c | 5 +- .../iso14443_3a/iso14443_3a_poller_i.h | 20 -- ...r_sync_api.c => iso14443_3a_poller_sync.c} | 4 +- ...r_sync_api.h => iso14443_3a_poller_sync.h} | 2 +- .../iso14443_3b/iso14443_3b_poller.c | 4 +- .../iso14443_3b/iso14443_3b_poller.h | 71 ++++- .../iso14443_3b/iso14443_3b_poller_i.c | 5 +- .../iso14443_3b/iso14443_3b_poller_i.h | 10 - lib/nfc/protocols/iso14443_4a/iso14443_4a.h | 16 +- lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h | 16 - .../iso14443_4a/iso14443_4a_poller.c | 3 +- .../iso14443_4a/iso14443_4a_poller.h | 70 ++++- .../iso14443_4a/iso14443_4a_poller_i.c | 2 +- .../iso14443_4a/iso14443_4a_poller_i.h | 10 - .../iso14443_4b/iso14443_4b_poller.h | 56 +++- .../iso14443_4b/iso14443_4b_poller_i.h | 7 - .../protocols/iso15693_3/iso15693_3_poller.c | 4 +- .../protocols/iso15693_3/iso15693_3_poller.h | 132 +++++++- .../iso15693_3/iso15693_3_poller_i.c | 28 +- .../iso15693_3/iso15693_3_poller_i.h | 30 -- .../protocols/mf_classic/mf_classic_poller.c | 68 ++--- .../protocols/mf_classic/mf_classic_poller.h | 281 ++++++++++++++---- .../mf_classic/mf_classic_poller_i.c | 16 +- .../mf_classic/mf_classic_poller_i.h | 31 -- ...er_sync_api.c => mf_classic_poller_sync.c} | 69 ++--- ...er_sync_api.h => mf_classic_poller_sync.h} | 16 +- .../protocols/mf_desfire/mf_desfire_poller.c | 15 +- .../protocols/mf_desfire/mf_desfire_poller.h | 259 +++++++++++++++- .../mf_desfire/mf_desfire_poller_i.c | 62 ++-- .../mf_desfire/mf_desfire_poller_i.h | 72 ----- .../mf_ultralight/mf_ultralight_poller.c | 25 +- .../mf_ultralight/mf_ultralight_poller.h | 178 ++++++++++- .../mf_ultralight/mf_ultralight_poller_i.c | 28 +- .../mf_ultralight/mf_ultralight_poller_i.h | 40 --- ...sync_api.c => mf_ultralight_poller_sync.c} | 51 ++-- .../mf_ultralight/mf_ultralight_poller_sync.h | 34 +++ .../mf_ultralight_poller_sync_api.h | 30 -- lib/nfc/protocols/nfc_protocol.h | 10 +- lib/nfc/protocols/slix/slix_poller.c | 7 +- lib/nfc/protocols/slix/slix_poller.h | 68 ++++- lib/nfc/protocols/slix/slix_poller_i.c | 4 +- lib/nfc/protocols/slix/slix_poller_i.h | 10 - lib/nfc/protocols/st25tb/st25tb_poller.c | 4 +- lib/nfc/protocols/st25tb/st25tb_poller.h | 17 ++ lib/nfc/protocols/st25tb/st25tb_poller_i.c | 19 +- lib/nfc/protocols/st25tb/st25tb_poller_i.h | 17 -- targets/f18/api_symbols.csv | 27 +- targets/f7/api_symbols.csv | 116 ++++++-- 62 files changed, 1708 insertions(+), 719 deletions(-) rename lib/nfc/protocols/iso14443_3a/{iso14443_3a_poller_sync_api.c => iso14443_3a_poller_sync.c} (93%) rename lib/nfc/protocols/iso14443_3a/{iso14443_3a_poller_sync_api.h => iso14443_3a_poller_sync.h} (58%) rename lib/nfc/protocols/mf_classic/{mf_classic_poller_sync_api.c => mf_classic_poller_sync.c} (88%) rename lib/nfc/protocols/mf_classic/{mf_classic_poller_sync_api.h => mf_classic_poller_sync.h} (64%) rename lib/nfc/protocols/mf_ultralight/{mf_ultralight_poller_sync_api.c => mf_ultralight_poller_sync.c} (83%) create mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h delete mode 100644 lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index ce5a9cb9cc..0dcd09046d 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -7,10 +7,10 @@ #include #include #include -#include +#include #include -#include -#include +#include +#include #include #include @@ -182,8 +182,8 @@ MU_TEST(iso14443_3a_reader) { Iso14443_3aData iso14443_3a_poller_data = {}; mu_assert( - iso14443_3a_poller_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone, - "iso14443_3a_poller_read() failed"); + iso14443_3a_poller_sync_read(poller, &iso14443_3a_poller_data) == Iso14443_3aErrorNone, + "iso14443_3a_poller_sync_read() failed"); nfc_listener_stop(iso3_listener); mu_assert( @@ -221,8 +221,8 @@ static void mf_ultralight_reader_test(const char* path) { nfc_listener_start(mfu_listener, NULL, NULL); MfUltralightData* mfu_data = mf_ultralight_alloc(); - MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); nfc_listener_stop(mfu_listener); nfc_listener_free(mfu_listener); @@ -270,8 +270,8 @@ MU_TEST(ntag_213_locked_reader) { nfc_listener_start(mfu_listener, NULL, NULL); MfUltralightData* mfu_data = mf_ultralight_alloc(); - MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); nfc_listener_stop(mfu_listener); nfc_listener_free(mfu_listener); @@ -308,8 +308,8 @@ static void mf_ultralight_write() { MfUltralightData* mfu_data = mf_ultralight_alloc(); // Initial read - MfUltralightError error = mf_ultralight_poller_read_card(poller, mfu_data); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + MfUltralightError error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); mu_assert( mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)), @@ -321,13 +321,13 @@ static void mf_ultralight_write() { FURI_LOG_D(TAG, "Writing page %d", i); furi_hal_random_fill_buf(page.data, sizeof(MfUltralightPage)); mfu_data->page[i] = page; - error = mf_ultralight_poller_write_page(poller, i, &page); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_write_page() failed"); + error = mf_ultralight_poller_sync_write_page(poller, i, &page); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_write_page() failed"); } // Verification read - error = mf_ultralight_poller_read_card(poller, mfu_data); - mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_read_card() failed"); + error = mf_ultralight_poller_sync_read_card(poller, mfu_data); + mu_assert(error == MfUltralightErrorNone, "mf_ultralight_poller_sync_read_card() failed"); nfc_listener_stop(mfu_listener); const MfUltralightData* mfu_listener_data = @@ -355,7 +355,7 @@ static void mf_classic_reader() { MfClassicBlock block = {}; MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; - mf_classic_poller_read_block(poller, 0, &key, MfClassicKeyTypeA, &block); + mf_classic_poller_sync_read_block(poller, 0, &key, MfClassicKeyTypeA, &block); nfc_listener_stop(mfc_listener); nfc_listener_free(mfc_listener); @@ -383,8 +383,8 @@ static void mf_classic_write() { furi_hal_random_fill_buf(block_write.data, sizeof(MfClassicBlock)); MfClassicKey key = {.data = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; - mf_classic_poller_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write); - mf_classic_poller_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read); + mf_classic_poller_sync_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write); + mf_classic_poller_sync_read_block(poller, 1, &key, MfClassicKeyTypeA, &block_read); nfc_listener_stop(mfc_listener); nfc_listener_free(mfc_listener); @@ -413,16 +413,18 @@ static void mf_classic_value_block() { mf_classic_value_to_block(value, 1, &block_write); MfClassicError error = MfClassicErrorNone; - error = mf_classic_poller_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write); + error = mf_classic_poller_sync_write_block(poller, 1, &key, MfClassicKeyTypeA, &block_write); mu_assert(error == MfClassicErrorNone, "Write failed"); int32_t data = 200; int32_t new_value = 0; - error = mf_classic_poller_change_value(poller, 1, &key, MfClassicKeyTypeA, data, &new_value); + error = + mf_classic_poller_sync_change_value(poller, 1, &key, MfClassicKeyTypeA, data, &new_value); mu_assert(error == MfClassicErrorNone, "Value increment failed"); mu_assert(new_value == value + data, "Value not match"); - error = mf_classic_poller_change_value(poller, 1, &key, MfClassicKeyTypeA, -data, &new_value); + error = + mf_classic_poller_sync_change_value(poller, 1, &key, MfClassicKeyTypeA, -data, &new_value); mu_assert(error == MfClassicErrorNone, "Value decrement failed"); mu_assert(new_value == value, "Value not match"); diff --git a/applications/main/nfc/plugins/supported_cards/plantain.c b/applications/main/nfc/plugins/supported_cards/plantain.c index cb8c0093d0..a21e1cd415 100644 --- a/applications/main/nfc/plugins/supported_cards/plantain.c +++ b/applications/main/nfc/plugins/supported_cards/plantain.c @@ -4,7 +4,7 @@ #include #include -#include +#include #define TAG "Plantain" @@ -91,7 +91,7 @@ static bool plantain_verify_type(Nfc* nfc, MfClassicType type) { MfClassicAuthContext auth_context; MfClassicError error = - mf_classic_poller_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context); + mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context); if(error != MfClassicErrorNone) { FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); break; @@ -119,7 +119,7 @@ static bool plantain_read(Nfc* nfc, NfcDevice* device) { do { MfClassicType type = MfClassicTypeMini; - MfClassicError error = mf_classic_poller_detect_type(nfc, &type); + MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); if(error != MfClassicErrorNone) break; data->type = type; @@ -134,7 +134,7 @@ static bool plantain_read(Nfc* nfc, NfcDevice* device) { FURI_BIT_SET(keys.key_b_mask, i); } - error = mf_classic_poller_read(nfc, &keys, data); + error = mf_classic_poller_sync_read(nfc, &keys, data); if(error != MfClassicErrorNone) { FURI_LOG_W(TAG, "Failed to read data"); break; diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index d42b977c6c..7cf1e4dd8c 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -4,7 +4,7 @@ #include #include -#include +#include #define TAG "Troika" @@ -91,7 +91,7 @@ static bool troika_verify_type(Nfc* nfc, MfClassicType type) { MfClassicAuthContext auth_context; MfClassicError error = - mf_classic_poller_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context); + mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context); if(error != MfClassicErrorNone) { FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); break; @@ -118,7 +118,7 @@ static bool troika_read(Nfc* nfc, NfcDevice* device) { do { MfClassicType type = MfClassicTypeMini; - MfClassicError error = mf_classic_poller_detect_type(nfc, &type); + MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); if(error != MfClassicErrorNone) break; data->type = type; @@ -136,7 +136,7 @@ static bool troika_read(Nfc* nfc, NfcDevice* device) { FURI_BIT_SET(keys.key_b_mask, i); } - error = mf_classic_poller_read(nfc, &keys, data); + error = mf_classic_poller_sync_read(nfc, &keys, data); if(error != MfClassicErrorNone) { FURI_LOG_W(TAG, "Failed to read data"); break; diff --git a/applications/main/nfc/plugins/supported_cards/two_cities.c b/applications/main/nfc/plugins/supported_cards/two_cities.c index fb964103ee..1748d372d2 100644 --- a/applications/main/nfc/plugins/supported_cards/two_cities.c +++ b/applications/main/nfc/plugins/supported_cards/two_cities.c @@ -4,7 +4,7 @@ #include #include -#include +#include #define TAG "TwoCities" @@ -49,7 +49,7 @@ bool two_cities_verify(Nfc* nfc) { MfClassicAuthContext auth_ctx = {}; MfClassicError error = - mf_classic_poller_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx); + mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx); if(error != MfClassicErrorNone) { FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); break; @@ -72,7 +72,7 @@ static bool two_cities_read(Nfc* nfc, NfcDevice* device) { do { MfClassicType type = MfClassicTypeMini; - MfClassicError error = mf_classic_poller_detect_type(nfc, &type); + MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); if(error != MfClassicErrorNone) break; data->type = type; @@ -84,7 +84,7 @@ static bool two_cities_read(Nfc* nfc, NfcDevice* device) { FURI_BIT_SET(keys.key_b_mask, i); } - error = mf_classic_poller_read(nfc, &keys, data); + error = mf_classic_poller_sync_read(nfc, &keys, data); if(error != MfClassicErrorNone) { FURI_LOG_W(TAG, "Failed to read data"); break; diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript index 103472ccb3..cf93d4bce9 100644 --- a/lib/drivers/SConscript +++ b/lib/drivers/SConscript @@ -6,6 +6,8 @@ env.Append( ], SDK_HEADERS=[ File("cc1101_regs.h"), + File("st25r3916_reg.h"), + File("st25r3916.h"), ], ) diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 6c55cf5d2b..605a8639dd 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -36,9 +36,9 @@ env.Append( File("protocols/mf_ultralight/mf_ultralight_listener.h"), File("protocols/mf_classic/mf_classic_listener.h"), # Sync API - File("protocols/iso14443_3a/iso14443_3a_poller_sync_api.h"), - File("protocols/mf_ultralight/mf_ultralight_poller_sync_api.h"), - File("protocols/mf_classic/mf_classic_poller_sync_api.h"), + File("protocols/iso14443_3a/iso14443_3a_poller_sync.h"), + File("protocols/mf_ultralight/mf_ultralight_poller_sync.h"), + File("protocols/mf_classic/mf_classic_poller_sync.h"), # Misc File("helpers/nfc_util.h"), File("helpers/iso14443_crc.h"), diff --git a/lib/nfc/nfc_poller.c b/lib/nfc/nfc_poller.c index ffe0318a0d..48be37d925 100644 --- a/lib/nfc/nfc_poller.c +++ b/lib/nfc/nfc_poller.c @@ -28,6 +28,9 @@ struct NfcPoller { NfcPollerList list; NfcPollerSessionState session_state; bool protocol_detected; + + NfcGenericCallbackEx callback; + void* context; }; static void nfc_poller_list_alloc(NfcPoller* instance) { @@ -127,6 +130,75 @@ void nfc_poller_start(NfcPoller* instance, NfcGenericCallback callback, void* co nfc_start(instance->nfc, nfc_poller_start_callback, instance); } +static NfcCommand nfc_poller_start_ex_tail_callback(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol != NfcProtocolInvalid); + + NfcPoller* instance = context; + NfcCommand command = NfcCommandContinue; + + NfcGenericEventEx poller_event = { + .poller = instance->list.tail->poller, + .parent_event_data = event.event_data, + }; + + command = instance->callback(poller_event, instance->context); + + return command; +} + +static NfcCommand nfc_poller_start_ex_head_callback(NfcEvent event, void* context) { + furi_assert(context); + + NfcCommand command = NfcCommandContinue; + NfcPoller* instance = context; + + NfcProtocol parent_protocol = nfc_protocol_get_parent(instance->protocol); + + if(parent_protocol == NfcProtocolInvalid) { + NfcGenericEventEx poller_event = { + .poller = instance->list.tail->poller, + .parent_event_data = &event, + }; + + command = instance->callback(poller_event, instance->context); + } else { + NfcGenericEvent poller_event = { + .protocol = NfcProtocolInvalid, + .instance = instance->nfc, + .event_data = &event, + }; + NfcPollerListElement* head_poller = instance->list.head; + command = head_poller->poller_api->run(poller_event, head_poller->poller); + } + + if(instance->session_state == NfcPollerSessionStateStopRequest) { + command = NfcCommandStop; + } + + return command; +} + +void nfc_poller_start_ex(NfcPoller* instance, NfcGenericCallbackEx callback, void* context) { + furi_assert(instance); + furi_assert(callback); + furi_assert(instance->session_state == NfcPollerSessionStateIdle); + + instance->callback = callback; + instance->context = context; + + NfcProtocol parent_protocol = nfc_protocol_get_parent(instance->protocol); + if(parent_protocol != NfcProtocolInvalid) { + NfcPollerListElement* iter = instance->list.head; + while(iter->protocol != parent_protocol) iter = iter->child; + + iter->poller_api->set_callback(iter->poller, nfc_poller_start_ex_tail_callback, instance); + } + + instance->session_state = NfcPollerSessionStateActive; + nfc_start(instance->nfc, nfc_poller_start_ex_head_callback, instance); +} + void nfc_poller_stop(NfcPoller* instance) { furi_assert(instance); furi_assert(instance->nfc); diff --git a/lib/nfc/nfc_poller.h b/lib/nfc/nfc_poller.h index 8ae01a8e43..18fbfb388a 100644 --- a/lib/nfc/nfc_poller.h +++ b/lib/nfc/nfc_poller.h @@ -26,6 +26,31 @@ extern "C" { */ typedef struct NfcPoller NfcPoller; +/** + * @brief Extended generic Nfc event type. + * + * An extended generic Nfc event contains protocol poller and it's parent protocol event data. + * If protocol has no parent, then events are produced by Nfc instance. + * + * The parent_event_data field is protocol-specific and should be cast to the appropriate type before use. + */ +typedef struct { + NfcGenericInstance* poller; /**< Pointer to the protocol poller. */ + NfcGenericEventData* + parent_event_data /**< Pointer to the protocol's parent poller event data. */; +} NfcGenericEventEx; + +/** + * @brief Extended generic Nfc event callback type. + * + * A function of this type must be passed as the callback parameter upon extended start of a poller. + * + * @param [in] event Nfc extended generic event, passed by value, complete with protocol type and data. + * @param [in,out] context pointer to the user-specific context (set when starting a poller/listener instance). + * @returns the command which the event producer must execute. + */ +typedef NfcCommand (*NfcGenericCallbackEx)(NfcGenericEventEx event, void* context); + /** * @brief Allocate an NfcPoller instance. * @@ -57,6 +82,18 @@ void nfc_poller_free(NfcPoller* instance); */ void nfc_poller_start(NfcPoller* instance, NfcGenericCallback callback, void* context); +/** + * @brief Start an NfcPoller instance in extended mode. + * + * When nfc poller is started in extended mode, callback will be called with parent protocol events + * and protocol instance. This mode enables to make custom poller state machines. + * + * @param[in,out] instance pointer to the instance to be started. + * @param[in] callback pointer to a user-defined callback function which will receive events. + * @param[in] context pointer to a user-specific context (will be passed to the callback). + */ +void nfc_poller_start_ex(NfcPoller* instance, NfcGenericCallbackEx callback, void* context); + /** * @brief Stop an NfcPoller instance. * diff --git a/lib/nfc/protocols/felica/felica_poller.c b/lib/nfc/protocols/felica/felica_poller.c index 3fc2affedc..23b1604e19 100644 --- a/lib/nfc/protocols/felica/felica_poller.c +++ b/lib/nfc/protocols/felica/felica_poller.c @@ -66,7 +66,7 @@ static NfcCommand felica_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { if(instance->state != FelicaPollerStateActivated) { - FelicaError error = felica_poller_async_activate(instance, instance->data); + FelicaError error = felica_poller_activate(instance, instance->data); if(error == FelicaErrorNone) { instance->felica_event.type = FelicaPollerEventTypeReady; instance->felica_event_data.error = error; @@ -100,7 +100,7 @@ static bool felica_poller_detect(NfcGenericEvent event, void* context) { furi_assert(instance->state == FelicaPollerStateIdle); if(nfc_event->type == NfcEventTypePollerReady) { - FelicaError error = felica_poller_async_activate(instance, instance->data); + FelicaError error = felica_poller_activate(instance, instance->data); protocol_detected = (error == FelicaErrorNone); } diff --git a/lib/nfc/protocols/felica/felica_poller.h b/lib/nfc/protocols/felica/felica_poller.h index 7d0c9525e7..45fd9a9a1f 100644 --- a/lib/nfc/protocols/felica/felica_poller.h +++ b/lib/nfc/protocols/felica/felica_poller.h @@ -9,22 +9,50 @@ extern "C" { #endif +/** + * @brief FelicaPoller opaque type definition. + */ typedef struct FelicaPoller FelicaPoller; +/** + * @brief Enumeration of possible Felica poller event types. + */ typedef enum { - FelicaPollerEventTypeError, - FelicaPollerEventTypeReady, + FelicaPollerEventTypeError, /**< The card was activated by the poller. */ + FelicaPollerEventTypeReady, /**< An error occured during activation procedure. */ } FelicaPollerEventType; -typedef struct { - FelicaError error; +/** + * @brief Felica poller event data. + */ +typedef union { + FelicaError error; /**< Error code indicating card activation fail reason. */ } FelicaPollerEventData; +/** + * @brief FelicaPoller poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - FelicaPollerEventType type; - FelicaPollerEventData* data; + FelicaPollerEventType type; /**< Type of emmitted event. */ + FelicaPollerEventData* data; /**< Pointer to event specific data. */ } FelicaPollerEvent; +/** + * @brief Perform collision resolution procedure. + * + * Must ONLY be used inside the callback function. + * + * Perfoms the collision resolution procedure as defined in FeliCa standars. The data + * field will be filled with Felica data on success. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the Felica data structure to be filled. + * @return FelicaErrorNone on success, an error code on failure. + */ +FelicaError felica_poller_activate(FelicaPoller* instance, FelicaData* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/felica/felica_poller_i.c b/lib/nfc/protocols/felica/felica_poller_i.c index d8015fdfad..bfbf150ef9 100644 --- a/lib/nfc/protocols/felica/felica_poller_i.c +++ b/lib/nfc/protocols/felica/felica_poller_i.c @@ -49,7 +49,7 @@ static FelicaError felica_poller_frame_exchange( return ret; } -FelicaError felica_poller_async_polling( +FelicaError felica_poller_polling( FelicaPoller* instance, const FelicaPollerPollingCommand* cmd, FelicaPollerPollingResponse* resp) { @@ -93,7 +93,7 @@ FelicaError felica_poller_async_polling( return error; } -FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* data) { +FelicaError felica_poller_activate(FelicaPoller* instance, FelicaData* data) { furi_assert(instance); felica_reset(data); @@ -112,7 +112,7 @@ FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* dat }; FelicaPollerPollingResponse polling_resp = {}; - ret = felica_poller_async_polling(instance, &polling_cmd, &polling_resp); + ret = felica_poller_polling(instance, &polling_cmd, &polling_resp); if(ret != FelicaErrorNone) { FURI_LOG_T(TAG, "Activation failed error: %d", ret); diff --git a/lib/nfc/protocols/felica/felica_poller_i.h b/lib/nfc/protocols/felica/felica_poller_i.h index e12f014726..3bd4d91f9f 100644 --- a/lib/nfc/protocols/felica/felica_poller_i.h +++ b/lib/nfc/protocols/felica/felica_poller_i.h @@ -48,13 +48,11 @@ typedef struct { const FelicaData* felica_poller_get_data(FelicaPoller* instance); -FelicaError felica_poller_async_polling( +FelicaError felica_poller_polling( FelicaPoller* instance, const FelicaPollerPollingCommand* cmd, FelicaPollerPollingResponse* resp); -FelicaError felica_poller_async_activate(FelicaPoller* instance, FelicaData* data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c index 880092c333..158250acdf 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.c @@ -72,7 +72,7 @@ static NfcCommand iso14443_3a_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { if(instance->state != Iso14443_3aPollerStateActivated) { Iso14443_3aData data = {}; - Iso14443_3aError error = iso14443_3a_poller_async_activate(instance, &data); + Iso14443_3aError error = iso14443_3a_poller_activate(instance, &data); if(error == Iso14443_3aErrorNone) { instance->state = Iso14443_3aPollerStateActivated; instance->iso14443_3a_event.type = Iso14443_3aPollerEventTypeReady; @@ -111,7 +111,7 @@ static bool iso14443_3a_poller_detect(NfcGenericEvent event, void* context) { furi_assert(instance->state == Iso14443_3aPollerStateIdle); if(nfc_event->type == NfcEventTypePollerReady) { - Iso14443_3aError error = iso14443_3a_poller_async_activate(instance, NULL); + Iso14443_3aError error = iso14443_3a_poller_activate(instance, NULL); protocol_detected = (error == Iso14443_3aErrorNone); } diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h index 385cd52256..42e4b4bf52 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h @@ -9,34 +9,137 @@ extern "C" { #endif +/** + * @brief Iso14443_3aPoller opaque type definition. + */ typedef struct Iso14443_3aPoller Iso14443_3aPoller; +/** + * @brief Enumeration of possible Iso14443_3a poller event types. + */ typedef enum { - Iso14443_3aPollerEventTypeError, - Iso14443_3aPollerEventTypeReady, + Iso14443_3aPollerEventTypeError, /**< The card was activated by the poller. */ + Iso14443_3aPollerEventTypeReady, /**< An error occured during activation procedure. */ } Iso14443_3aPollerEventType; -typedef struct { - Iso14443_3aError error; +/** + * @brief Iso14443_3a poller event data. + */ +typedef union { + Iso14443_3aError error; /**< Error code indicating card activation fail reason. */ } Iso14443_3aPollerEventData; +/** + * @brief Iso14443_3a poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso14443_3aPollerEventType type; - Iso14443_3aPollerEventData* data; + Iso14443_3aPollerEventType type; /**< Type of emmitted event. */ + Iso14443_3aPollerEventData* data; /**< Pointer to event specific data. */ } Iso14443_3aPollerEvent; +/** + * @brief Transmit and receive Iso14443_3a frames in poller mode. + * + * Must ONLY be used inside the callback function. + * + * The rx_buffer will be filled with any data received as a response to data + * sent from tx_buffer, with a timeout defined by the fwt parameter. + * + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tx_buffer pointer to the buffer containing the data to be transmitted. + * @param[out] rx_buffer pointer to the buffer to be filled with received data. + * @param[in] fwt frame wait time (response timeout), in carrier cycles. + * @return Iso14443_3aErrorNone on success, an error code on failure. + */ Iso14443_3aError iso14443_3a_poller_txrx( Iso14443_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt); +/** + * @brief Transmit and receive Iso14443_3a standard frames in poller mode. + * + * Must ONLY be used inside the callback function. + * + * The rx_buffer will be filled with any data received as a response to data + * sent from tx_buffer, with a timeout defined by the fwt parameter. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tx_buffer pointer to the buffer containing the data to be transmitted. + * @param[out] rx_buffer pointer to the buffer to be filled with received data. + * @param[in] fwt frame wait time (response timeout), in carrier cycles. + * @return Iso14443_3aErrorNone on success, an error code on failure. + */ Iso14443_3aError iso14443_3a_poller_send_standard_frame( Iso14443_3aPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, uint32_t fwt); +/** + * @brief Transmit and receive Iso14443_3a frames with custom parity bits in poller mode. + * + * Must ONLY be used inside the callback function. + * + * The rx_buffer will be filled with any data received as a response to data + * sent from tx_buffer, with a timeout defined by the fwt parameter. + * + * Custom parity bits must be set in the tx_buffer. The rx_buffer will contain + * the received data with the parity bits. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tx_buffer pointer to the buffer containing the data to be transmitted. + * @param[out] rx_buffer pointer to the buffer to be filled with received data. + * @param[in] fwt frame wait time (response timeout), in carrier cycles. + * @return Iso14443_3aErrorNone on success, an error code on failure. + */ +Iso14443_3aError iso14443_3a_poller_txrx_custom_parity( + Iso14443_3aPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +/** + * @brief Checks presence of Iso14443_3a complient card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @return Iso14443_3aErrorNone if card is present, an error code otherwise. + */ +Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance); + +/** + * @brief Perform collision resolution procedure. + * + * Must ONLY be used inside the callback function. + * + * Perfoms the collision resolution procedure as defined in Iso14443-3a. The iso14443_3a_data + * field will be filled with Iso14443-3a data on success. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] iso14443_3a_data pointer to the Iso14443_3a data structure to be filled. + * @return Iso14443_3aErrorNone on success, an error code on failure. + */ +Iso14443_3aError + iso14443_3a_poller_activate(Iso14443_3aPoller* instance, Iso14443_3aData* iso14443_3a_data); + +/** + * @brief Send HALT command to the card. + * + * Must ONLY be used inside the callback function. + * + * Halts card and changes internal Iso14443_3aPoller state to Idle. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @return Iso14443_3aErrorNone on success, an error code on failure. + */ +Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c index 3434dc8e35..2be88bc515 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.c @@ -94,9 +94,8 @@ Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance) { return Iso14443_3aErrorNone; } -Iso14443_3aError iso14443_3a_poller_async_activate( - Iso14443_3aPoller* instance, - Iso14443_3aData* iso14443_3a_data) { +Iso14443_3aError + iso14443_3a_poller_activate(Iso14443_3aPoller* instance, Iso14443_3aData* iso14443_3a_data) { furi_assert(instance); furi_assert(instance->nfc); furi_assert(instance->tx_buffer); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h index 063ef15566..764f1a6b59 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h @@ -39,15 +39,9 @@ typedef enum { Iso14443_3aPollerStateActivated, } Iso14443_3aPollerState; -typedef enum { - Iso14443_3aPollerConfigStateIdle, - Iso14443_3aPollerConfigStateDone, -} Iso14443_3aPollerConfigState; - struct Iso14443_3aPoller { Nfc* nfc; Iso14443_3aPollerState state; - Iso14443_3aPollerConfigState config_state; Iso14443_3aPollerColRes col_res; Iso14443_3aData* data; BitBuffer* tx_buffer; @@ -62,20 +56,6 @@ struct Iso14443_3aPoller { const Iso14443_3aData* iso14443_3a_poller_get_data(Iso14443_3aPoller* instance); -Iso14443_3aError iso14443_3a_poller_check_presence(Iso14443_3aPoller* instance); - -Iso14443_3aError iso14443_3a_poller_async_activate( - Iso14443_3aPoller* instance, - Iso14443_3aData* iso14443_3a_data); - -Iso14443_3aError iso14443_3a_poller_halt(Iso14443_3aPoller* instance); - -Iso14443_3aError iso14443_3a_poller_txrx_custom_parity( - Iso14443_3aPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.c similarity index 93% rename from lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c rename to lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.c index 2bab1a881a..ea7a6ae156 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.c +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.c @@ -1,4 +1,4 @@ -#include "iso14443_3a_poller_sync_api.h" +#include "iso14443_3a_poller_sync.h" #include "iso14443_3a_poller_i.h" #include @@ -34,7 +34,7 @@ NfcCommand iso14443_3a_poller_read_callback(NfcGenericEvent event, void* context return NfcCommandStop; } -Iso14443_3aError iso14443_3a_poller_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data) { +Iso14443_3aError iso14443_3a_poller_sync_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data) { furi_assert(nfc); furi_assert(iso14443_3a_data); diff --git a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h similarity index 58% rename from lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h rename to lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h index ed17ff4324..72f084d1b0 100644 --- a/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h +++ b/lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h @@ -7,7 +7,7 @@ extern "C" { #endif -Iso14443_3aError iso14443_3a_poller_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data); +Iso14443_3aError iso14443_3a_poller_sync_read(Nfc* nfc, Iso14443_3aData* iso14443_3a_data); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c index 9507f28c41..f0c9b67ad1 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.c @@ -70,7 +70,7 @@ static NfcCommand iso14443_3b_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { if(instance->state != Iso14443_3bPollerStateActivated) { - Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, instance->data); + Iso14443_3bError error = iso14443_3b_poller_activate(instance, instance->data); if(error == Iso14443_3bErrorNone) { instance->iso14443_3b_event.type = Iso14443_3bPollerEventTypeReady; instance->iso14443_3b_event_data.error = error; @@ -104,7 +104,7 @@ static bool iso14443_3b_poller_detect(NfcGenericEvent event, void* context) { furi_assert(instance->state == Iso14443_3bPollerStateIdle); if(nfc_event->type == NfcEventTypePollerReady) { - Iso14443_3bError error = iso14443_3b_poller_async_activate(instance, instance->data); + Iso14443_3bError error = iso14443_3b_poller_activate(instance, instance->data); protocol_detected = (error == Iso14443_3bErrorNone); } diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h index d25d9dbe9f..940903c1dc 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h @@ -9,22 +9,81 @@ extern "C" { #endif +/** + * @brief Iso14443_3bPoller opaque type definition. + */ typedef struct Iso14443_3bPoller Iso14443_3bPoller; +/** + * @brief Enumeration of possible Iso14443_3b poller event types. + */ typedef enum { - Iso14443_3bPollerEventTypeError, - Iso14443_3bPollerEventTypeReady, + Iso14443_3bPollerEventTypeError, /**< The card was activated by the poller. */ + Iso14443_3bPollerEventTypeReady, /**< An error occured during activation procedure. */ } Iso14443_3bPollerEventType; -typedef struct { - Iso14443_3bError error; +/** + * @brief Iso14443_3b poller event data. + */ +typedef union { + Iso14443_3bError error; /**< Error code indicating card activation fail reason. */ } Iso14443_3bPollerEventData; +/** + * @brief Iso14443_3b poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso14443_3bPollerEventType type; - Iso14443_3bPollerEventData* data; + Iso14443_3bPollerEventType type; /**< Type of emmitted event. */ + Iso14443_3bPollerEventData* data; /**< Pointer to event specific data. */ } Iso14443_3bPollerEvent; +/** + * @brief Transmit and receive Iso14443_3b frames in poller mode. + * + * Must ONLY be used inside the callback function. + * + * The rx_buffer will be filled with any data received as a response to data + * sent from tx_buffer, with a timeout defined by the fwt parameter. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tx_buffer pointer to the buffer containing the data to be transmitted. + * @param[out] rx_buffer pointer to the buffer to be filled with received data. + * @param[in] fwt frame wait time (response timeout), in carrier cycles. + * @return Iso14443_3bErrorNone on success, an error code on failure. + */ +Iso14443_3bError iso14443_3b_poller_send_frame( + Iso14443_3bPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer); + +/** + * @brief Perform collision resolution procedure. + * + * Must ONLY be used inside the callback function. + * + * Perfoms the collision resolution procedure as defined in Iso14443-3b. The data + * field will be filled with Iso14443-3b data on success. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the Iso14443_3b data structure to be filled. + * @return Iso14443_3bErrorNone on success, an error code on failure. + */ +Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data); + +/** + * @brief Send HALT command to the card. + * + * Must ONLY be used inside the callback function. + * + * Halts card and changes internal Iso14443_3bPoller state to Idle. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @return Iso14443_3bErrorNone on success, an error code on failure. + */ +Iso14443_3bError iso14443_3b_poller_halt(Iso14443_3bPoller* instance); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c index 95668ccf22..1ee5237c64 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c @@ -21,7 +21,7 @@ static Iso14443_3bError iso14443_3b_poller_prepare_trx(Iso14443_3bPoller* instan furi_assert(instance); if(instance->state == Iso14443_3bPollerStateIdle) { - return iso14443_3b_poller_async_activate(instance, NULL); + return iso14443_3b_poller_activate(instance, NULL); } return Iso14443_3bErrorNone; @@ -63,8 +63,7 @@ static Iso14443_3bError iso14443_3b_poller_frame_exchange( return ret; } -Iso14443_3bError - iso14443_3b_poller_async_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data) { +Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data) { furi_assert(instance); furi_assert(instance->nfc); diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h index 5821d6373f..2503c2e41e 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.h @@ -34,16 +34,6 @@ struct Iso14443_3bPoller { const Iso14443_3bData* iso14443_3b_poller_get_data(Iso14443_3bPoller* instance); -Iso14443_3bError - iso14443_3b_poller_async_activate(Iso14443_3bPoller* instance, Iso14443_3bData* data); - -Iso14443_3bError iso14443_3b_poller_halt(Iso14443_3bPoller* instance); - -Iso14443_3bError iso14443_3b_poller_send_frame( - Iso14443_3bPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h index 9580c14040..df212152de 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a.h @@ -2,6 +2,8 @@ #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -28,7 +30,19 @@ typedef enum { Iso14443_4aFrameOptionCid, } Iso14443_4aFrameOption; -typedef struct Iso14443_4aData Iso14443_4aData; +typedef struct { + uint8_t tl; + uint8_t t0; + uint8_t ta_1; + uint8_t tb_1; + uint8_t tc_1; + SimpleArray* t1_tk; +} Iso14443_4aAtsData; + +typedef struct { + Iso14443_3aData* iso14443_3a_data; + Iso14443_4aAtsData ats_data; +} Iso14443_4aData; // Virtual methods diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h index e45fb90cca..e5483a6ba1 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_i.h @@ -2,8 +2,6 @@ #include "iso14443_4a.h" -#include - #define ISO14443_4A_CMD_READ_ATS (0xE0) // ATS bit definitions @@ -23,20 +21,6 @@ #define ISO14443_4A_ATS_TC1_NAD (1U << 0) #define ISO14443_4A_ATS_TC1_CID (1U << 1) -typedef struct { - uint8_t tl; - uint8_t t0; - uint8_t ta_1; - uint8_t tb_1; - uint8_t tc_1; - SimpleArray* t1_tk; -} Iso14443_4aAtsData; - -struct Iso14443_4aData { - Iso14443_3aData* iso14443_3a_data; - Iso14443_4aAtsData ats_data; -}; - bool iso14443_4a_ats_parse(Iso14443_4aAtsData* data, const BitBuffer* buf); Iso14443_4aError iso14443_4a_process_error(Iso14443_3aError error); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c index c07cc6b7f0..e20048b509 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.c @@ -55,8 +55,7 @@ static NfcCommand iso14443_4a_poller_handler_idle(Iso14443_4aPoller* instance) { } static NfcCommand iso14443_4a_poller_handler_read_ats(Iso14443_4aPoller* instance) { - Iso14443_4aError error = - iso14443_4a_poller_async_read_ats(instance, &instance->data->ats_data); + Iso14443_4aError error = iso14443_4a_poller_read_ats(instance, &instance->data->ats_data); if(error == Iso14443_4aErrorNone) { FURI_LOG_D(TAG, "Read ATS success"); instance->poller_state = Iso14443_4aPollerStateReady; diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h index b224299e0a..73eb6ef74d 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller.h @@ -8,22 +8,80 @@ extern "C" { #endif +/** + * @brief Iso14443_4aPoller opaque type definition. + */ typedef struct Iso14443_4aPoller Iso14443_4aPoller; +/** + * @brief Enumeration of possible Iso14443_4a poller event types. + */ typedef enum { - Iso14443_4aPollerEventTypeError, - Iso14443_4aPollerEventTypeReady, + Iso14443_4aPollerEventTypeError, /**< The card was activated by the poller. */ + Iso14443_4aPollerEventTypeReady, /**< An error occured during activation procedure. */ } Iso14443_4aPollerEventType; -typedef struct { - Iso14443_4aError error; +/** + * @brief Iso14443_4a poller event data. + */ +typedef union { + Iso14443_4aError error; /**< Error code indicating card activation fail reason. */ } Iso14443_4aPollerEventData; +/** + * @brief Iso14443_4a poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso14443_4aPollerEventType type; - Iso14443_4aPollerEventData* data; + Iso14443_4aPollerEventType type; /**< Type of emmitted event. */ + Iso14443_4aPollerEventData* data; /**< Pointer to event specific data. */ } Iso14443_4aPollerEvent; +/** + * @brief Transmit and receive Iso14443_4a blocks in poller mode. + * + * Must ONLY be used inside the callback function. + * + * The rx_buffer will be filled with any data received as a response to data + * sent from tx_buffer. The fwt parameter is calculated during activation procedure. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tx_buffer pointer to the buffer containing the data to be transmitted. + * @param[out] rx_buffer pointer to the buffer to be filled with received data. + * @return Iso14443_4aErrorNone on success, an error code on failure. + */ +Iso14443_4aError iso14443_4a_poller_send_block( + Iso14443_4aPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer); + +/** + * @brief Send HALT command to the card. + * + * Must ONLY be used inside the callback function. + * + * Halts card and changes internal Iso14443_4aPoller state to Idle. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @return Iso14443_4aErrorNone on success, an error code on failure. + */ +Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance); + +/** + * @brief Read Answer To Select (ATS) from the card. + * + * Must ONLY be used inside the callback function. + * + * Send Request Answer To Select (RATS) command to the card and parse the response. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the buffer to be filled with ATS data. + * @return Iso14443_4aErrorNone on success, an error code on failure. + */ +Iso14443_4aError + iso14443_4a_poller_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index 7221e2aa94..938e4e715f 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -18,7 +18,7 @@ Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { } Iso14443_4aError - iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data) { + iso14443_4a_poller_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data) { furi_assert(instance); bit_buffer_reset(instance->tx_buffer); diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h index ce878cb40a..7aae852e43 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.h @@ -45,16 +45,6 @@ struct Iso14443_4aPoller { const Iso14443_4aData* iso14443_4a_poller_get_data(Iso14443_4aPoller* instance); -Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance); - -Iso14443_4aError - iso14443_4a_poller_async_read_ats(Iso14443_4aPoller* instance, Iso14443_4aAtsData* data); - -Iso14443_4aError iso14443_4a_poller_send_block( - Iso14443_4aPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h index e60090c04e..03b288c079 100644 --- a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h +++ b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h @@ -8,22 +8,66 @@ extern "C" { #endif +/** + * @brief Iso14443_4bPoller opaque type definition. + */ typedef struct Iso14443_4bPoller Iso14443_4bPoller; +/** + * @brief Enumeration of possible Iso14443_4b poller event types. + */ typedef enum { - Iso14443_4bPollerEventTypeError, - Iso14443_4bPollerEventTypeReady, + Iso14443_4bPollerEventTypeError, /**< The card was activated by the poller. */ + Iso14443_4bPollerEventTypeReady, /**< An error occured during activation procedure. */ } Iso14443_4bPollerEventType; -typedef struct { - Iso14443_4bError error; +/** + * @brief Iso14443_4b poller event data. + */ +typedef union { + Iso14443_4bError error; /**< Error code indicating card activation fail reason. */ } Iso14443_4bPollerEventData; +/** + * @brief Iso14443_4b poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso14443_4bPollerEventType type; - Iso14443_4bPollerEventData* data; + Iso14443_4bPollerEventType type; /**< Type of emmitted event. */ + Iso14443_4bPollerEventData* data; /**< Pointer to event specific data. */ } Iso14443_4bPollerEvent; +/** + * @brief Transmit and receive Iso14443_4b blocks in poller mode. + * + * Must ONLY be used inside the callback function. + * + * The rx_buffer will be filled with any data received as a response to data + * sent from tx_buffer. The fwt parameter is calculated during activation procedure. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tx_buffer pointer to the buffer containing the data to be transmitted. + * @param[out] rx_buffer pointer to the buffer to be filled with received data. + * @return Iso14443_4bErrorNone on success, an error code on failure. + */ +Iso14443_4bError iso14443_4b_poller_send_block( + Iso14443_4bPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer); + +/** + * @brief Send HALT command to the card. + * + * Must ONLY be used inside the callback function. + * + * Halts card and changes internal Iso14443_4aPoller state to Idle. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @return Iso14443_4bErrorNone on success, an error code on failure. + */ +Iso14443_4bError iso14443_4b_poller_halt(Iso14443_4bPoller* instance); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h index bd55c61882..fc9c2632b2 100644 --- a/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h +++ b/lib/nfc/protocols/iso14443_4b/iso14443_4b_poller_i.h @@ -42,13 +42,6 @@ struct Iso14443_4bPoller { const Iso14443_4bData* iso14443_4b_poller_get_data(Iso14443_4bPoller* instance); -Iso14443_4bError iso14443_4b_poller_halt(Iso14443_4bPoller* instance); - -Iso14443_4bError iso14443_4b_poller_send_block( - Iso14443_4bPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c index 9500e16539..cf27b1f3fd 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.c @@ -70,7 +70,7 @@ static NfcCommand iso15693_3_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { if(instance->state != Iso15693_3PollerStateActivated) { - Iso15693_3Error error = iso15693_3_poller_async_activate(instance, instance->data); + Iso15693_3Error error = iso15693_3_poller_activate(instance, instance->data); if(error == Iso15693_3ErrorNone) { instance->iso15693_3_event.type = Iso15693_3PollerEventTypeReady; instance->iso15693_3_event_data.error = error; @@ -105,7 +105,7 @@ static bool iso15693_3_poller_detect(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { uint8_t uid[ISO15693_3_UID_SIZE]; - Iso15693_3Error error = iso15693_3_poller_async_inventory(instance, uid); + Iso15693_3Error error = iso15693_3_poller_inventory(instance, uid); protocol_detected = (error == Iso15693_3ErrorNone); } diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h index 9d73242f1a..a187ceace1 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller.h @@ -8,22 +8,142 @@ extern "C" { #endif +/** + * @brief Iso15693_3Poller opaque type definition. + */ typedef struct Iso15693_3Poller Iso15693_3Poller; +/** + * @brief Enumeration of possible Iso15693_3 poller event types. + */ typedef enum { - Iso15693_3PollerEventTypeError, - Iso15693_3PollerEventTypeReady, + Iso15693_3PollerEventTypeError, /**< The card was activated by the poller. */ + Iso15693_3PollerEventTypeReady, /**< An error occured during activation procedure. */ } Iso15693_3PollerEventType; -typedef struct { - Iso15693_3Error error; +/** + * @brief Iso15693_3 poller event data. + */ +typedef union { + Iso15693_3Error error; /**< Error code indicating card activation fail reason. */ } Iso15693_3PollerEventData; +/** + * @brief Iso15693_3 poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - Iso15693_3PollerEventType type; - Iso15693_3PollerEventData* data; + Iso15693_3PollerEventType type; /**< Type of emmitted event. */ + Iso15693_3PollerEventData* data; /**< Pointer to event specific data. */ } Iso15693_3PollerEvent; +/** + * @brief Transmit and receive Iso15693_3 frames in poller mode. + * + * Must ONLY be used inside the callback function. + * + * The rx_buffer will be filled with any data received as a response to data + * sent from tx_buffer, with a timeout defined by the fwt parameter. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tx_buffer pointer to the buffer containing the data to be transmitted. + * @param[out] rx_buffer pointer to the buffer to be filled with received data. + * @param[in] fwt frame wait time (response timeout), in carrier cycles. + * @return Iso15693_3ErrorNone on success, an error code on failure. + */ +Iso15693_3Error iso15693_3_poller_send_frame( + Iso15693_3Poller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +/** + * @brief Perform activation procedure. + * + * Must ONLY be used inside the callback function. + * + * Perfoms the activation procedure as defined in Iso15693_3. The data + * field will be filled with Iso15693_3Data data on success. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the Iso15693_3 data structure to be filled. + * @return Iso15693_3ErrorNone on success, an error code on failure. + */ +Iso15693_3Error iso15693_3_poller_activate(Iso15693_3Poller* instance, Iso15693_3Data* data); + +/** + * @brief Send invertory command and parse response. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] uid pointer to the buffer to be filled with the UID. + * @return Iso15693_3ErrorNone on success, an error code on failure. + */ +Iso15693_3Error iso15693_3_poller_inventory(Iso15693_3Poller* instance, uint8_t* uid); + +/** + * @brief Send get system info command and parse response. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the Iso15693_3SystemInfo structure to be filled. + * @return Iso15693_3ErrorNone on success, an error code on failure. + */ +Iso15693_3Error + iso15693_3_poller_get_system_info(Iso15693_3Poller* instance, Iso15693_3SystemInfo* data); + +/** + * @brief Read Iso15693_3 block. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the buffer to be filled with the block data. + * @param[in] block_number block number to be read. + * @param[in] block_size size of the block to be read. + * @return Iso15693_3ErrorNone on success, an error code on failure. + */ +Iso15693_3Error iso15693_3_poller_read_block( + Iso15693_3Poller* instance, + uint8_t* data, + uint8_t block_number, + uint8_t block_size); + +/** + * @brief Read multiple Iso15693_3 blocks. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the buffer to be filled with the block data. + * @param[in] block_count number of blocks to be read. + * @param[in] block_size size of the blocks to be read. + * @return Iso15693_3ErrorNone on success, an error code on failure. + */ +Iso15693_3Error iso15693_3_poller_read_blocks( + Iso15693_3Poller* instance, + uint8_t* data, + uint16_t block_count, + uint8_t block_size); + +/** + * @brief Get Iso15693_3 block security status. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the buffer to be filled with the block security status. + * @param[in] block_count block security number to be read. + * @return Iso15693_3ErrorNone on success, an error code on failure. + */ +Iso15693_3Error iso15693_3_poller_get_blocks_security( + Iso15693_3Poller* instance, + uint8_t* data, + uint16_t block_count); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c index 8b8d8cee04..917f7dbb8e 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c @@ -36,7 +36,7 @@ static Iso15693_3Error iso15693_3_poller_prepare_trx(Iso15693_3Poller* instance) furi_assert(instance); if(instance->state == Iso15693_3PollerStateIdle) { - return iso15693_3_poller_async_activate(instance, NULL); + return iso15693_3_poller_activate(instance, NULL); } return Iso15693_3ErrorNone; @@ -80,8 +80,7 @@ static Iso15693_3Error iso15693_3_poller_frame_exchange( return ret; } -Iso15693_3Error - iso15693_3_poller_async_activate(Iso15693_3Poller* instance, Iso15693_3Data* data) { +Iso15693_3Error iso15693_3_poller_activate(Iso15693_3Poller* instance, Iso15693_3Data* data) { furi_assert(instance); furi_assert(instance->nfc); @@ -93,7 +92,7 @@ Iso15693_3Error instance->state = Iso15693_3PollerStateColResInProgress; // Inventory: Mandatory command - ret = iso15693_3_poller_async_inventory(instance, data->uid); + ret = iso15693_3_poller_inventory(instance, data->uid); if(ret != Iso15693_3ErrorNone) { instance->state = Iso15693_3PollerStateColResFailed; break; @@ -103,7 +102,7 @@ Iso15693_3Error // Get system info: Optional command Iso15693_3SystemInfo* system_info = &data->system_info; - ret = iso15693_3_poller_async_get_system_info(instance, system_info); + ret = iso15693_3_poller_get_system_info(instance, system_info); if(ret != Iso15693_3ErrorNone) { ret = iso15693_3_poller_filter_error(ret); break; @@ -111,7 +110,7 @@ Iso15693_3Error // Read blocks: Optional command simple_array_init(data->block_data, system_info->block_count * system_info->block_size); - ret = iso15693_3_poller_async_read_blocks( + ret = iso15693_3_poller_read_blocks( instance, simple_array_get_data(data->block_data), system_info->block_count, @@ -124,7 +123,7 @@ Iso15693_3Error // Get block security status: Optional command simple_array_init(data->block_security, system_info->block_count); - ret = iso15693_3_poller_async_get_blocks_security( + ret = iso15693_3_poller_get_blocks_security( instance, simple_array_get_data(data->block_security), system_info->block_count); if(ret != Iso15693_3ErrorNone) { ret = iso15693_3_poller_filter_error(ret); @@ -136,7 +135,7 @@ Iso15693_3Error return ret; } -Iso15693_3Error iso15693_3_poller_async_inventory(Iso15693_3Poller* instance, uint8_t* uid) { +Iso15693_3Error iso15693_3_poller_inventory(Iso15693_3Poller* instance, uint8_t* uid) { furi_assert(instance); furi_assert(instance->nfc); furi_assert(uid); @@ -165,9 +164,8 @@ Iso15693_3Error iso15693_3_poller_async_inventory(Iso15693_3Poller* instance, ui return ret; } -Iso15693_3Error iso15693_3_poller_async_get_system_info( - Iso15693_3Poller* instance, - Iso15693_3SystemInfo* data) { +Iso15693_3Error + iso15693_3_poller_get_system_info(Iso15693_3Poller* instance, Iso15693_3SystemInfo* data) { furi_assert(instance); furi_assert(data); @@ -193,7 +191,7 @@ Iso15693_3Error iso15693_3_poller_async_get_system_info( return ret; } -Iso15693_3Error iso15693_3_poller_async_read_block( +Iso15693_3Error iso15693_3_poller_read_block( Iso15693_3Poller* instance, uint8_t* data, uint8_t block_number, @@ -222,7 +220,7 @@ Iso15693_3Error iso15693_3_poller_async_read_block( return ret; } -Iso15693_3Error iso15693_3_poller_async_read_blocks( +Iso15693_3Error iso15693_3_poller_read_blocks( Iso15693_3Poller* instance, uint8_t* data, uint16_t block_count, @@ -235,14 +233,14 @@ Iso15693_3Error iso15693_3_poller_async_read_blocks( Iso15693_3Error ret = Iso15693_3ErrorNone; for(uint32_t i = 0; i < block_count; ++i) { - ret = iso15693_3_poller_async_read_block(instance, &data[block_size * i], i, block_size); + ret = iso15693_3_poller_read_block(instance, &data[block_size * i], i, block_size); if(ret != Iso15693_3ErrorNone) break; } return ret; } -Iso15693_3Error iso15693_3_poller_async_get_blocks_security( +Iso15693_3Error iso15693_3_poller_get_blocks_security( Iso15693_3Poller* instance, uint8_t* data, uint16_t block_count) { diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h index 154ee684c9..346d0d724c 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.h @@ -35,36 +35,6 @@ struct Iso15693_3Poller { const Iso15693_3Data* iso15693_3_poller_get_data(Iso15693_3Poller* instance); -Iso15693_3Error iso15693_3_poller_async_activate(Iso15693_3Poller* instance, Iso15693_3Data* data); - -Iso15693_3Error iso15693_3_poller_async_inventory(Iso15693_3Poller* instance, uint8_t* uid); - -Iso15693_3Error - iso15693_3_poller_async_get_system_info(Iso15693_3Poller* instance, Iso15693_3SystemInfo* data); - -Iso15693_3Error iso15693_3_poller_async_read_block( - Iso15693_3Poller* instance, - uint8_t* data, - uint8_t block_number, - uint8_t block_size); - -Iso15693_3Error iso15693_3_poller_async_read_blocks( - Iso15693_3Poller* instance, - uint8_t* data, - uint16_t block_count, - uint8_t block_size); - -Iso15693_3Error iso15693_3_poller_async_get_blocks_security( - Iso15693_3Poller* instance, - uint8_t* data, - uint16_t block_count); - -Iso15693_3Error iso15693_3_poller_send_frame( - Iso15693_3Poller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.c b/lib/nfc/protocols/mf_classic/mf_classic_poller.c index 3eba6ee569..dbc32a1b51 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.c @@ -85,7 +85,7 @@ NfcCommand mf_classic_poller_handler_detect_type(MfClassicPoller* instance) { iso14443_3a_copy( instance->data->iso14443_3a_data, iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); - MfClassicError error = mf_classic_async_get_nt(instance, 254, MfClassicKeyTypeA, NULL); + MfClassicError error = mf_classic_poller_get_nt(instance, 254, MfClassicKeyTypeA, NULL); if(error == MfClassicErrorNone) { instance->data->type = MfClassicType4k; instance->state = MfClassicPollerStateStart; @@ -95,7 +95,7 @@ NfcCommand mf_classic_poller_handler_detect_type(MfClassicPoller* instance) { instance->current_type_check = MfClassicType1k; } } else if(instance->current_type_check == MfClassicType1k) { - MfClassicError error = mf_classic_async_get_nt(instance, 62, MfClassicKeyTypeA, NULL); + MfClassicError error = mf_classic_poller_get_nt(instance, 62, MfClassicKeyTypeA, NULL); if(error == MfClassicErrorNone) { instance->data->type = MfClassicType1k; FURI_LOG_D(TAG, "1K detected"); @@ -234,7 +234,7 @@ NfcCommand mf_classic_poller_handler_read_block(MfClassicPoller* instance) { do { // Authenticate to sector - error = mf_classic_async_auth( + error = mf_classic_poller_auth( instance, write_ctx->current_block, auth_key, write_ctx->key_type_read, NULL); if(error != MfClassicErrorNone) { FURI_LOG_D(TAG, "Failed to auth to block %d", write_ctx->current_block); @@ -243,8 +243,8 @@ NfcCommand mf_classic_poller_handler_read_block(MfClassicPoller* instance) { } // Read block from tag - error = - mf_classic_async_read_block(instance, write_ctx->current_block, &write_ctx->tag_block); + error = mf_classic_poller_read_block( + instance, write_ctx->current_block, &write_ctx->tag_block); if(error != MfClassicErrorNone) { FURI_LOG_D(TAG, "Failed to read block %d", write_ctx->current_block); instance->state = MfClassicPollerStateFail; @@ -252,11 +252,11 @@ NfcCommand mf_classic_poller_handler_read_block(MfClassicPoller* instance) { } if(write_ctx->is_value_block) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); instance->state = MfClassicPollerStateWriteValueBlock; } else { if(write_ctx->need_halt_before_write) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); } instance->state = MfClassicPollerStateWriteBlock; } @@ -292,7 +292,7 @@ NfcCommand mf_classic_poller_handler_write_block(MfClassicPoller* instance) { // Reauth if necessary if(write_ctx->need_halt_before_write) { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( instance, write_ctx->current_block, auth_key, write_ctx->key_type_write, NULL); if(error != MfClassicErrorNone) { FURI_LOG_D( @@ -303,7 +303,7 @@ NfcCommand mf_classic_poller_handler_write_block(MfClassicPoller* instance) { } // Write block - error = mf_classic_async_write_block( + error = mf_classic_poller_write_block( instance, write_ctx->current_block, &instance->mfc_event_data.write_block_data.write_block); @@ -315,7 +315,7 @@ NfcCommand mf_classic_poller_handler_write_block(MfClassicPoller* instance) { } while(false); - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); write_ctx->current_block++; instance->state = MfClassicPollerStateCheckWriteConditions; @@ -403,18 +403,18 @@ NfcCommand mf_classic_poller_handler_write_value_block(MfClassicPoller* instance &write_ctx->sec_tr.key_b; MfClassicError error = - mf_classic_async_auth(instance, write_ctx->current_block, key, auth_key_type, NULL); + mf_classic_poller_auth(instance, write_ctx->current_block, key, auth_key_type, NULL); if(error != MfClassicErrorNone) break; - error = mf_classic_async_value_cmd(instance, write_ctx->current_block, value_cmd, diff); + error = mf_classic_poller_value_cmd(instance, write_ctx->current_block, value_cmd, diff); if(error != MfClassicErrorNone) break; - error = mf_classic_async_value_transfer(instance, write_ctx->current_block); + error = mf_classic_poller_value_transfer(instance, write_ctx->current_block); if(error != MfClassicErrorNone) break; } while(false); - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); write_ctx->is_value_block = false; write_ctx->current_block++; instance->state = MfClassicPollerStateCheckWriteConditions; @@ -462,7 +462,7 @@ NfcCommand mf_classic_poller_handler_request_read_sector_blocks(MfClassicPoller* sec_read_ctx->current_block, sec_read_ctx->key_type == MfClassicKeyTypeA ? 'A' : 'B', key); - error = mf_classic_async_auth( + error = mf_classic_poller_auth( instance, sec_read_ctx->current_block, &sec_read_ctx->key, @@ -481,7 +481,7 @@ NfcCommand mf_classic_poller_handler_request_read_sector_blocks(MfClassicPoller* FURI_LOG_D(TAG, "Reading block %d", sec_read_ctx->current_block); MfClassicBlock read_block = {}; - error = mf_classic_async_read_block(instance, sec_read_ctx->current_block, &read_block); + error = mf_classic_poller_read_block(instance, sec_read_ctx->current_block, &read_block); if(error == MfClassicErrorNone) { mf_classic_set_block_read(instance->data, sec_read_ctx->current_block, &read_block); if(sec_read_ctx->key_type == MfClassicKeyTypeA) { @@ -489,7 +489,7 @@ NfcCommand mf_classic_poller_handler_request_read_sector_blocks(MfClassicPoller* instance, sec_read_ctx->current_block, &read_block); } } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); sec_read_ctx->auth_passed = false; } } while(false); @@ -497,7 +497,7 @@ NfcCommand mf_classic_poller_handler_request_read_sector_blocks(MfClassicPoller* uint8_t sec_tr_num = mf_classic_get_sector_trailer_num_by_sector(sec_read_ctx->current_sector); sec_read_ctx->current_block++; if(sec_read_ctx->current_block > sec_tr_num) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); instance->state = MfClassicPollerStateRequestReadSector; } @@ -532,7 +532,7 @@ NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) { uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey)); FURI_LOG_D(TAG, "Auth to block %d with key A: %06llx", block, key); - MfClassicError error = mf_classic_async_auth( + MfClassicError error = mf_classic_poller_auth( instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeA, NULL); if(error == MfClassicErrorNone) { FURI_LOG_I(TAG, "Key A found"); @@ -545,7 +545,7 @@ NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) { dict_attack_ctx->auth_passed = true; instance->state = MfClassicPollerStateReadSector; } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); instance->state = MfClassicPollerStateAuthKeyB; } } @@ -570,7 +570,7 @@ NfcCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) { uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey)); FURI_LOG_D(TAG, "Auth to block %d with key B: %06llx", block, key); - MfClassicError error = mf_classic_async_auth( + MfClassicError error = mf_classic_poller_auth( instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeB, NULL); if(error == MfClassicErrorNone) { FURI_LOG_I(TAG, "Key B found"); @@ -584,7 +584,7 @@ NfcCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) { dict_attack_ctx->auth_passed = true; instance->state = MfClassicPollerStateReadSector; } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); instance->state = MfClassicPollerStateRequestKey; } } @@ -621,7 +621,7 @@ NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) { if(mf_classic_is_block_read(instance->data, block_num)) break; if(!dict_attack_ctx->auth_passed) { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( instance, block_num, &dict_attack_ctx->current_key, @@ -635,10 +635,10 @@ NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) { } FURI_LOG_D(TAG, "Reading block %d", block_num); - error = mf_classic_async_read_block(instance, block_num, &block); + error = mf_classic_poller_read_block(instance, block_num, &block); if(error != MfClassicErrorNone) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; FURI_LOG_D(TAG, "Failed to read block %d", block_num); } else { @@ -655,7 +655,7 @@ NfcCommand mf_classic_poller_handler_read_sector(MfClassicPoller* instance) { if(dict_attack_ctx->current_block > sec_tr_block_num) { mf_classic_poller_handle_data_update(instance); - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; if(dict_attack_ctx->current_sector == instance->sectors_total) { @@ -713,7 +713,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_auth_key_a(MfClassicPoller* insta uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey)); FURI_LOG_D(TAG, "Key attack auth to block %d with key A: %06llx", block, key); - MfClassicError error = mf_classic_async_auth( + MfClassicError error = mf_classic_poller_auth( instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeA, NULL); if(error == MfClassicErrorNone) { FURI_LOG_I(TAG, "Key A found"); @@ -726,7 +726,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_auth_key_a(MfClassicPoller* insta dict_attack_ctx->auth_passed = true; instance->state = MfClassicPollerStateKeyReuseReadSector; } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; instance->state = MfClassicPollerStateKeyReuseStart; } @@ -748,7 +748,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_auth_key_b(MfClassicPoller* insta uint64_t key = nfc_util_bytes2num(dict_attack_ctx->current_key.data, sizeof(MfClassicKey)); FURI_LOG_D(TAG, "Key attack auth to block %d with key B: %06llx", block, key); - MfClassicError error = mf_classic_async_auth( + MfClassicError error = mf_classic_poller_auth( instance, block, &dict_attack_ctx->current_key, MfClassicKeyTypeB, NULL); if(error == MfClassicErrorNone) { FURI_LOG_I(TAG, "Key B found"); @@ -762,7 +762,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_auth_key_b(MfClassicPoller* insta dict_attack_ctx->auth_passed = true; instance->state = MfClassicPollerStateKeyReuseReadSector; } else { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; instance->state = MfClassicPollerStateKeyReuseStart; } @@ -783,7 +783,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_read_sector(MfClassicPoller* inst if(mf_classic_is_block_read(instance->data, block_num)) break; if(!dict_attack_ctx->auth_passed) { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( instance, block_num, &dict_attack_ctx->current_key, @@ -796,10 +796,10 @@ NfcCommand mf_classic_poller_handler_key_reuse_read_sector(MfClassicPoller* inst } FURI_LOG_D(TAG, "Reading block %d", block_num); - error = mf_classic_async_read_block(instance, block_num, &block); + error = mf_classic_poller_read_block(instance, block_num, &block); if(error != MfClassicErrorNone) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; FURI_LOG_D(TAG, "Failed to read block %d", block_num); } else { @@ -814,7 +814,7 @@ NfcCommand mf_classic_poller_handler_key_reuse_read_sector(MfClassicPoller* inst mf_classic_get_sector_trailer_num_by_sector(dict_attack_ctx->reuse_key_sector); dict_attack_ctx->current_block++; if(dict_attack_ctx->current_block > sec_tr_block_num) { - mf_classic_async_halt(instance); + mf_classic_poller_halt(instance); dict_attack_ctx->auth_passed = false; mf_classic_poller_handle_data_update(instance); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index da1f3c3dce..f05a6800ad 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -7,103 +7,274 @@ extern "C" { #endif +/** + * @brief MfClassicPoller opaque type definition. + */ typedef struct MfClassicPoller MfClassicPoller; +/** + * @brief Enumeration of possible MfClassic poller event types. + */ typedef enum { - // Start event - MfClassicPollerEventTypeRequestMode, + MfClassicPollerEventTypeRequestMode, /**< Poller requests to fill the mode. */ - // Read with key cache events - MfClassicPollerEventTypeRequestReadSector, + MfClassicPollerEventTypeRequestReadSector, /**< Poller requests data to read sector. */ - // Write events - MfClassicPollerEventTypeRequestSectorTrailer, - MfClassicPollerEventTypeRequestWriteBlock, + MfClassicPollerEventTypeRequestSectorTrailer, /**< Poller requests sector trailer for writing block. */ + MfClassicPollerEventTypeRequestWriteBlock, /**< Poller requests data to write block. */ - // Dictionary attack events - MfClassicPollerEventTypeRequestKey, - MfClassicPollerEventTypeNextSector, - MfClassicPollerEventTypeDataUpdate, - MfClassicPollerEventTypeFoundKeyA, - MfClassicPollerEventTypeFoundKeyB, - MfClassicPollerEventTypeCardNotDetected, - MfClassicPollerEventTypeKeyAttackStart, - MfClassicPollerEventTypeKeyAttackStop, - MfClassicPollerEventTypeKeyAttackNextSector, + MfClassicPollerEventTypeRequestKey, /**< Poller requests key for sector authentication. */ + MfClassicPollerEventTypeNextSector, /**< Poller switches to next sector during dictionary attack. */ + MfClassicPollerEventTypeDataUpdate, /**< Poller updates data. */ + MfClassicPollerEventTypeFoundKeyA, /**< Poller found key A. */ + MfClassicPollerEventTypeFoundKeyB, /**< Poller found key B. */ + MfClassicPollerEventTypeKeyAttackStart, /**< Poller starts key attack. */ + MfClassicPollerEventTypeKeyAttackStop, /**< Poller stops key attack. */ + MfClassicPollerEventTypeKeyAttackNextSector, /**< Poller switches to next sector during key attack. */ - // Common events - MfClassicPollerEventTypeCardDetected, - MfClassicPollerEventTypeCardLost, - MfClassicPollerEventTypeSuccess, - MfClassicPollerEventTypeFail, + MfClassicPollerEventTypeCardDetected, /**< Poller detected card. */ + MfClassicPollerEventTypeCardLost, /**< Poller lost card. */ + MfClassicPollerEventTypeSuccess, /**< Poller succeeded. */ + MfClassicPollerEventTypeFail, /**< Poller failed. */ } MfClassicPollerEventType; +/** + * @brief MfClassic poller mode. + */ typedef enum { - MfClassicPollerModeRead, - MfClassicPollerModeWrite, - MfClassicPollerModeDictAttack, + MfClassicPollerModeRead, /**< Poller reading mode. */ + MfClassicPollerModeWrite, /**< Poller writing mode. */ + MfClassicPollerModeDictAttack, /**< Poller dictionary attack mode. */ } MfClassicPollerMode; +/** + * @brief MfClassic poller request mode event data. + * + * This instance of this structure must be filled on MfClassicPollerEventTypeRequestMode event. + */ typedef struct { - MfClassicPollerMode mode; - const MfClassicData* data; + MfClassicPollerMode mode; /**< Mode to be used by poller. */ + const MfClassicData* data; /**< Data to be used by poller. */ } MfClassicPollerEventDataRequestMode; +/** + * @brief MfClassic poller next sector event data. + * + * The instance of this structure is filled by poller and passed with + * MfClassicPollerEventTypeNextSector event. + */ typedef struct { - uint8_t current_sector; + uint8_t current_sector; /**< Current sector number. */ } MfClassicPollerEventDataDictAttackNextSector; +/** + * @brief MfClassic poller update event data. + * + * The instance of this structure is filled by poller and passed with + * MfClassicPollerEventTypeDataUpdate event. + */ typedef struct { - uint8_t sectors_read; - uint8_t keys_found; - uint8_t current_sector; + uint8_t sectors_read; /**< Number of sectors read. */ + uint8_t keys_found; /**< Number of keys found. */ + uint8_t current_sector; /**< Current sector number. */ } MfClassicPollerEventDataUpdate; +/** + * @brief MfClassic poller key request event data. + * + * The instance of this structure must be filled on MfClassicPollerEventTypeRequestKey event. + */ typedef struct { - MfClassicKey key; - bool key_provided; + MfClassicKey key; /**< Key to be used by poller. */ + bool key_provided; /**< Flag indicating if key is provided. */ } MfClassicPollerEventDataKeyRequest; +/** + * @brief MfClassic poller read sector request event data. + * + * The instance of this structure must be filled on MfClassicPollerEventTypeRequestReadSector event. + */ typedef struct { - uint8_t sector_num; - MfClassicKey key; - MfClassicKeyType key_type; - bool key_provided; + uint8_t sector_num; /**< Sector number to be read. */ + MfClassicKey key; /**< Key to be used by poller. */ + MfClassicKeyType key_type; /**< Key type to be used by poller. */ + bool key_provided; /**< Flag indicating if key is provided. */ } MfClassicPollerEventDataReadSectorRequest; +/** + * @brief MfClassic poller sector trailer request event data. + * + * The instance of this structure must be filled on MfClassicPollerEventTypeRequestSectorTrailer event. + */ typedef struct { - uint8_t sector_num; - MfClassicBlock sector_trailer; - bool sector_trailer_provided; + uint8_t sector_num; /**< Sector number to be read. */ + MfClassicBlock sector_trailer; /**< Sector trailer to be used by poller. */ + bool sector_trailer_provided; /**< Flag indicating if sector trailer is provided. */ } MfClassicPollerEventDataSectorTrailerRequest; +/** + * @brief MfClassic poller write block request event data. + * + * The instance of this structure must be filled on MfClassicPollerEventTypeRequestWriteBlock event. + */ typedef struct { - uint8_t block_num; - MfClassicBlock write_block; - bool write_block_provided; + uint8_t block_num; /**< Block number to be written. */ + MfClassicBlock write_block; /**< Block to be written. */ + bool write_block_provided; /**< Flag indicating if block is provided. */ } MfClassicPollerEventDataWriteBlockRequest; +/** + * @brief MfClassic poller key attack event data. + * + * The instance of this structure is filled by poller and passed with + * MfClassicPollerEventTypeKeyAttackNextSector event. + */ typedef struct { - uint8_t current_sector; + uint8_t current_sector; /**< Current sector number. */ } MfClassicPollerEventKeyAttackData; +/** + * @brief MfClassic poller event data. + */ typedef union { - MfClassicError error; - MfClassicPollerEventDataRequestMode poller_mode; - MfClassicPollerEventDataDictAttackNextSector next_sector_data; - MfClassicPollerEventDataKeyRequest key_request_data; - MfClassicPollerEventDataUpdate data_update; - MfClassicPollerEventDataReadSectorRequest read_sector_request_data; - MfClassicPollerEventKeyAttackData key_attack_data; - MfClassicPollerEventDataSectorTrailerRequest sec_tr_data; - MfClassicPollerEventDataWriteBlockRequest write_block_data; + MfClassicError error; /**< Error code on MfClassicPollerEventTypeFail event. */ + MfClassicPollerEventDataRequestMode poller_mode; /**< Poller mode context. */ + MfClassicPollerEventDataDictAttackNextSector next_sector_data; /**< Next sector context. */ + MfClassicPollerEventDataKeyRequest key_request_data; /**< Key request context. */ + MfClassicPollerEventDataUpdate data_update; /**< Data update context. */ + MfClassicPollerEventDataReadSectorRequest + read_sector_request_data; /**< Read sector request context. */ + MfClassicPollerEventKeyAttackData key_attack_data; /**< Key attack context. */ + MfClassicPollerEventDataSectorTrailerRequest sec_tr_data; /**< Sector trailer request context. */ + MfClassicPollerEventDataWriteBlockRequest write_block_data; /**< Write block request context. */ } MfClassicPollerEventData; +/** + * @brief MfClassic poller event. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - MfClassicPollerEventType type; - MfClassicPollerEventData* data; + MfClassicPollerEventType type; /**< Event type. */ + MfClassicPollerEventData* data; /**< Pointer to event specific data. */ } MfClassicPollerEvent; +/** + * @brief Collect tag nonce during authentication. + * + * Must ONLY be used inside the callback function. + * + * Starts authentication procedure and collects tag nonce. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number for authentication. + * @param[in] key_type key type to be used for authentication. + * @param[out] nt pointer to the MfClassicNt structure to be filled with nonce data. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_get_nt( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt); + +/** + * @brief Perform authentication. + * + * Must ONLY be used inside the callback function. + * + * Perform authentication as specified in Mf Classic protocol. Initialize crypto state for futher + * communication with the tag. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number for authentication. + * @param[in] key key to be used for authentication. + * @param[in] key_type key type to be used for authentication. + * @param[out] data pointer to MfClassicAuthContext structure to be filled with authentication data. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_auth( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data); + +/** + * @brief Halt the tag. + * + * Must ONLY be used inside the callback function. + * + * Halt the tag and reset crypto state of the poller. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_halt(MfClassicPoller* instance); + +/** + * @brief Read block from tag. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number to be read. + * @param[out] data pointer to the MfClassicBlock structure to be filled with block data. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_read_block( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicBlock* data); + +/** + * @brief Write block to tag. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number to be written. + * @param[in] data pointer to the MfClassicBlock structure to be written. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_write_block( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicBlock* data); + +/** + * @brief Perform value command on tag. + * + * Must ONLY be used inside the callback function. + * + * Perform Increment, Decrement or Restore command on tag. The result is stored in internal transfer + * block of the tag. Use mf_classic_poller_value_transfer to transfer the result to the tag. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number to be used for value command. + * @param[in] cmd value command to be performed. + * @param[in] data value to be used for value command. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_value_cmd( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicValueCommand cmd, + int32_t data); + +/** + * @brief Transfer internal transfer block to tag. + * + * Must ONLY be used inside the callback function. + * + * Transfer internal transfer block to tag. The block is filled by mf_classic_poller_value_cmd. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number to be used for value command. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_value_transfer(MfClassicPoller* instance, uint8_t block_num); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 7eab4fe3b5..4b071815ea 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -33,7 +33,7 @@ MfClassicError mf_classic_process_error(Iso14443_3aError error) { return ret; } -MfClassicError mf_classic_async_get_nt( +MfClassicError mf_classic_poller_get_nt( MfClassicPoller* instance, uint8_t block_num, MfClassicKeyType key_type, @@ -69,7 +69,7 @@ MfClassicError mf_classic_async_get_nt( return ret; } -MfClassicError mf_classic_async_auth( +MfClassicError mf_classic_poller_auth( MfClassicPoller* instance, uint8_t block_num, MfClassicKey* key, @@ -84,7 +84,7 @@ MfClassicError mf_classic_async_auth( iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); MfClassicNt nt = {}; - ret = mf_classic_async_get_nt(instance, block_num, key_type, &nt); + ret = mf_classic_poller_get_nt(instance, block_num, key_type, &nt); if(ret != MfClassicErrorNone) break; if(data) { data->nt = nt; @@ -130,7 +130,7 @@ MfClassicError mf_classic_async_auth( return ret; } -MfClassicError mf_classic_async_halt(MfClassicPoller* instance) { +MfClassicError mf_classic_poller_halt(MfClassicPoller* instance) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -158,7 +158,7 @@ MfClassicError mf_classic_async_halt(MfClassicPoller* instance) { return ret; } -MfClassicError mf_classic_async_read_block( +MfClassicError mf_classic_poller_read_block( MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data) { @@ -204,7 +204,7 @@ MfClassicError mf_classic_async_read_block( return ret; } -MfClassicError mf_classic_async_write_block( +MfClassicError mf_classic_poller_write_block( MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data) { @@ -275,7 +275,7 @@ MfClassicError mf_classic_async_write_block( return ret; } -MfClassicError mf_classic_async_value_cmd( +MfClassicError mf_classic_poller_value_cmd( MfClassicPoller* instance, uint8_t block_num, MfClassicValueCommand cmd, @@ -345,7 +345,7 @@ MfClassicError mf_classic_async_value_cmd( return ret; } -MfClassicError mf_classic_async_value_transfer(MfClassicPoller* instance, uint8_t block_num) { +MfClassicError mf_classic_poller_value_transfer(MfClassicPoller* instance, uint8_t block_num) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h index c6f4ccf7f0..0be42196f1 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.h @@ -169,37 +169,6 @@ MfClassicPoller* mf_classic_poller_alloc(Iso14443_3aPoller* iso14443_3a_poller); void mf_classic_poller_free(MfClassicPoller* instance); -MfClassicError mf_classic_async_get_nt( - MfClassicPoller* instance, - uint8_t block_num, - MfClassicKeyType key_type, - MfClassicNt* nt); - -MfClassicError mf_classic_async_auth( - MfClassicPoller* instance, - uint8_t block_num, - MfClassicKey* key, - MfClassicKeyType key_type, - MfClassicAuthContext* data); - -MfClassicError mf_classic_async_halt(MfClassicPoller* instance); - -MfClassicError - mf_classic_async_read_block(MfClassicPoller* instance, uint8_t block_num, MfClassicBlock* data); - -MfClassicError mf_classic_async_write_block( - MfClassicPoller* instance, - uint8_t block_num, - MfClassicBlock* data); - -MfClassicError mf_classic_async_value_cmd( - MfClassicPoller* instance, - uint8_t block_num, - MfClassicValueCommand cmd, - int32_t data); - -MfClassicError mf_classic_async_value_transfer(MfClassicPoller* instance, uint8_t block_num); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync.c similarity index 88% rename from lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c rename to lib/nfc/protocols/mf_classic/mf_classic_poller_sync.c index 8b9fb69f16..69954452aa 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync.c @@ -1,3 +1,4 @@ +#include "mf_classic_poller_sync.h" #include "mf_classic_poller_i.h" #include @@ -32,7 +33,7 @@ typedef MfClassicError ( static MfClassicError mf_classic_poller_collect_nt_handler( MfClassicPoller* poller, MfClassicPollerContextData* data) { - return mf_classic_async_get_nt( + return mf_classic_poller_get_nt( poller, data->collect_nt_context.block, data->collect_nt_context.key_type, @@ -41,7 +42,7 @@ static MfClassicError mf_classic_poller_collect_nt_handler( static MfClassicError mf_classic_poller_auth_handler(MfClassicPoller* poller, MfClassicPollerContextData* data) { - return mf_classic_async_auth( + return mf_classic_poller_auth( poller, data->auth_context.block_num, &data->auth_context.key, @@ -55,7 +56,7 @@ static MfClassicError mf_classic_poller_read_block_handler( MfClassicError error = MfClassicErrorNone; do { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( poller, data->read_block_context.block_num, &data->read_block_context.key, @@ -63,11 +64,11 @@ static MfClassicError mf_classic_poller_read_block_handler( NULL); if(error != MfClassicErrorNone) break; - error = mf_classic_async_read_block( + error = mf_classic_poller_read_block( poller, data->read_block_context.block_num, &data->read_block_context.block); if(error != MfClassicErrorNone) break; - error = mf_classic_async_halt(poller); + error = mf_classic_poller_halt(poller); if(error != MfClassicErrorNone) break; } while(false); @@ -81,7 +82,7 @@ static MfClassicError mf_classic_poller_write_block_handler( MfClassicError error = MfClassicErrorNone; do { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( poller, data->read_block_context.block_num, &data->read_block_context.key, @@ -89,11 +90,11 @@ static MfClassicError mf_classic_poller_write_block_handler( NULL); if(error != MfClassicErrorNone) break; - error = mf_classic_async_write_block( + error = mf_classic_poller_write_block( poller, data->write_block_context.block_num, &data->write_block_context.block); if(error != MfClassicErrorNone) break; - error = mf_classic_async_halt(poller); + error = mf_classic_poller_halt(poller); if(error != MfClassicErrorNone) break; } while(false); @@ -107,7 +108,7 @@ static MfClassicError mf_classic_poller_read_value_handler( MfClassicError error = MfClassicErrorNone; do { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( poller, data->read_value_context.block_num, &data->read_value_context.key, @@ -116,7 +117,7 @@ static MfClassicError mf_classic_poller_read_value_handler( if(error != MfClassicErrorNone) break; MfClassicBlock block = {}; - error = mf_classic_async_read_block(poller, data->read_value_context.block_num, &block); + error = mf_classic_poller_read_block(poller, data->read_value_context.block_num, &block); if(error != MfClassicErrorNone) break; if(!mf_classic_block_to_value(&block, &data->read_value_context.value, NULL)) { @@ -124,7 +125,7 @@ static MfClassicError mf_classic_poller_read_value_handler( break; } - error = mf_classic_async_halt(poller); + error = mf_classic_poller_halt(poller); if(error != MfClassicErrorNone) break; } while(false); @@ -138,7 +139,7 @@ static MfClassicError mf_classic_poller_change_value_handler( MfClassicError error = MfClassicErrorNone; do { - error = mf_classic_async_auth( + error = mf_classic_poller_auth( poller, data->change_value_context.block_num, &data->change_value_context.key, @@ -146,21 +147,21 @@ static MfClassicError mf_classic_poller_change_value_handler( NULL); if(error != MfClassicErrorNone) break; - error = mf_classic_async_value_cmd( + error = mf_classic_poller_value_cmd( poller, data->change_value_context.block_num, data->change_value_context.value_cmd, data->change_value_context.data); if(error != MfClassicErrorNone) break; - error = mf_classic_async_value_transfer(poller, data->change_value_context.block_num); + error = mf_classic_poller_value_transfer(poller, data->change_value_context.block_num); if(error != MfClassicErrorNone) break; MfClassicBlock block = {}; - error = mf_classic_async_read_block(poller, data->change_value_context.block_num, &block); + error = mf_classic_poller_read_block(poller, data->change_value_context.block_num, &block); if(error != MfClassicErrorNone) break; - error = mf_classic_async_halt(poller); + error = mf_classic_poller_halt(poller); if(error != MfClassicErrorNone) break; if(!mf_classic_block_to_value(&block, &data->change_value_context.new_value, NULL)) { @@ -182,16 +183,14 @@ static const MfClassicPollerCmdHandler mf_classic_poller_cmd_handlers[MfClassicP [MfClassicPollerCmdTypeChangeValue] = mf_classic_poller_change_value_handler, }; -static NfcCommand mf_classic_poller_cmd_callback(NfcGenericEvent event, void* context) { - furi_assert(event.instance); - furi_assert(event.protocol == NfcProtocolIso14443_3a); - furi_assert(event.event_data); +static NfcCommand mf_classic_poller_cmd_callback(NfcGenericEventEx event, void* context) { + furi_assert(event.poller); + furi_assert(event.parent_event_data); furi_assert(context); MfClassicPollerContext* poller_context = context; - Iso14443_3aPollerEvent* iso14443_3a_event = event.event_data; - Iso14443_3aPoller* iso14443_3a_poller = event.instance; - MfClassicPoller* mfc_poller = mf_classic_poller_alloc(iso14443_3a_poller); + Iso14443_3aPollerEvent* iso14443_3a_event = event.parent_event_data; + MfClassicPoller* mfc_poller = event.poller; if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { poller_context->error = mf_classic_poller_cmd_handlers[poller_context->cmd_type]( @@ -202,8 +201,6 @@ static NfcCommand mf_classic_poller_cmd_callback(NfcGenericEvent event, void* co furi_thread_flags_set(poller_context->thread_id, MF_CLASSIC_POLLER_COMPLETE_EVENT); - mf_classic_poller_free(mfc_poller); - return NfcCommandStop; } @@ -212,8 +209,8 @@ static MfClassicError mf_classic_poller_cmd_execute(Nfc* nfc, MfClassicPollerCon poller_ctx->thread_id = furi_thread_get_current_id(); - NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a); - nfc_poller_start(poller, mf_classic_poller_cmd_callback, poller_ctx); + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfClassic); + nfc_poller_start_ex(poller, mf_classic_poller_cmd_callback, poller_ctx); furi_thread_flags_wait(MF_CLASSIC_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(MF_CLASSIC_POLLER_COMPLETE_EVENT); @@ -223,7 +220,7 @@ static MfClassicError mf_classic_poller_cmd_execute(Nfc* nfc, MfClassicPollerCon return poller_ctx->error; } -MfClassicError mf_classic_poller_collect_nt( +MfClassicError mf_classic_poller_sync_collect_nt( Nfc* nfc, uint8_t block_num, MfClassicKeyType key_type, @@ -247,7 +244,7 @@ MfClassicError mf_classic_poller_collect_nt( return error; } -MfClassicError mf_classic_poller_auth( +MfClassicError mf_classic_poller_sync_auth( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -274,7 +271,7 @@ MfClassicError mf_classic_poller_auth( return error; } -MfClassicError mf_classic_poller_read_block( +MfClassicError mf_classic_poller_sync_read_block( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -300,7 +297,7 @@ MfClassicError mf_classic_poller_read_block( return error; } -MfClassicError mf_classic_poller_write_block( +MfClassicError mf_classic_poller_sync_write_block( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -323,7 +320,7 @@ MfClassicError mf_classic_poller_write_block( return error; } -MfClassicError mf_classic_poller_read_value( +MfClassicError mf_classic_poller_sync_read_value( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -349,7 +346,7 @@ MfClassicError mf_classic_poller_read_value( return error; } -MfClassicError mf_classic_poller_change_value( +MfClassicError mf_classic_poller_sync_change_value( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -461,7 +458,7 @@ NfcCommand mf_classic_poller_read_callback(NfcGenericEvent event, void* context) } MfClassicError - mf_classic_poller_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data) { + mf_classic_poller_sync_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data) { furi_assert(nfc); furi_assert(keys); furi_assert(data); @@ -498,7 +495,7 @@ MfClassicError return error; } -MfClassicError mf_classic_poller_detect_type(Nfc* nfc, MfClassicType* type) { +MfClassicError mf_classic_poller_sync_detect_type(Nfc* nfc, MfClassicType* type) { furi_assert(nfc); furi_assert(type); @@ -512,7 +509,7 @@ MfClassicError mf_classic_poller_detect_type(Nfc* nfc, MfClassicType* type) { size_t i = 0; for(i = 0; i < COUNT_OF(mf_classic_verify_block); i++) { - error = mf_classic_poller_collect_nt( + error = mf_classic_poller_sync_collect_nt( nfc, mf_classic_verify_block[MfClassicTypeNum - i - 1], MfClassicKeyTypeA, NULL); if(error == MfClassicErrorNone) { *type = MfClassicTypeNum - i - 1; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h similarity index 64% rename from lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h rename to lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h index 11db291b80..d384e46e4e 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h @@ -7,41 +7,41 @@ extern "C" { #endif -MfClassicError mf_classic_poller_collect_nt( +MfClassicError mf_classic_poller_sync_collect_nt( Nfc* nfc, uint8_t block_num, MfClassicKeyType key_type, MfClassicNt* nt); -MfClassicError mf_classic_poller_auth( +MfClassicError mf_classic_poller_sync_auth( Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, MfClassicAuthContext* data); -MfClassicError mf_classic_poller_read_block( +MfClassicError mf_classic_poller_sync_read_block( Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, MfClassicBlock* data); -MfClassicError mf_classic_poller_write_block( +MfClassicError mf_classic_poller_sync_write_block( Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, MfClassicBlock* data); -MfClassicError mf_classic_poller_read_value( +MfClassicError mf_classic_poller_sync_read_value( Nfc* nfc, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, int32_t* value); -MfClassicError mf_classic_poller_change_value( +MfClassicError mf_classic_poller_sync_change_value( Nfc* nfc, uint8_t block_num, MfClassicKey* key, @@ -49,10 +49,10 @@ MfClassicError mf_classic_poller_change_value( int32_t data, int32_t* new_value); -MfClassicError mf_classic_poller_detect_type(Nfc* nfc, MfClassicType* type); +MfClassicError mf_classic_poller_sync_detect_type(Nfc* nfc, MfClassicType* type); MfClassicError - mf_classic_poller_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data); + mf_classic_poller_sync_read(Nfc* nfc, const MfClassicDeviceKeys* keys, MfClassicData* data); #ifdef __cplusplus } diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index 11db021d57..5af033d4ca 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -61,7 +61,7 @@ static NfcCommand mf_desfire_poller_handler_idle(MfDesfirePoller* instance) { } static NfcCommand mf_desfire_poller_handler_read_version(MfDesfirePoller* instance) { - instance->error = mf_desfire_poller_async_read_version(instance, &instance->data->version); + instance->error = mf_desfire_poller_read_version(instance, &instance->data->version); if(instance->error == MfDesfireErrorNone) { FURI_LOG_D(TAG, "Read version success"); instance->state = MfDesfirePollerStateReadFreeMemory; @@ -75,8 +75,7 @@ static NfcCommand mf_desfire_poller_handler_read_version(MfDesfirePoller* instan } static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* instance) { - instance->error = - mf_desfire_poller_async_read_free_memory(instance, &instance->data->free_memory); + instance->error = mf_desfire_poller_read_free_memory(instance, &instance->data->free_memory); if(instance->error == MfDesfireErrorNone) { FURI_LOG_D(TAG, "Read free memory success"); instance->state = MfDesfirePollerStateReadMasterKeySettings; @@ -91,7 +90,7 @@ static NfcCommand mf_desfire_poller_handler_read_free_memory(MfDesfirePoller* in static NfcCommand mf_desfire_poller_handler_read_master_key_settings(MfDesfirePoller* instance) { instance->error = - mf_desfire_poller_async_read_key_settings(instance, &instance->data->master_key_settings); + mf_desfire_poller_read_key_settings(instance, &instance->data->master_key_settings); if(instance->error == MfDesfireErrorNone) { FURI_LOG_D(TAG, "Read master key settings success"); instance->state = MfDesfirePollerStateReadMasterKeyVersion; @@ -105,7 +104,7 @@ static NfcCommand mf_desfire_poller_handler_read_master_key_settings(MfDesfirePo } static NfcCommand mf_desfire_poller_handler_read_master_key_version(MfDesfirePoller* instance) { - instance->error = mf_desfire_poller_async_read_key_versions( + instance->error = mf_desfire_poller_read_key_versions( instance, instance->data->master_key_versions, instance->data->master_key_settings.max_keys); @@ -123,7 +122,7 @@ static NfcCommand mf_desfire_poller_handler_read_master_key_version(MfDesfirePol static NfcCommand mf_desfire_poller_handler_read_application_ids(MfDesfirePoller* instance) { instance->error = - mf_desfire_poller_async_read_application_ids(instance, instance->data->application_ids); + mf_desfire_poller_read_application_ids(instance, instance->data->application_ids); if(instance->error == MfDesfireErrorNone) { FURI_LOG_D(TAG, "Read application ids success"); instance->state = MfDesfirePollerStateReadApplications; @@ -137,7 +136,7 @@ static NfcCommand mf_desfire_poller_handler_read_application_ids(MfDesfirePoller } static NfcCommand mf_desfire_poller_handler_read_applications(MfDesfirePoller* instance) { - instance->error = mf_desfire_poller_async_read_applications( + instance->error = mf_desfire_poller_read_applications( instance, instance->data->application_ids, instance->data->applications); if(instance->error == MfDesfireErrorNone) { FURI_LOG_D(TAG, "Read applications success"); @@ -227,7 +226,7 @@ static bool mf_desfire_poller_detect(NfcGenericEvent event, void* context) { if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { MfDesfireVersion version = {}; - const MfDesfireError error = mf_desfire_poller_async_read_version(instance, &version); + const MfDesfireError error = mf_desfire_poller_read_version(instance, &version); protocol_detected = (error == MfDesfireErrorNone); } diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h index 360b0508ff..6ef2f3f68d 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.h @@ -8,24 +8,267 @@ extern "C" { #endif +/** + * @brief MfDesfirePoller opaque type definition. + */ typedef struct MfDesfirePoller MfDesfirePoller; +/** + * @brief Enumeration of possible MfDesfire poller event types. + */ typedef enum { - MfDesfirePollerEventTypeReadSuccess, - MfDesfirePollerEventTypeReadFailed, + MfDesfirePollerEventTypeReadSuccess, /**< Card was read successfully. */ + MfDesfirePollerEventTypeReadFailed, /**< Poller failed to read card. */ } MfDesfirePollerEventType; -typedef struct { - union { - MfDesfireError error; - }; +/** + * @brief MfDesfire poller event data. + */ +typedef union { + MfDesfireError error; /**< Error code indicating card reading fail reason. */ } MfDesfirePollerEventData; +/** + * @brief MfDesfire poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - MfDesfirePollerEventType type; - MfDesfirePollerEventData* data; + MfDesfirePollerEventType type; /**< Type of emmitted event. */ + MfDesfirePollerEventData* data; /**< Pointer to event specific data. */ } MfDesfirePollerEvent; +/** + * @brief Transmit and receive MfDesfire chunks in poller mode. + * + * Must ONLY be used inside the callback function. + * + * The rx_buffer will be filled with any data received as a response to data + * sent from tx_buffer, with a timeout defined by the fwt parameter. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tx_buffer pointer to the buffer containing the data to be transmitted. + * @param[out] rx_buffer pointer to the buffer to be filled with received data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_send_chunks( + MfDesfirePoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer); + +/** + * @brief Read MfDesfire card version. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the MfDesfireVersion structure to be filled with version data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_version(MfDesfirePoller* instance, MfDesfireVersion* data); + +/** + * @brief Read free memory available on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the MfDesfireFreeMemory structure to be filled with free memory data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError + mf_desfire_poller_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data); + +/** + * @brief Read key settings on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the MfDesfireKeySettings structure to be filled with key settings data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError + mf_desfire_poller_read_key_settings(MfDesfirePoller* instance, MfDesfireKeySettings* data); + +/** + * @brief Read key versions on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the SimpleArray structure to be filled with key versions data. + * @param[in] count number of key versions to read. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_key_versions( + MfDesfirePoller* instance, + SimpleArray* data, + uint32_t count); + +/** + * @brief Read applications IDs on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the SimpleArray structure to be filled with application ids data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError + mf_desfire_poller_read_application_ids(MfDesfirePoller* instance, SimpleArray* data); + +/** + * @brief Select application on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] id pointer to the MfDesfireApplicationId structure with application id to select. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_select_application( + MfDesfirePoller* instance, + const MfDesfireApplicationId* id); + +/** + * @brief Read file IDs for selected application on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the SimpleArray structure to be filled with file ids data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_file_ids(MfDesfirePoller* instance, SimpleArray* data); + +/** + * @brief Read file settings on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] id file id to read settings for. + * @param[out] data pointer to the MfDesfireFileSettings structure to be filled with file settings data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_file_settings( + MfDesfirePoller* instance, + MfDesfireFileId id, + MfDesfireFileSettings* data); + +/** + * @brief Read multiple file settings on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] file_ids pointer to the SimpleArray structure array with file ids to read settings for. + * @param[out] data pointer to the SimpleArray structure array to be filled with file settings data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_file_settings_multi( + MfDesfirePoller* instance, + const SimpleArray* file_ids, + SimpleArray* data); + +/** + * @brief Read file data on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] id file id to read data from. + * @param[in] offset offset in bytes to start reading from. + * @param[in] size number of bytes to read. + * @param[out] data pointer to the MfDesfireFileData structure to be filled with file data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_file_data( + MfDesfirePoller* instance, + MfDesfireFileId id, + uint32_t offset, + size_t size, + MfDesfireFileData* data); + +/** + * @brief Read file value on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] id file id to read value from. + * @param[out] data pointer to the MfDesfireFileData structure to be filled with file value. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_file_value( + MfDesfirePoller* instance, + MfDesfireFileId id, + MfDesfireFileData* data); + +/** + * @brief Read file records on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] id file id to read data from. + * @param[in] offset offset in bytes to start reading from. + * @param[in] size number of bytes to read. + * @param[out] data pointer to the MfDesfireFileData structure to be filled with file records data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_file_records( + MfDesfirePoller* instance, + MfDesfireFileId id, + uint32_t offset, + size_t size, + MfDesfireFileData* data); + +/** + * @brief Read data from multiple files on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] file_ids pointer to the SimpleArray structure array with files ids to read data from. + * @param[in] file_settings pointer to the SimpleArray structure array with files settings to read data from. + * @param[out] data pointer to the SimpleArray structure array to be filled with files data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_file_data_multi( + MfDesfirePoller* instance, + const SimpleArray* file_ids, + const SimpleArray* file_settings, + SimpleArray* data); + +/** + * @brief Read application data for selected application on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the MfDesfireApplication structure to be filled with application data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError + mf_desfire_poller_read_application(MfDesfirePoller* instance, MfDesfireApplication* data); + +/** + * @brief Read multiple applications data on MfDesfire card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] app_ids pointer to the SimpleArray structure array with application ids to read data from. + * @param[out] data pointer to the SimpleArray structure array to be filled with applications data. + * @return MfDesfireErrorNone on success, an error code on failure. + */ +MfDesfireError mf_desfire_poller_read_applications( + MfDesfirePoller* instance, + const SimpleArray* app_ids, + SimpleArray* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c index 38ae2f466d..0b2d841382 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.c @@ -74,8 +74,7 @@ MfDesfireError mf_desfire_send_chunks( return error; } -MfDesfireError - mf_desfire_poller_async_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) { +MfDesfireError mf_desfire_poller_read_version(MfDesfirePoller* instance, MfDesfireVersion* data) { furi_assert(instance); bit_buffer_reset(instance->input_buffer); @@ -97,7 +96,7 @@ MfDesfireError } MfDesfireError - mf_desfire_poller_async_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data) { + mf_desfire_poller_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data) { furi_assert(instance); bit_buffer_reset(instance->input_buffer); @@ -118,9 +117,8 @@ MfDesfireError return error; } -MfDesfireError mf_desfire_poller_async_read_key_settings( - MfDesfirePoller* instance, - MfDesfireKeySettings* data) { +MfDesfireError + mf_desfire_poller_read_key_settings(MfDesfirePoller* instance, MfDesfireKeySettings* data) { furi_assert(instance); bit_buffer_reset(instance->input_buffer); @@ -141,7 +139,7 @@ MfDesfireError mf_desfire_poller_async_read_key_settings( return error; } -MfDesfireError mf_desfire_poller_async_read_key_versions( +MfDesfireError mf_desfire_poller_read_key_versions( MfDesfirePoller* instance, SimpleArray* data, uint32_t count) { @@ -172,7 +170,7 @@ MfDesfireError mf_desfire_poller_async_read_key_versions( } MfDesfireError - mf_desfire_poller_async_read_application_ids(MfDesfirePoller* instance, SimpleArray* data) { + mf_desfire_poller_read_application_ids(MfDesfirePoller* instance, SimpleArray* data) { furi_assert(instance); bit_buffer_reset(instance->input_buffer); @@ -203,7 +201,7 @@ MfDesfireError return error; } -MfDesfireError mf_desfire_poller_async_select_application( +MfDesfireError mf_desfire_poller_select_application( MfDesfirePoller* instance, const MfDesfireApplicationId* id) { furi_assert(instance); @@ -219,8 +217,7 @@ MfDesfireError mf_desfire_poller_async_select_application( return error; } -MfDesfireError - mf_desfire_poller_async_read_file_ids(MfDesfirePoller* instance, SimpleArray* data) { +MfDesfireError mf_desfire_poller_read_file_ids(MfDesfirePoller* instance, SimpleArray* data) { furi_assert(instance); bit_buffer_reset(instance->input_buffer); @@ -250,7 +247,7 @@ MfDesfireError return error; } -MfDesfireError mf_desfire_poller_async_read_file_settings( +MfDesfireError mf_desfire_poller_read_file_settings( MfDesfirePoller* instance, MfDesfireFileId id, MfDesfireFileSettings* data) { @@ -275,7 +272,7 @@ MfDesfireError mf_desfire_poller_async_read_file_settings( return error; } -MfDesfireError mf_desfire_poller_async_read_file_settings_multi( +MfDesfireError mf_desfire_poller_read_file_settings_multi( MfDesfirePoller* instance, const SimpleArray* file_ids, SimpleArray* data) { @@ -290,15 +287,14 @@ MfDesfireError mf_desfire_poller_async_read_file_settings_multi( for(uint32_t i = 0; i < file_id_count; ++i) { const MfDesfireFileId file_id = *(const MfDesfireFileId*)simple_array_cget(file_ids, i); - error = mf_desfire_poller_async_read_file_settings( - instance, file_id, simple_array_get(data, i)); + error = mf_desfire_poller_read_file_settings(instance, file_id, simple_array_get(data, i)); if(error != MfDesfireErrorNone) break; } return error; } -MfDesfireError mf_desfire_poller_async_read_file_data( +MfDesfireError mf_desfire_poller_read_file_data( MfDesfirePoller* instance, MfDesfireFileId id, uint32_t offset, @@ -327,7 +323,7 @@ MfDesfireError mf_desfire_poller_async_read_file_data( return error; } -MfDesfireError mf_desfire_poller_async_read_file_value( +MfDesfireError mf_desfire_poller_read_file_value( MfDesfirePoller* instance, MfDesfireFileId id, MfDesfireFileData* data) { @@ -352,7 +348,7 @@ MfDesfireError mf_desfire_poller_async_read_file_value( return error; } -MfDesfireError mf_desfire_poller_async_read_file_records( +MfDesfireError mf_desfire_poller_read_file_records( MfDesfirePoller* instance, MfDesfireFileId id, uint32_t offset, @@ -381,7 +377,7 @@ MfDesfireError mf_desfire_poller_async_read_file_records( return error; } -MfDesfireError mf_desfire_poller_async_read_file_data_multi( +MfDesfireError mf_desfire_poller_read_file_data_multi( MfDesfirePoller* instance, const SimpleArray* file_ids, const SimpleArray* file_settings, @@ -404,14 +400,14 @@ MfDesfireError mf_desfire_poller_async_read_file_data_multi( MfDesfireFileData* file_data = simple_array_get(data, i); if(file_type == MfDesfireFileTypeStandard || file_type == MfDesfireFileTypeBackup) { - error = mf_desfire_poller_async_read_file_data( + error = mf_desfire_poller_read_file_data( instance, file_id, 0, file_settings_cur->data.size, file_data); } else if(file_type == MfDesfireFileTypeValue) { - error = mf_desfire_poller_async_read_file_value(instance, file_id, file_data); + error = mf_desfire_poller_read_file_value(instance, file_id, file_data); } else if( file_type == MfDesfireFileTypeLinearRecord || file_type == MfDesfireFileTypeCyclicRecord) { - error = mf_desfire_poller_async_read_file_records( + error = mf_desfire_poller_read_file_records( instance, file_id, 0, file_settings_cur->data.size, file_data); } @@ -421,30 +417,29 @@ MfDesfireError mf_desfire_poller_async_read_file_data_multi( return error; } -MfDesfireError mf_desfire_poller_async_read_application( - MfDesfirePoller* instance, - MfDesfireApplication* data) { +MfDesfireError + mf_desfire_poller_read_application(MfDesfirePoller* instance, MfDesfireApplication* data) { furi_assert(instance); furi_assert(data); MfDesfireError error; do { - error = mf_desfire_poller_async_read_key_settings(instance, &data->key_settings); + error = mf_desfire_poller_read_key_settings(instance, &data->key_settings); if(error != MfDesfireErrorNone) break; - error = mf_desfire_poller_async_read_key_versions( + error = mf_desfire_poller_read_key_versions( instance, data->key_versions, data->key_settings.max_keys); if(error != MfDesfireErrorNone) break; - error = mf_desfire_poller_async_read_file_ids(instance, data->file_ids); + error = mf_desfire_poller_read_file_ids(instance, data->file_ids); if(error != MfDesfireErrorNone) break; - error = mf_desfire_poller_async_read_file_settings_multi( + error = mf_desfire_poller_read_file_settings_multi( instance, data->file_ids, data->file_settings); if(error != MfDesfireErrorNone) break; - error = mf_desfire_poller_async_read_file_data_multi( + error = mf_desfire_poller_read_file_data_multi( instance, data->file_ids, data->file_settings, data->file_data); if(error != MfDesfireErrorNone) break; @@ -453,7 +448,7 @@ MfDesfireError mf_desfire_poller_async_read_application( return error; } -MfDesfireError mf_desfire_poller_async_read_applications( +MfDesfireError mf_desfire_poller_read_applications( MfDesfirePoller* instance, const SimpleArray* app_ids, SimpleArray* data) { @@ -468,12 +463,11 @@ MfDesfireError mf_desfire_poller_async_read_applications( for(uint32_t i = 0; i < app_id_count; ++i) { do { - error = mf_desfire_poller_async_select_application( - instance, simple_array_cget(app_ids, i)); + error = mf_desfire_poller_select_application(instance, simple_array_cget(app_ids, i)); if(error != MfDesfireErrorNone) break; MfDesfireApplication* current_app = simple_array_get(data, i); - error = mf_desfire_poller_async_read_application(instance, current_app); + error = mf_desfire_poller_read_application(instance, current_app); } while(false); } diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h index abc48d0eb5..1c80af36fb 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller_i.h @@ -49,78 +49,6 @@ MfDesfireError mf_desfire_process_error(Iso14443_4aError error); const MfDesfireData* mf_desfire_poller_get_data(MfDesfirePoller* instance); -MfDesfireError mf_desfire_send_chunks( - MfDesfirePoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer); - -MfDesfireError - mf_desfire_poller_async_read_version(MfDesfirePoller* instance, MfDesfireVersion* data); - -MfDesfireError - mf_desfire_poller_async_read_free_memory(MfDesfirePoller* instance, MfDesfireFreeMemory* data); - -MfDesfireError mf_desfire_poller_async_read_key_settings( - MfDesfirePoller* instance, - MfDesfireKeySettings* data); - -MfDesfireError mf_desfire_poller_async_read_key_versions( - MfDesfirePoller* instance, - SimpleArray* data, - uint32_t count); - -MfDesfireError - mf_desfire_poller_async_read_application_ids(MfDesfirePoller* instance, SimpleArray* data); - -MfDesfireError mf_desfire_poller_async_select_application( - MfDesfirePoller* instance, - const MfDesfireApplicationId* id); - -MfDesfireError mf_desfire_poller_async_read_file_ids(MfDesfirePoller* instance, SimpleArray* data); - -MfDesfireError mf_desfire_poller_async_read_file_settings( - MfDesfirePoller* instance, - MfDesfireFileId id, - MfDesfireFileSettings* data); - -MfDesfireError mf_desfire_poller_async_read_file_settings_multi( - MfDesfirePoller* instance, - const SimpleArray* file_ids, - SimpleArray* data); - -MfDesfireError mf_desfire_poller_async_read_file_data( - MfDesfirePoller* instance, - MfDesfireFileId id, - uint32_t offset, - size_t size, - MfDesfireFileData* data); - -MfDesfireError mf_desfire_poller_async_read_file_value( - MfDesfirePoller* instance, - MfDesfireFileId id, - MfDesfireFileData* data); - -MfDesfireError mf_desfire_poller_async_read_file_records( - MfDesfirePoller* instance, - MfDesfireFileId id, - uint32_t offset, - size_t size, - MfDesfireFileData* data); - -MfDesfireError mf_desfire_poller_async_read_file_data_multi( - MfDesfirePoller* instance, - const SimpleArray* file_ids, - const SimpleArray* file_settings, - SimpleArray* data); - -MfDesfireError - mf_desfire_poller_async_read_application(MfDesfirePoller* instance, MfDesfireApplication* data); - -MfDesfireError mf_desfire_poller_async_read_applications( - MfDesfirePoller* instance, - const SimpleArray* app_ids, - SimpleArray* data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 4ad7bc147d..86ab68c8b1 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -230,7 +230,7 @@ static NfcCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance } static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { - instance->error = mf_ultralight_poller_async_read_version(instance, &instance->data->version); + instance->error = mf_ultralight_poller_read_version(instance, &instance->data->version); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Read version success"); instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); @@ -245,7 +245,7 @@ static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* } static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPoller* instance) { - instance->error = mf_ultralight_poller_async_authenticate(instance); + instance->error = mf_ultralight_poller_authenticate(instance); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Ultralight C detected"); instance->data->type = MfUltralightTypeMfulC; @@ -260,7 +260,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPo static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { MfUltralightPageReadCommandData data = {}; - instance->error = mf_ultralight_poller_async_read_page(instance, 41, &data); + instance->error = mf_ultralight_poller_read_page(instance, 41, &data); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "NTAG203 detected"); instance->data->type = MfUltralightTypeNTAG203; @@ -294,7 +294,7 @@ static NfcCommand mf_ultralight_poller_handler_read_signature(MfUltralightPoller instance->feature_set, MfUltralightFeatureSupportReadSignature)) { FURI_LOG_D(TAG, "Reading signature"); instance->error = - mf_ultralight_poller_async_read_signature(instance, &instance->data->signature); + mf_ultralight_poller_read_signature(instance, &instance->data->signature); if(instance->error != MfUltralightErrorNone) { FURI_LOG_D(TAG, "Read signature failed"); next_state = MfUltralightPollerStateReadFailed; @@ -337,7 +337,7 @@ static NfcCommand mf_ultralight_poller_handler_read_counters(MfUltralightPoller* } FURI_LOG_D(TAG, "Reading counter %d", instance->counters_read); - instance->error = mf_ultralight_poller_async_read_counter( + instance->error = mf_ultralight_poller_read_counter( instance, instance->counters_read, &instance->data->counter[instance->counters_read]); if(instance->error != MfUltralightErrorNone) { FURI_LOG_D(TAG, "Failed to read %d counter", instance->counters_read); @@ -363,7 +363,7 @@ static NfcCommand mf_ultralight_poller_handler_read_tearing_flags(MfUltralightPo if(single_counter) instance->tearing_flag_read = 2; FURI_LOG_D(TAG, "Reading tearing flag %d", instance->tearing_flag_read); - instance->error = mf_ultralight_poller_async_read_tearing_flag( + instance->error = mf_ultralight_poller_read_tearing_flag( instance, instance->tearing_flag_read, &instance->data->tearing_flag[instance->tearing_flag_read]); @@ -396,8 +396,7 @@ static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance uint32_t pass = nfc_util_bytes2num( instance->auth_context.password.data, sizeof(MfUltralightAuthPassword)); FURI_LOG_D(TAG, "Trying to authenticate with password %08lX", pass); - instance->error = - mf_ultralight_poller_async_auth_pwd(instance, &instance->auth_context); + instance->error = mf_ultralight_poller_auth_pwd(instance, &instance->auth_context); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Auth success"); instance->auth_context.auth_success = true; @@ -428,13 +427,13 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in if(mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( instance, start_page, §or, &tag, &pages_left)) { instance->error = - mf_ultralight_poller_async_read_page_from_sector(instance, sector, tag, &data); + mf_ultralight_poller_read_page_from_sector(instance, sector, tag, &data); } else { FURI_LOG_D(TAG, "Failed to calculate sector and tag from %d page", start_page); instance->error = MfUltralightErrorProtocol; } } else { - instance->error = mf_ultralight_poller_async_read_page(instance, start_page, &data); + instance->error = mf_ultralight_poller_read_page(instance, start_page, &data); } if(instance->error == MfUltralightErrorNone) { @@ -478,8 +477,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll MF_ULTRALIGHT_DEFAULT_PASSWORD, sizeof(MfUltralightAuthPassword), instance->auth_context.password.data); - instance->error = - mf_ultralight_poller_async_auth_pwd(instance, &instance->auth_context); + instance->error = mf_ultralight_poller_auth_pwd(instance, &instance->auth_context); if(instance->error == MfUltralightErrorNone) { FURI_LOG_D(TAG, "Default password detected"); nfc_util_num2bytes( @@ -576,8 +574,7 @@ static bool mf_ultralight_poller_detect(NfcGenericEvent event, void* context) { if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { MfUltralightPageReadCommandData read_page_cmd_data = {}; - MfUltralightError error = - mf_ultralight_poller_async_read_page(instance, 0, &read_page_cmd_data); + MfUltralightError error = mf_ultralight_poller_read_page(instance, 0, &read_page_cmd_data); protocol_detected = (error == MfUltralightErrorNone); iso14443_3a_poller_halt(instance->iso14443_3a_poller); } diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index 2d4ef33ea9..665d90cb70 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -7,35 +7,181 @@ extern "C" { #endif +/** + * @brief MfUltralightPoller opaque type definition. + */ typedef struct MfUltralightPoller MfUltralightPoller; +/** + * @brief Enumeration of possible MfUltralight poller event types. + */ typedef enum { - MfUltralightPollerEventTypeAuthRequest, - MfUltralightPollerEventTypeAuthSuccess, - MfUltralightPollerEventTypeAuthFailed, - MfUltralightPollerEventTypeReadSuccess, - MfUltralightPollerEventTypeReadFailed, + MfUltralightPollerEventTypeAuthRequest, /**< Poller requests to fill authentication context. */ + MfUltralightPollerEventTypeAuthSuccess, /**< Authentication succeeded. */ + MfUltralightPollerEventTypeAuthFailed, /**< Authentication failed. */ + MfUltralightPollerEventTypeReadSuccess, /**< Poller read card successfully. */ + MfUltralightPollerEventTypeReadFailed, /**< Poller failed to read card. */ } MfUltralightPollerEventType; +/** + * @brief MfUltralight poller authentication context. + */ typedef struct { - MfUltralightAuthPassword password; - MfUltralightAuthPack pack; - bool auth_success; - bool skip_auth; + MfUltralightAuthPassword password; /**< Password to be used for authentication. */ + MfUltralightAuthPack pack; /**< Pack received on successfull authentication. */ + bool auth_success; /**< Set to true if authentication succeeded, false otherwise. */ + bool skip_auth; /**< Set to true if authentication should be skipped, false otherwise. */ } MfUltralightPollerAuthContext; -typedef struct { - union { - MfUltralightPollerAuthContext auth_context; - MfUltralightError error; - }; +/** + * @brief MfUltralight poller event data. + */ +typedef union { + MfUltralightPollerAuthContext auth_context; /**< Authentication context. */ + MfUltralightError error; /**< Error code indicating reading fail reason. */ } MfUltralightPollerEventData; +/** + * @brief MfUltralight poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - MfUltralightPollerEventType type; - MfUltralightPollerEventData* data; + MfUltralightPollerEventType type; /**< Type of emmitted event. */ + MfUltralightPollerEventData* data; /**< Pointer to event specific data. */ } MfUltralightPollerEvent; +/** + * @brief Perform authentication with password. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in, out] data pointer to the authentication context. + * @return MfUltralightErrorNone on success, an error code on failure. + */ +MfUltralightError mf_ultralight_poller_auth_pwd( + MfUltralightPoller* instance, + MfUltralightPollerAuthContext* data); + +/** + * @brief Start authentication procedure. + * + * Must ONLY be used inside the callback function. + * + * This function now is used only to identify Mf Ultralight C cards. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @return MfUltralightErrorNone if card supports authentication command, an error code on otherwise. + */ +MfUltralightError mf_ultralight_poller_authenticate(MfUltralightPoller* instance); + +/** + * @brief Read page from card. + * + * Must ONLY be used inside the callback function. + * + * Send read command and parse response. The response on this command is data of 4 pages starting + * from the page specified in the command. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] start_page page number to be read. + * @param[out] data pointer to the MfUltralightPageReadCommandData structure to be filled with page data. + * @return MfUltralightErrorNone on success, an error code on failure. + */ +MfUltralightError mf_ultralight_poller_read_page( + MfUltralightPoller* instance, + uint8_t start_page, + MfUltralightPageReadCommandData* data); + +/** + * @brief Read page from sector. + * + * Must ONLY be used inside the callback function. + * + * This command should be used for NTAGI2C tags. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] sector sector number to be read. + * @param[in] tag tag number to be read. + * @param[out] data pointer to the MfUltralightPageReadCommandData structure to be filled with page data. + * @return MfUltralightErrorNone on success, an error code on failure. + */ +MfUltralightError mf_ultralight_poller_read_page_from_sector( + MfUltralightPoller* instance, + uint8_t sector, + uint8_t tag, + MfUltralightPageReadCommandData* data); + +/** + * @brief Write page to card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] page page number to be written. + * @param[in] data pointer to the MfUltralightPage structure to be written. + * @return MfUltralightErrorNone on success, an error code on failure. + */ +MfUltralightError mf_ultralight_poller_write_page( + MfUltralightPoller* instance, + uint8_t page, + const MfUltralightPage* data); + +/** + * @brief Read version from card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the MfUltralightVersion structure to be filled. + * @return MfUltralightErrorNone on success, an error code on failure. + */ +MfUltralightError + mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data); + +/** + * @brief Read signature from card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the MfUltralightSignature structure to be filled. + * @return MfUltralightErrorNone on success, an error code on failure. + */ +MfUltralightError + mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data); + +/** + * @brief Read counter from card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] counter_num counter number to be read. + * @param[out] data pointer to the MfUltralightCounter structure to be filled. + * @return MfUltralightErrorNone on success, an error code on failure. + */ +MfUltralightError mf_ultralight_poller_read_counter( + MfUltralightPoller* instance, + uint8_t counter_num, + MfUltralightCounter* data); + +/** + * @brief Read tearing flag from card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tearing_falg_num tearing flag number to be read. + * @param[out] data pointer to the MfUltralightTearingFlag structure to be filled. + * @return MfUltralightErrorNone on success, an error code on failure. + */ +MfUltralightError mf_ultralight_poller_read_tearing_flag( + MfUltralightPoller* instance, + uint8_t tearing_falg_num, + MfUltralightTearingFlag* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c index 795b03e65f..2d88db3e59 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.c @@ -30,7 +30,7 @@ MfUltralightError mf_ultralight_process_error(Iso14443_3aError error) { return ret; } -MfUltralightError mf_ultralight_poller_async_auth_pwd( +MfUltralightError mf_ultralight_poller_auth_pwd( MfUltralightPoller* instance, MfUltralightPollerAuthContext* data) { uint8_t auth_cmd[5] = {MF_ULTRALIGHT_CMD_PWD_AUTH}; //-V1009 @@ -59,7 +59,7 @@ MfUltralightError mf_ultralight_poller_async_auth_pwd( return ret; } -MfUltralightError mf_ultralight_poller_async_authenticate(MfUltralightPoller* instance) { +MfUltralightError mf_ultralight_poller_authenticate(MfUltralightPoller* instance) { uint8_t auth_cmd[2] = {MF_ULTRALIGHT_CMD_AUTH, 0x00}; bit_buffer_copy_bytes(instance->tx_buffer, auth_cmd, sizeof(auth_cmd)); @@ -86,7 +86,7 @@ MfUltralightError mf_ultralight_poller_async_authenticate(MfUltralightPoller* in return ret; } -MfUltralightError mf_ultralight_poller_async_read_page_from_sector( +MfUltralightError mf_ultralight_poller_read_page_from_sector( MfUltralightPoller* instance, uint8_t sector, uint8_t tag, @@ -122,13 +122,13 @@ MfUltralightError mf_ultralight_poller_async_read_page_from_sector( break; } - ret = mf_ultralight_poller_async_read_page(instance, tag, data); + ret = mf_ultralight_poller_read_page(instance, tag, data); } while(false); return ret; } -MfUltralightError mf_ultralight_poller_async_read_page( +MfUltralightError mf_ultralight_poller_read_page( MfUltralightPoller* instance, uint8_t start_page, MfUltralightPageReadCommandData* data) { @@ -158,10 +158,10 @@ MfUltralightError mf_ultralight_poller_async_read_page( return ret; } -MfUltralightError mf_ultralight_poller_async_write_page( +MfUltralightError mf_ultralight_poller_write_page( MfUltralightPoller* instance, uint8_t page, - MfUltralightPage* data) { + const MfUltralightPage* data) { MfUltralightError ret = MfUltralightErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -191,9 +191,8 @@ MfUltralightError mf_ultralight_poller_async_write_page( return ret; } -MfUltralightError mf_ultralight_poller_async_read_version( - MfUltralightPoller* instance, - MfUltralightVersion* data) { +MfUltralightError + mf_ultralight_poller_read_version(MfUltralightPoller* instance, MfUltralightVersion* data) { MfUltralightError ret = MfUltralightErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -221,9 +220,8 @@ MfUltralightError mf_ultralight_poller_async_read_version( return ret; } -MfUltralightError mf_ultralight_poller_async_read_signature( - MfUltralightPoller* instance, - MfUltralightSignature* data) { +MfUltralightError + mf_ultralight_poller_read_signature(MfUltralightPoller* instance, MfUltralightSignature* data) { MfUltralightError ret = MfUltralightErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -249,7 +247,7 @@ MfUltralightError mf_ultralight_poller_async_read_signature( return ret; } -MfUltralightError mf_ultralight_poller_async_read_counter( +MfUltralightError mf_ultralight_poller_read_counter( MfUltralightPoller* instance, uint8_t counter_num, MfUltralightCounter* data) { @@ -278,7 +276,7 @@ MfUltralightError mf_ultralight_poller_async_read_counter( return ret; } -MfUltralightError mf_ultralight_poller_async_read_tearing_flag( +MfUltralightError mf_ultralight_poller_read_tearing_flag( MfUltralightPoller* instance, uint8_t tearing_falg_num, MfUltralightTearingFlag* data) { diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index 13490cf1a9..c89402b421 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -103,46 +103,6 @@ bool mf_ultralight_poller_ntag_i2c_addr_lin_to_tag( uint8_t* tag, uint8_t* pages_left); -MfUltralightError mf_ultralight_poller_async_auth_pwd( - MfUltralightPoller* instance, - MfUltralightPollerAuthContext* data); - -MfUltralightError mf_ultralight_poller_async_authenticate(MfUltralightPoller* instance); - -MfUltralightError mf_ultralight_poller_async_read_page( - MfUltralightPoller* instance, - uint8_t start_page, - MfUltralightPageReadCommandData* data); - -MfUltralightError mf_ultralight_poller_async_read_page_from_sector( - MfUltralightPoller* instance, - uint8_t sector, - uint8_t tag, - MfUltralightPageReadCommandData* data); - -MfUltralightError mf_ultralight_poller_async_write_page( - MfUltralightPoller* instance, - uint8_t page, - MfUltralightPage* data); - -MfUltralightError mf_ultralight_poller_async_read_version( - MfUltralightPoller* instance, - MfUltralightVersion* data); - -MfUltralightError mf_ultralight_poller_async_read_signature( - MfUltralightPoller* instance, - MfUltralightSignature* data); - -MfUltralightError mf_ultralight_poller_async_read_counter( - MfUltralightPoller* instance, - uint8_t counter_num, - MfUltralightCounter* data); - -MfUltralightError mf_ultralight_poller_async_read_tearing_flag( - MfUltralightPoller* instance, - uint8_t tearing_falg_num, - MfUltralightTearingFlag* data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c similarity index 83% rename from lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c rename to lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c index 739df597d2..c4833facf0 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.c @@ -1,3 +1,4 @@ +#include "mf_ultralight_poller_sync.h" #include "mf_ultralight_poller_i.h" #include @@ -31,40 +32,39 @@ typedef MfUltralightError (*MfUltralightPollerCmdHandler)( MfUltralightError mf_ultralight_poller_read_page_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { - return mf_ultralight_poller_async_read_page( - poller, data->read_cmd.start_page, &data->read_cmd.data); + return mf_ultralight_poller_read_page(poller, data->read_cmd.start_page, &data->read_cmd.data); } MfUltralightError mf_ultralight_poller_write_page_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { - return mf_ultralight_poller_async_write_page( + return mf_ultralight_poller_write_page( poller, data->write_cmd.page_to_write, &data->write_cmd.page); } MfUltralightError mf_ultralight_poller_read_version_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { - return mf_ultralight_poller_async_read_version(poller, &data->version); + return mf_ultralight_poller_read_version(poller, &data->version); } MfUltralightError mf_ultralight_poller_read_signature_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { - return mf_ultralight_poller_async_read_signature(poller, &data->signature); + return mf_ultralight_poller_read_signature(poller, &data->signature); } MfUltralightError mf_ultralight_poller_read_counter_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { - return mf_ultralight_poller_async_read_counter( + return mf_ultralight_poller_read_counter( poller, data->counter_cmd.counter_num, &data->counter_cmd.data); } MfUltralightError mf_ultralight_poller_read_tearing_flag_handler( MfUltralightPoller* poller, MfUltralightPollerContextData* data) { - return mf_ultralight_poller_async_read_tearing_flag( + return mf_ultralight_poller_read_tearing_flag( poller, data->tearing_flag_cmd.tearing_flag_num, &data->tearing_flag_cmd.data); } @@ -79,16 +79,14 @@ static const MfUltralightPollerCmdHandler mf_ultralight_poller_read_tearing_flag_handler, }; -static NfcCommand mf_ultralight_poller_cmd_callback(NfcGenericEvent event, void* context) { - furi_assert(event.instance); - furi_assert(event.protocol == NfcProtocolIso14443_3a); - furi_assert(event.event_data); +static NfcCommand mf_ultralight_poller_cmd_callback(NfcGenericEventEx event, void* context) { + furi_assert(event.poller); + furi_assert(event.parent_event_data); furi_assert(context); MfUltralightPollerContext* poller_context = context; - Iso14443_3aPollerEvent* iso14443_3a_event = event.event_data; - Iso14443_3aPoller* iso14443_3a_poller = event.instance; - MfUltralightPoller* mfu_poller = mf_ultralight_poller_alloc(iso14443_3a_poller); + Iso14443_3aPollerEvent* iso14443_3a_event = event.parent_event_data; + MfUltralightPoller* mfu_poller = event.poller; if(iso14443_3a_event->type == Iso14443_3aPollerEventTypeReady) { poller_context->error = mf_ultralight_poller_cmd_handlers[poller_context->cmd_type]( @@ -99,8 +97,6 @@ static NfcCommand mf_ultralight_poller_cmd_callback(NfcGenericEvent event, void* furi_thread_flags_set(poller_context->thread_id, MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); - mf_ultralight_poller_free(mfu_poller); - return NfcCommandStop; } @@ -110,8 +106,8 @@ static MfUltralightError poller_ctx->thread_id = furi_thread_get_current_id(); - NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolIso14443_3a); - nfc_poller_start(poller, mf_ultralight_poller_cmd_callback, poller_ctx); + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolMfUltralight); + nfc_poller_start_ex(poller, mf_ultralight_poller_cmd_callback, poller_ctx); furi_thread_flags_wait(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT, FuriFlagWaitAny, FuriWaitForever); furi_thread_flags_clear(MF_ULTRALIGHT_POLLER_COMPLETE_EVENT); @@ -121,7 +117,8 @@ static MfUltralightError return poller_ctx->error; } -MfUltralightError mf_ultralight_poller_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) { +MfUltralightError + mf_ultralight_poller_sync_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) { furi_assert(nfc); furi_assert(data); @@ -140,7 +137,7 @@ MfUltralightError mf_ultralight_poller_read_page(Nfc* nfc, uint16_t page, MfUltr } MfUltralightError - mf_ultralight_poller_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) { + mf_ultralight_poller_sync_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data) { furi_assert(nfc); furi_assert(data); @@ -158,7 +155,7 @@ MfUltralightError return error; } -MfUltralightError mf_ultralight_poller_read_version(Nfc* nfc, MfUltralightVersion* data) { +MfUltralightError mf_ultralight_poller_sync_read_version(Nfc* nfc, MfUltralightVersion* data) { furi_assert(nfc); furi_assert(data); @@ -175,7 +172,7 @@ MfUltralightError mf_ultralight_poller_read_version(Nfc* nfc, MfUltralightVersio return error; } -MfUltralightError mf_ultralight_poller_read_signature(Nfc* nfc, MfUltralightSignature* data) { +MfUltralightError mf_ultralight_poller_sync_read_signature(Nfc* nfc, MfUltralightSignature* data) { furi_assert(nfc); furi_assert(data); @@ -192,8 +189,10 @@ MfUltralightError mf_ultralight_poller_read_signature(Nfc* nfc, MfUltralightSign return error; } -MfUltralightError - mf_ultralight_poller_read_counter(Nfc* nfc, uint8_t counter_num, MfUltralightCounter* data) { +MfUltralightError mf_ultralight_poller_sync_read_counter( + Nfc* nfc, + uint8_t counter_num, + MfUltralightCounter* data) { furi_assert(nfc); furi_assert(data); @@ -211,7 +210,7 @@ MfUltralightError return error; } -MfUltralightError mf_ultralight_poller_read_tearing_flag( +MfUltralightError mf_ultralight_poller_sync_read_tearing_flag( Nfc* nfc, uint8_t flag_num, MfUltralightTearingFlag* data) { @@ -261,7 +260,7 @@ static NfcCommand mf_ultralight_poller_read_callback(NfcGenericEvent event, void return command; } -MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* data) { +MfUltralightError mf_ultralight_poller_sync_read_card(Nfc* nfc, MfUltralightData* data) { furi_assert(nfc); furi_assert(data); diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h new file mode 100644 index 0000000000..ac585aad7e --- /dev/null +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h @@ -0,0 +1,34 @@ +#pragma once + +#include "mf_ultralight.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +MfUltralightError + mf_ultralight_poller_sync_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data); + +MfUltralightError + mf_ultralight_poller_sync_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data); + +MfUltralightError mf_ultralight_poller_sync_read_version(Nfc* nfc, MfUltralightVersion* data); + +MfUltralightError mf_ultralight_poller_sync_read_signature(Nfc* nfc, MfUltralightSignature* data); + +MfUltralightError mf_ultralight_poller_sync_read_counter( + Nfc* nfc, + uint8_t counter_num, + MfUltralightCounter* data); + +MfUltralightError mf_ultralight_poller_sync_read_tearing_flag( + Nfc* nfc, + uint8_t flag_num, + MfUltralightTearingFlag* data); + +MfUltralightError mf_ultralight_poller_sync_read_card(Nfc* nfc, MfUltralightData* data); + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h deleted file mode 100644 index a0124ae092..0000000000 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync_api.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "mf_ultralight.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -MfUltralightError mf_ultralight_poller_read_page(Nfc* nfc, uint16_t page, MfUltralightPage* data); - -MfUltralightError mf_ultralight_poller_write_page(Nfc* nfc, uint16_t page, MfUltralightPage* data); - -MfUltralightError mf_ultralight_poller_read_version(Nfc* nfc, MfUltralightVersion* data); - -MfUltralightError mf_ultralight_poller_read_signature(Nfc* nfc, MfUltralightSignature* data); - -MfUltralightError - mf_ultralight_poller_read_counter(Nfc* nfc, uint8_t counter_num, MfUltralightCounter* data); - -MfUltralightError mf_ultralight_poller_read_tearing_flag( - Nfc* nfc, - uint8_t flag_num, - MfUltralightTearingFlag* data); - -MfUltralightError mf_ultralight_poller_read_card(Nfc* nfc, MfUltralightData* data); - -#ifdef __cplusplus -} -#endif diff --git a/lib/nfc/protocols/nfc_protocol.h b/lib/nfc/protocols/nfc_protocol.h index 55aa8a5895..ee63453335 100644 --- a/lib/nfc/protocols/nfc_protocol.h +++ b/lib/nfc/protocols/nfc_protocol.h @@ -61,9 +61,9 @@ * | | * +- protocol_name_listener_defs.h | * | - * +- protocol_name_sync_api.h | + * +- protocol_name_sync.h | * | |- add for synchronous API support - * +- protocol_name_sync_api.c | + * +- protocol_name_sync.c | * | * ``` * @@ -83,8 +83,8 @@ * | protocol_name_listener.h | Protocol-specific listener and associated functions declarations. Optional, needed for emulation support. | * | protocol_name_listener.c | Implementation of functions declared in `protocol_name_listener.h`. Optional, needed for emulation support. | * | protocol_name_listener_defs.h | Declarations for use by the NfcListener library. See nfc_listener_base.h for more info. Optional, needed for emulation support. | - * | protocol_name_sync_api.h | Synchronous API declarations. (See below for sync API explanation). Optional.| - * | protocol_name_sync_api.c | Synchronous API implementation. Optional. | + * | protocol_name_sync.h | Synchronous API declarations. (See below for sync API explanation). Optional.| + * | protocol_name_sync.c | Synchronous API implementation. Optional. | * * ## 3 Implement the code * @@ -145,7 +145,7 @@ * `protocol_name_poller_defs` structure under the appropriate index. * 5. (Optional) If emulation support was implemented, do the step 4, but for the listener. * 6. Add `protocol_name.h`, `protocol_name_poller.h`, and optionally, `protocol_name_listener.h` - * and `protocol_name_sync_api.h` into the `SDK_HEADERS` list in the SConscript file. + * and `protocol_name_sync.h` into the `SDK_HEADERS` list in the SConscript file. * This will export the protocol's types and functions for use by the applications. * 7. Done! * diff --git a/lib/nfc/protocols/slix/slix_poller.c b/lib/nfc/protocols/slix/slix_poller.c index 9731bfc6b8..46a1711943 100644 --- a/lib/nfc/protocols/slix/slix_poller.c +++ b/lib/nfc/protocols/slix/slix_poller.c @@ -50,8 +50,7 @@ static NfcCommand slix_poller_handler_idle(SlixPoller* instance) { } static NfcCommand slix_poller_handler_get_nfc_system_info(SlixPoller* instance) { - instance->error = - slix_poller_async_get_nxp_system_info(instance, &instance->data->system_info); + instance->error = slix_poller_get_nxp_system_info(instance, &instance->data->system_info); if(instance->error == SlixErrorNone) { instance->poller_state = SlixPollerStateReadSignature; } else { @@ -62,7 +61,7 @@ static NfcCommand slix_poller_handler_get_nfc_system_info(SlixPoller* instance) } static NfcCommand slix_poller_handler_read_signature(SlixPoller* instance) { - instance->error = slix_poller_async_read_signature(instance, &instance->data->signature); + instance->error = slix_poller_read_signature(instance, &instance->data->signature); if(instance->error == SlixErrorNone) { instance->poller_state = SlixPollerStateReady; } else { @@ -141,7 +140,7 @@ static bool slix_poller_detect(NfcGenericEvent event, void* context) { if(iso15693_3_event->type == Iso15693_3PollerEventTypeReady) { if(slix_get_type(instance->data) < SlixTypeCount) { SlixSystemInfo system_info = {}; - SlixError error = slix_poller_async_get_nxp_system_info(instance, &system_info); + SlixError error = slix_poller_get_nxp_system_info(instance, &system_info); protocol_detected = (error == SlixErrorNone); } } diff --git a/lib/nfc/protocols/slix/slix_poller.h b/lib/nfc/protocols/slix/slix_poller.h index f4c7214de4..62d60be5fe 100644 --- a/lib/nfc/protocols/slix/slix_poller.h +++ b/lib/nfc/protocols/slix/slix_poller.h @@ -8,22 +8,78 @@ extern "C" { #endif +/** + * @brief SlixPoller opaque type definition. + */ typedef struct SlixPoller SlixPoller; +/** + * @brief Enumeration of possible Slix poller event types. + */ typedef enum { - SlixPollerEventTypeError, - SlixPollerEventTypeReady, + SlixPollerEventTypeError, /**< An error occured while reading card. */ + SlixPollerEventTypeReady, /**< The card was successfully read by the poller. */ } SlixPollerEventType; -typedef struct { - SlixError error; +/** + * @brief Slixs poller event data. + */ +typedef union { + SlixError error; /**< Error code indicating card reaing fail reason. */ } SlixPollerEventData; +/** + * @brief Slix poller event structure. + * + * Upon emission of an event, an instance of this struct will be passed to the callback. + */ typedef struct { - SlixPollerEventType type; - SlixPollerEventData* data; + SlixPollerEventType type; /**< Type of emmitted event. */ + SlixPollerEventData* data; /**< Pointer to event specific data. */ } SlixPollerEvent; +/** + * @brief Transmit and receive Slix frames in poller mode. + * + * Must ONLY be used inside the callback function. + * + * The rx_buffer will be filled with any data received as a response to data + * sent from tx_buffer, with a timeout defined by the fwt parameter. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] tx_buffer pointer to the buffer containing the data to be transmitted. + * @param[out] rx_buffer pointer to the buffer to be filled with received data. + * @param[in] fwt frame wait time (response timeout), in carrier cycles. + * @return SlixErrorNone on success, an error code on failure. + */ +SlixError slix_poller_send_frame( + SlixPoller* instance, + const BitBuffer* tx_data, + BitBuffer* rx_data, + uint32_t fwt); + +/** + * @brief Send get nxp system info command and parse response. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the SlixSystemInfo structure to be filled. + * @return SlixErrorNone on success, an error code on failure. + */ +SlixError slix_poller_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* data); + +/** + * @brief Read signature from card. + * + * Must ONLY be used inside the callback function. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[out] data pointer to the SlixSignature structure to be filled. + * @return SlixErrorNone on success, an error code on failure. + */ +SlixError slix_poller_read_signature(SlixPoller* instance, SlixSignature* data); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/slix/slix_poller_i.c b/lib/nfc/protocols/slix/slix_poller_i.c index a36e7694a4..6d7bdf3779 100644 --- a/lib/nfc/protocols/slix/slix_poller_i.c +++ b/lib/nfc/protocols/slix/slix_poller_i.c @@ -32,7 +32,7 @@ SlixError slix_poller_send_frame( return slix_process_iso15693_3_error(iso15693_3_error); } -SlixError slix_poller_async_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* data) { +SlixError slix_poller_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* data) { furi_assert(instance); furi_assert(data); @@ -50,7 +50,7 @@ SlixError slix_poller_async_get_nxp_system_info(SlixPoller* instance, SlixSystem return error; } -SlixError slix_poller_async_read_signature(SlixPoller* instance, SlixSignature* data) { +SlixError slix_poller_read_signature(SlixPoller* instance, SlixSignature* data) { furi_assert(instance); furi_assert(data); diff --git a/lib/nfc/protocols/slix/slix_poller_i.h b/lib/nfc/protocols/slix/slix_poller_i.h index c6a8a3c33e..1fda1a7d24 100644 --- a/lib/nfc/protocols/slix/slix_poller_i.h +++ b/lib/nfc/protocols/slix/slix_poller_i.h @@ -33,16 +33,6 @@ struct SlixPoller { void* context; }; -SlixError slix_poller_send_frame( - SlixPoller* instance, - const BitBuffer* tx_data, - BitBuffer* rx_data, - uint32_t fwt); - -SlixError slix_poller_async_get_nxp_system_info(SlixPoller* instance, SlixSystemInfo* data); - -SlixError slix_poller_async_read_signature(SlixPoller* instance, SlixSignature* data); - #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/st25tb/st25tb_poller.c b/lib/nfc/protocols/st25tb/st25tb_poller.c index df659a2051..2bc5dd9410 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller.c +++ b/lib/nfc/protocols/st25tb/st25tb_poller.c @@ -71,7 +71,7 @@ static NfcCommand st25tb_poller_run(NfcGenericEvent event, void* context) { if(nfc_event->type == NfcEventTypePollerReady) { if(instance->state != St25tbPollerStateActivated) { - St25tbError error = st25tb_poller_async_activate(instance, instance->data); + St25tbError error = st25tb_poller_activate(instance, instance->data); if(error == St25tbErrorNone) { instance->st25tb_event.type = St25tbPollerEventTypeReady; @@ -106,7 +106,7 @@ static bool st25tb_poller_detect(NfcGenericEvent event, void* context) { furi_assert(instance->state == St25tbPollerStateIdle); if(nfc_event->type == NfcEventTypePollerReady) { - St25tbError error = st25tb_poller_async_initiate(instance, NULL); + St25tbError error = st25tb_poller_initiate(instance, NULL); protocol_detected = (error == St25tbErrorNone); } diff --git a/lib/nfc/protocols/st25tb/st25tb_poller.h b/lib/nfc/protocols/st25tb/st25tb_poller.h index a521b6d5b4..d3b85e3066 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller.h +++ b/lib/nfc/protocols/st25tb/st25tb_poller.h @@ -25,6 +25,23 @@ typedef struct { St25tbPollerEventData* data; } St25tbPollerEvent; +St25tbError st25tb_poller_send_frame( + St25tbPoller* instance, + const BitBuffer* tx_buffer, + BitBuffer* rx_buffer, + uint32_t fwt); + +St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id); + +St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data); + +St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid); + +St25tbError + st25tb_poller_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number); + +St25tbError st25tb_poller_halt(St25tbPoller* instance); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_i.c b/lib/nfc/protocols/st25tb/st25tb_poller_i.c index bcbc69382a..76c9a8b1fa 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller_i.c +++ b/lib/nfc/protocols/st25tb/st25tb_poller_i.c @@ -22,7 +22,7 @@ static St25tbError st25tb_poller_prepare_trx(St25tbPoller* instance) { furi_assert(instance); if(instance->state == St25tbPollerStateIdle) { - return st25tb_poller_async_activate(instance, NULL); + return st25tb_poller_activate(instance, NULL); } return St25tbErrorNone; @@ -85,7 +85,7 @@ St25tbType st25tb_get_type_from_uid(const uint8_t uid[ST25TB_UID_SIZE]) { } } -St25tbError st25tb_poller_async_initiate(St25tbPoller* instance, uint8_t* chip_id) { +St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id) { // Send Initiate() furi_assert(instance); furi_assert(instance->nfc); @@ -117,7 +117,7 @@ St25tbError st25tb_poller_async_initiate(St25tbPoller* instance, uint8_t* chip_i return ret; } -St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* data) { +St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data) { furi_assert(instance); furi_assert(instance->nfc); @@ -126,7 +126,7 @@ St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* dat St25tbError ret; do { - ret = st25tb_poller_async_initiate(instance, &data->chip_id); + ret = st25tb_poller_initiate(instance, &data->chip_id); if(ret != St25tbErrorNone) { break; } @@ -162,7 +162,7 @@ St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* dat } instance->state = St25tbPollerStateActivated; - ret = st25tb_poller_async_get_uid(instance, data->uid); + ret = st25tb_poller_get_uid(instance, data->uid); if(ret != St25tbErrorNone) { instance->state = St25tbPollerStateActivationFailed; break; @@ -171,7 +171,7 @@ St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* dat bool read_blocks = true; for(uint8_t i = 0; i < st25tb_get_block_count(data->type); i++) { - ret = st25tb_poller_async_read_block(instance, &data->blocks[i], i); + ret = st25tb_poller_read_block(instance, &data->blocks[i], i); if(ret != St25tbErrorNone) { read_blocks = false; break; @@ -180,14 +180,13 @@ St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* dat if(!read_blocks) { break; } - ret = st25tb_poller_async_read_block( - instance, &data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); + ret = st25tb_poller_read_block(instance, &data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); } while(false); return ret; } -St25tbError st25tb_poller_async_get_uid(St25tbPoller* instance, uint8_t uid[ST25TB_UID_SIZE]) { +St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) { furi_assert(instance); furi_assert(instance->nfc); @@ -221,7 +220,7 @@ St25tbError st25tb_poller_async_get_uid(St25tbPoller* instance, uint8_t uid[ST25 } St25tbError - st25tb_poller_async_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number) { + st25tb_poller_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number) { furi_assert(instance); furi_assert(instance->nfc); furi_assert(block); diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_i.h b/lib/nfc/protocols/st25tb/st25tb_poller_i.h index 7f38f2d45b..27218d7b44 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller_i.h +++ b/lib/nfc/protocols/st25tb/st25tb_poller_i.h @@ -34,23 +34,6 @@ struct St25tbPoller { const St25tbData* st25tb_poller_get_data(St25tbPoller* instance); -St25tbError st25tb_poller_async_initiate(St25tbPoller* instance, uint8_t* chip_id); - -St25tbError st25tb_poller_async_activate(St25tbPoller* instance, St25tbData* data); - -St25tbError st25tb_poller_async_get_uid(St25tbPoller* instance, uint8_t uid[ST25TB_UID_SIZE]); - -St25tbError - st25tb_poller_async_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number); - -St25tbError st25tb_poller_halt(St25tbPoller* instance); - -St25tbError st25tb_poller_send_frame( - St25tbPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt); - #ifdef __cplusplus } #endif diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 0eadd799d4..44829c264d 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,44.0,, +Version,+,45.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -39,6 +39,8 @@ Header,+,applications/services/storage/storage.h,, Header,+,lib/digital_signal/digital_sequence.h,, Header,+,lib/digital_signal/digital_signal.h,, Header,+,lib/drivers/cc1101_regs.h,, +Header,+,lib/drivers/st25r3916.h,, +Header,+,lib/drivers/st25r3916_reg.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, @@ -2045,6 +2047,29 @@ Function,+,srand,void,unsigned Function,-,srand48,void,long Function,-,srandom,void,unsigned Function,+,sscanf,int,"const char*, const char*, ..." +Function,+,st25r3916_change_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_change_test_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_check_reg,_Bool,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_clear_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_direct_cmd,void,"FuriHalSpiBusHandle*, uint8_t" +Function,+,st25r3916_get_irq,uint32_t,FuriHalSpiBusHandle* +Function,+,st25r3916_mask_irq,void,"FuriHalSpiBusHandle*, uint32_t" +Function,+,st25r3916_modify_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_read_burst_regs,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*, uint8_t" +Function,+,st25r3916_read_fifo,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, size_t*" +Function,+,st25r3916_read_pta_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_read_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" +Function,+,st25r3916_read_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" +Function,+,st25r3916_reg_read_fifo,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_reg_write_fifo,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_set_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_write_burst_regs,void,"FuriHalSpiBusHandle*, uint8_t, const uint8_t*, uint8_t" +Function,+,st25r3916_write_fifo,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_pta_mem,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_ptf_mem,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_pttsn_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_write_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_write_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" Function,+,storage_common_exists,_Bool,"Storage*, const char*" Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 9834531953..514f332868 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,44.0,, +Version,+,45.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -40,6 +40,8 @@ Header,+,applications/services/storage/storage.h,, Header,+,lib/digital_signal/digital_sequence.h,, Header,+,lib/digital_signal/digital_signal.h,, Header,+,lib/drivers/cc1101_regs.h,, +Header,+,lib/drivers/st25r3916.h,, +Header,+,lib/drivers/st25r3916_reg.h,, Header,+,lib/flipper_application/api_hashtable/api_hashtable.h,, Header,+,lib/flipper_application/api_hashtable/compilesort.hpp,, Header,+,lib/flipper_application/flipper_application.h,, @@ -117,7 +119,7 @@ Header,+,lib/nfc/nfc_scanner.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_listener.h,, Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller.h,, -Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync_api.h,, +Header,+,lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_sync.h,, Header,+,lib/nfc/protocols/iso14443_3b/iso14443_3b.h,, Header,+,lib/nfc/protocols/iso14443_3b/iso14443_3b_poller.h,, Header,+,lib/nfc/protocols/iso14443_4a/iso14443_4a.h,, @@ -128,13 +130,13 @@ Header,+,lib/nfc/protocols/iso14443_4b/iso14443_4b_poller.h,, Header,+,lib/nfc/protocols/mf_classic/mf_classic.h,, Header,+,lib/nfc/protocols/mf_classic/mf_classic_listener.h,, Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller.h,, -Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller_sync_api.h,, +Header,+,lib/nfc/protocols/mf_classic/mf_classic_poller_sync.h,, Header,+,lib/nfc/protocols/mf_desfire/mf_desfire.h,, Header,+,lib/nfc/protocols/mf_desfire/mf_desfire_poller.h,, Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight.h,, 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_api.h,, +Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h,, Header,+,lib/nfc/protocols/slix/slix.h,, Header,+,lib/nfc/protocols/st25tb/st25tb.h,, Header,+,lib/nfc/protocols/st25tb/st25tb_poller.h,, @@ -1861,9 +1863,13 @@ Function,+,iso14443_3a_get_sak,uint8_t,const Iso14443_3aData* Function,+,iso14443_3a_get_uid,const uint8_t*,"const Iso14443_3aData*, size_t*" Function,+,iso14443_3a_is_equal,_Bool,"const Iso14443_3aData*, const Iso14443_3aData*" Function,+,iso14443_3a_load,_Bool,"Iso14443_3aData*, FlipperFormat*, uint32_t" -Function,+,iso14443_3a_poller_read,Iso14443_3aError,"Nfc*, Iso14443_3aData*" +Function,+,iso14443_3a_poller_activate,Iso14443_3aError,"Iso14443_3aPoller*, Iso14443_3aData*" +Function,+,iso14443_3a_poller_check_presence,Iso14443_3aError,Iso14443_3aPoller* +Function,+,iso14443_3a_poller_halt,Iso14443_3aError,Iso14443_3aPoller* Function,+,iso14443_3a_poller_send_standard_frame,Iso14443_3aError,"Iso14443_3aPoller*, const BitBuffer*, BitBuffer*, uint32_t" +Function,+,iso14443_3a_poller_sync_read,Iso14443_3aError,"Nfc*, Iso14443_3aData*" Function,+,iso14443_3a_poller_txrx,Iso14443_3aError,"Iso14443_3aPoller*, const BitBuffer*, BitBuffer*, uint32_t" +Function,+,iso14443_3a_poller_txrx_custom_parity,Iso14443_3aError,"Iso14443_3aPoller*, const BitBuffer*, BitBuffer*, uint32_t" Function,+,iso14443_3a_reset,void,Iso14443_3aData* Function,+,iso14443_3a_save,_Bool,"const Iso14443_3aData*, FlipperFormat*" Function,+,iso14443_3a_set_atqa,void,"Iso14443_3aData*, const uint8_t[2]" @@ -1882,6 +1888,9 @@ Function,+,iso14443_3b_get_fwt_fc_max,uint32_t,const Iso14443_3bData* Function,+,iso14443_3b_get_uid,const uint8_t*,"const Iso14443_3bData*, size_t*" Function,+,iso14443_3b_is_equal,_Bool,"const Iso14443_3bData*, const Iso14443_3bData*" Function,+,iso14443_3b_load,_Bool,"Iso14443_3bData*, FlipperFormat*, uint32_t" +Function,+,iso14443_3b_poller_activate,Iso14443_3bError,"Iso14443_3bPoller*, Iso14443_3bData*" +Function,+,iso14443_3b_poller_halt,Iso14443_3bError,Iso14443_3bPoller* +Function,+,iso14443_3b_poller_send_frame,Iso14443_3bError,"Iso14443_3bPoller*, const BitBuffer*, BitBuffer*" Function,+,iso14443_3b_reset,void,Iso14443_3bData* Function,+,iso14443_3b_save,_Bool,"const Iso14443_3bData*, FlipperFormat*" Function,+,iso14443_3b_set_uid,_Bool,"Iso14443_3bData*, const uint8_t*, size_t" @@ -1900,6 +1909,9 @@ Function,+,iso14443_4a_get_historical_bytes,const uint8_t*,"const Iso14443_4aDat Function,+,iso14443_4a_get_uid,const uint8_t*,"const Iso14443_4aData*, size_t*" Function,+,iso14443_4a_is_equal,_Bool,"const Iso14443_4aData*, const Iso14443_4aData*" Function,+,iso14443_4a_load,_Bool,"Iso14443_4aData*, FlipperFormat*, uint32_t" +Function,+,iso14443_4a_poller_halt,Iso14443_4aError,Iso14443_4aPoller* +Function,+,iso14443_4a_poller_read_ats,Iso14443_4aError,"Iso14443_4aPoller*, Iso14443_4aAtsData*" +Function,+,iso14443_4a_poller_send_block,Iso14443_4aError,"Iso14443_4aPoller*, const BitBuffer*, BitBuffer*" Function,+,iso14443_4a_reset,void,Iso14443_4aData* Function,+,iso14443_4a_save,_Bool,"const Iso14443_4aData*, FlipperFormat*" Function,+,iso14443_4a_set_uid,_Bool,"Iso14443_4aData*, const uint8_t*, size_t" @@ -1914,6 +1926,8 @@ Function,+,iso14443_4b_get_device_name,const char*,"const Iso14443_4bData*, NfcD Function,+,iso14443_4b_get_uid,const uint8_t*,"const Iso14443_4bData*, size_t*" Function,+,iso14443_4b_is_equal,_Bool,"const Iso14443_4bData*, const Iso14443_4bData*" Function,+,iso14443_4b_load,_Bool,"Iso14443_4bData*, FlipperFormat*, uint32_t" +Function,+,iso14443_4b_poller_halt,Iso14443_4bError,Iso14443_4bPoller* +Function,+,iso14443_4b_poller_send_block,Iso14443_4bError,"Iso14443_4bPoller*, const BitBuffer*, BitBuffer*" Function,+,iso14443_4b_reset,void,Iso14443_4bData* Function,+,iso14443_4b_save,_Bool,"const Iso14443_4bData*, FlipperFormat*" Function,+,iso14443_4b_set_uid,_Bool,"Iso14443_4bData*, const uint8_t*, size_t" @@ -2141,14 +2155,21 @@ Function,+,mf_classic_is_sector_read,_Bool,"const MfClassicData*, uint8_t" Function,+,mf_classic_is_sector_trailer,_Bool,uint8_t Function,+,mf_classic_is_value_block,_Bool,"MfClassicSectorTrailer*, uint8_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" -Function,+,mf_classic_poller_auth,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" -Function,+,mf_classic_poller_change_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t, int32_t*" -Function,+,mf_classic_poller_collect_nt,MfClassicError,"Nfc*, uint8_t, MfClassicKeyType, MfClassicNt*" -Function,+,mf_classic_poller_detect_type,MfClassicError,"Nfc*, MfClassicType*" -Function,+,mf_classic_poller_read,MfClassicError,"Nfc*, const MfClassicDeviceKeys*, MfClassicData*" -Function,+,mf_classic_poller_read_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" -Function,+,mf_classic_poller_read_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t*" -Function,+,mf_classic_poller_write_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" +Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_get_nt,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" +Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller* +Function,+,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*" +Function,+,mf_classic_poller_sync_auth,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_sync_change_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t, int32_t*" +Function,+,mf_classic_poller_sync_collect_nt,MfClassicError,"Nfc*, uint8_t, MfClassicKeyType, MfClassicNt*" +Function,+,mf_classic_poller_sync_detect_type,MfClassicError,"Nfc*, MfClassicType*" +Function,+,mf_classic_poller_sync_read,MfClassicError,"Nfc*, const MfClassicDeviceKeys*, MfClassicData*" +Function,+,mf_classic_poller_sync_read_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" +Function,+,mf_classic_poller_sync_read_value,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, int32_t*" +Function,+,mf_classic_poller_sync_write_block,MfClassicError,"Nfc*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicBlock*" +Function,+,mf_classic_poller_value_cmd,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicValueCommand, int32_t" +Function,+,mf_classic_poller_value_transfer,MfClassicError,"MfClassicPoller*, uint8_t" +Function,+,mf_classic_poller_write_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*" Function,+,mf_classic_reset,void,MfClassicData* Function,+,mf_classic_save,_Bool,"const MfClassicData*, FlipperFormat*" Function,+,mf_classic_set_block_read,void,"MfClassicData*, uint8_t, MfClassicBlock*" @@ -2168,8 +2189,24 @@ Function,+,mf_desfire_get_file_settings,const MfDesfireFileSettings*,"const MfDe Function,+,mf_desfire_get_uid,const uint8_t*,"const MfDesfireData*, size_t*" Function,+,mf_desfire_is_equal,_Bool,"const MfDesfireData*, const MfDesfireData*" Function,+,mf_desfire_load,_Bool,"MfDesfireData*, FlipperFormat*, uint32_t" +Function,+,mf_desfire_poller_read_application,MfDesfireError,"MfDesfirePoller*, MfDesfireApplication*" +Function,+,mf_desfire_poller_read_application_ids,MfDesfireError,"MfDesfirePoller*, SimpleArray*" +Function,+,mf_desfire_poller_read_applications,MfDesfireError,"MfDesfirePoller*, const SimpleArray*, SimpleArray*" +Function,+,mf_desfire_poller_read_file_data,MfDesfireError,"MfDesfirePoller*, MfDesfireFileId, uint32_t, size_t, MfDesfireFileData*" +Function,+,mf_desfire_poller_read_file_data_multi,MfDesfireError,"MfDesfirePoller*, const SimpleArray*, const SimpleArray*, SimpleArray*" +Function,+,mf_desfire_poller_read_file_ids,MfDesfireError,"MfDesfirePoller*, SimpleArray*" +Function,+,mf_desfire_poller_read_file_records,MfDesfireError,"MfDesfirePoller*, MfDesfireFileId, uint32_t, size_t, MfDesfireFileData*" +Function,+,mf_desfire_poller_read_file_settings,MfDesfireError,"MfDesfirePoller*, MfDesfireFileId, MfDesfireFileSettings*" +Function,+,mf_desfire_poller_read_file_settings_multi,MfDesfireError,"MfDesfirePoller*, const SimpleArray*, SimpleArray*" +Function,+,mf_desfire_poller_read_file_value,MfDesfireError,"MfDesfirePoller*, MfDesfireFileId, MfDesfireFileData*" +Function,+,mf_desfire_poller_read_free_memory,MfDesfireError,"MfDesfirePoller*, MfDesfireFreeMemory*" +Function,+,mf_desfire_poller_read_key_settings,MfDesfireError,"MfDesfirePoller*, MfDesfireKeySettings*" +Function,+,mf_desfire_poller_read_key_versions,MfDesfireError,"MfDesfirePoller*, SimpleArray*, uint32_t" +Function,+,mf_desfire_poller_read_version,MfDesfireError,"MfDesfirePoller*, MfDesfireVersion*" +Function,+,mf_desfire_poller_select_application,MfDesfireError,"MfDesfirePoller*, const MfDesfireApplicationId*" Function,+,mf_desfire_reset,void,MfDesfireData* Function,+,mf_desfire_save,_Bool,"const MfDesfireData*, FlipperFormat*" +Function,+,mf_desfire_send_chunks,MfDesfireError,"MfDesfirePoller*, const BitBuffer*, BitBuffer*" Function,+,mf_desfire_set_uid,_Bool,"MfDesfireData*, const uint8_t*, size_t" Function,+,mf_desfire_verify,_Bool,"MfDesfireData*, const FuriString*" Function,+,mf_ultralight_alloc,MfUltralightData*, @@ -2190,13 +2227,22 @@ Function,+,mf_ultralight_is_counter_configured,_Bool,const MfUltralightData* Function,+,mf_ultralight_is_equal,_Bool,"const MfUltralightData*, const MfUltralightData*" Function,+,mf_ultralight_is_page_pwd_or_pack,_Bool,"MfUltralightType, uint16_t" Function,+,mf_ultralight_load,_Bool,"MfUltralightData*, FlipperFormat*, uint32_t" -Function,+,mf_ultralight_poller_read_card,MfUltralightError,"Nfc*, MfUltralightData*" -Function,+,mf_ultralight_poller_read_counter,MfUltralightError,"Nfc*, uint8_t, MfUltralightCounter*" -Function,+,mf_ultralight_poller_read_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" -Function,+,mf_ultralight_poller_read_signature,MfUltralightError,"Nfc*, MfUltralightSignature*" -Function,+,mf_ultralight_poller_read_tearing_flag,MfUltralightError,"Nfc*, uint8_t, MfUltralightTearingFlag*" -Function,+,mf_ultralight_poller_read_version,MfUltralightError,"Nfc*, MfUltralightVersion*" -Function,+,mf_ultralight_poller_write_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" +Function,+,mf_ultralight_poller_auth_pwd,MfUltralightError,"MfUltralightPoller*, MfUltralightPollerAuthContext*" +Function,+,mf_ultralight_poller_authenticate,MfUltralightError,MfUltralightPoller* +Function,+,mf_ultralight_poller_read_counter,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightCounter*" +Function,+,mf_ultralight_poller_read_page,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightPageReadCommandData*" +Function,+,mf_ultralight_poller_read_page_from_sector,MfUltralightError,"MfUltralightPoller*, uint8_t, uint8_t, MfUltralightPageReadCommandData*" +Function,+,mf_ultralight_poller_read_signature,MfUltralightError,"MfUltralightPoller*, MfUltralightSignature*" +Function,+,mf_ultralight_poller_read_tearing_flag,MfUltralightError,"MfUltralightPoller*, uint8_t, MfUltralightTearingFlag*" +Function,+,mf_ultralight_poller_read_version,MfUltralightError,"MfUltralightPoller*, MfUltralightVersion*" +Function,+,mf_ultralight_poller_sync_read_card,MfUltralightError,"Nfc*, MfUltralightData*" +Function,+,mf_ultralight_poller_sync_read_counter,MfUltralightError,"Nfc*, uint8_t, MfUltralightCounter*" +Function,+,mf_ultralight_poller_sync_read_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" +Function,+,mf_ultralight_poller_sync_read_signature,MfUltralightError,"Nfc*, MfUltralightSignature*" +Function,+,mf_ultralight_poller_sync_read_tearing_flag,MfUltralightError,"Nfc*, uint8_t, MfUltralightTearingFlag*" +Function,+,mf_ultralight_poller_sync_read_version,MfUltralightError,"Nfc*, MfUltralightVersion*" +Function,+,mf_ultralight_poller_sync_write_page,MfUltralightError,"Nfc*, uint16_t, MfUltralightPage*" +Function,+,mf_ultralight_poller_write_page,MfUltralightError,"MfUltralightPoller*, uint8_t, const MfUltralightPage*" Function,+,mf_ultralight_reset,void,MfUltralightData* Function,+,mf_ultralight_save,_Bool,"const MfUltralightData*, FlipperFormat*" Function,+,mf_ultralight_set_uid,_Bool,"MfUltralightData*, const uint8_t*, size_t" @@ -2290,6 +2336,7 @@ Function,+,nfc_poller_free,void,NfcPoller* Function,+,nfc_poller_get_data,const NfcDeviceData*,const NfcPoller* Function,+,nfc_poller_get_protocol,NfcProtocol,const NfcPoller* Function,+,nfc_poller_start,void,"NfcPoller*, NfcGenericCallback, void*" +Function,+,nfc_poller_start_ex,void,"NfcPoller*, NfcGenericCallbackEx, void*" Function,+,nfc_poller_stop,void,NfcPoller* Function,+,nfc_poller_trx,NfcError,"Nfc*, const BitBuffer*, BitBuffer*, uint32_t" Function,+,nfc_protocol_get_parent,NfcProtocol,NfcProtocol @@ -2608,6 +2655,29 @@ Function,+,srand,void,unsigned Function,-,srand48,void,long Function,-,srandom,void,unsigned Function,+,sscanf,int,"const char*, const char*, ..." +Function,+,st25r3916_change_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_change_test_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_check_reg,_Bool,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_clear_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_direct_cmd,void,"FuriHalSpiBusHandle*, uint8_t" +Function,+,st25r3916_get_irq,uint32_t,FuriHalSpiBusHandle* +Function,+,st25r3916_mask_irq,void,"FuriHalSpiBusHandle*, uint32_t" +Function,+,st25r3916_modify_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t, uint8_t" +Function,+,st25r3916_read_burst_regs,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*, uint8_t" +Function,+,st25r3916_read_fifo,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, size_t*" +Function,+,st25r3916_read_pta_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_read_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" +Function,+,st25r3916_read_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" +Function,+,st25r3916_reg_read_fifo,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_reg_write_fifo,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_set_reg_bits,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_write_burst_regs,void,"FuriHalSpiBusHandle*, uint8_t, const uint8_t*, uint8_t" +Function,+,st25r3916_write_fifo,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_pta_mem,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_ptf_mem,void,"FuriHalSpiBusHandle*, const uint8_t*, size_t" +Function,+,st25r3916_write_pttsn_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_t" +Function,+,st25r3916_write_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" +Function,+,st25r3916_write_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" Function,+,st25tb_alloc,St25tbData*, Function,+,st25tb_copy,void,"St25tbData*, const St25tbData*" Function,+,st25tb_free,void,St25tbData* @@ -2617,6 +2687,12 @@ Function,+,st25tb_get_device_name,const char*,"const St25tbData*, NfcDeviceNameT Function,+,st25tb_get_uid,const uint8_t*,"const St25tbData*, size_t*" Function,+,st25tb_is_equal,_Bool,"const St25tbData*, const St25tbData*" Function,+,st25tb_load,_Bool,"St25tbData*, FlipperFormat*, uint32_t" +Function,+,st25tb_poller_activate,St25tbError,"St25tbPoller*, St25tbData*" +Function,+,st25tb_poller_get_uid,St25tbError,"St25tbPoller*, uint8_t*" +Function,+,st25tb_poller_halt,St25tbError,St25tbPoller* +Function,+,st25tb_poller_initiate,St25tbError,"St25tbPoller*, uint8_t*" +Function,+,st25tb_poller_read_block,St25tbError,"St25tbPoller*, uint32_t*, uint8_t" +Function,+,st25tb_poller_send_frame,St25tbError,"St25tbPoller*, const BitBuffer*, BitBuffer*, uint32_t" Function,+,st25tb_reset,void,St25tbData* Function,+,st25tb_save,_Bool,"const St25tbData*, FlipperFormat*" Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t" From 615a1479734ecf2e03626153f60dc267800cc429 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:45:41 +0300 Subject: [PATCH 22/40] [FL-3608] Fix iButton crash on missing file (#3210) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/main/ibutton/ibutton.c | 13 ++++++------- applications/main/ibutton/ibutton_i.h | 2 +- .../main/ibutton/scenes/ibutton_scene_add_value.c | 2 +- .../main/ibutton/scenes/ibutton_scene_rpc.c | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/applications/main/ibutton/ibutton.c b/applications/main/ibutton/ibutton.c index fb6d9dcb52..afd51f7c9e 100644 --- a/applications/main/ibutton/ibutton.c +++ b/applications/main/ibutton/ibutton.c @@ -174,22 +174,21 @@ void ibutton_free(iButton* ibutton) { free(ibutton); } -bool ibutton_load_key(iButton* ibutton) { +bool ibutton_load_key(iButton* ibutton, bool show_error) { view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading); const bool success = ibutton_protocols_load( ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path)); - if(!success) { - dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file"); - - } else { + if(success) { FuriString* tmp = furi_string_alloc(); path_extract_filename(ibutton->file_path, tmp, true); strncpy(ibutton->key_name, furi_string_get_cstr(tmp), IBUTTON_KEY_NAME_SIZE); furi_string_free(tmp); + } else if(show_error) { + dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file"); } return success; @@ -210,7 +209,7 @@ bool ibutton_select_and_load_key(iButton* ibutton) { if(!dialog_file_browser_show( ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options)) break; - success = ibutton_load_key(ibutton); + success = ibutton_load_key(ibutton, true); } while(!success); return success; @@ -283,7 +282,7 @@ int32_t ibutton_app(void* arg) { } else { furi_string_set(ibutton->file_path, (const char*)arg); - key_loaded = ibutton_load_key(ibutton); + key_loaded = ibutton_load_key(ibutton, true); } } diff --git a/applications/main/ibutton/ibutton_i.h b/applications/main/ibutton/ibutton_i.h index 077b148076..c6a35f888b 100644 --- a/applications/main/ibutton/ibutton_i.h +++ b/applications/main/ibutton/ibutton_i.h @@ -90,7 +90,7 @@ typedef enum { } iButtonNotificationMessage; bool ibutton_select_and_load_key(iButton* ibutton); -bool ibutton_load_key(iButton* ibutton); +bool ibutton_load_key(iButton* ibutton, bool show_error); bool ibutton_save_key(iButton* ibutton); bool ibutton_delete_key(iButton* ibutton); void ibutton_reset_key(iButton* ibutton); diff --git a/applications/main/ibutton/scenes/ibutton_scene_add_value.c b/applications/main/ibutton/scenes/ibutton_scene_add_value.c index dc340771b2..71b852115e 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_add_value.c +++ b/applications/main/ibutton/scenes/ibutton_scene_add_value.c @@ -43,7 +43,7 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) { } else if(event.type == SceneManagerEventTypeBack) { // User cancelled editing, reload the key from storage if(scene_manager_has_previous_scene(scene_manager, iButtonSceneSavedKeyMenu)) { - if(!ibutton_load_key(ibutton)) { + if(!ibutton_load_key(ibutton, true)) { consumed = scene_manager_search_and_switch_to_previous_scene( scene_manager, iButtonSceneStart); } diff --git a/applications/main/ibutton/scenes/ibutton_scene_rpc.c b/applications/main/ibutton/scenes/ibutton_scene_rpc.c index 7106fefaa2..f4f193a47e 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_rpc.c +++ b/applications/main/ibutton/scenes/ibutton_scene_rpc.c @@ -26,7 +26,7 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { if(event.event == iButtonCustomEventRpcLoadFile) { bool result = false; - if(ibutton_load_key(ibutton)) { + if(ibutton_load_key(ibutton, false)) { popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop); view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup); From ba074068b0c0c620b6ab13b88c8e294b9d3aaf8d Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:56:13 +0300 Subject: [PATCH 23/40] [FL-3662] Do not remove file when renaming to itself (#3193) * Do not allow overwriting a file with dir and support renaming file to itself * Fix operator precedence error * Add support for storage-specific path equivalence checks * Fix typo * Fix updater compilation * Update Doxygen comments in storage.h Co-authored-by: Aleksandr Kutuzov --- .../storage/filesystem_api_internal.h | 8 + applications/services/storage/storage.h | 593 ++++++++++++------ .../services/storage/storage_external_api.c | 42 +- .../services/storage/storage_message.h | 9 + .../services/storage/storage_processing.c | 50 ++ .../services/storage/storages/storage_ext.c | 11 + .../services/storage/storages/storage_int.c | 5 + targets/f18/api_symbols.csv | 3 +- targets/f7/api_symbols.csv | 3 +- 9 files changed, 508 insertions(+), 216 deletions(-) diff --git a/applications/services/storage/filesystem_api_internal.h b/applications/services/storage/filesystem_api_internal.h index 967d3bb41c..ba98b380e9 100644 --- a/applications/services/storage/filesystem_api_internal.h +++ b/applications/services/storage/filesystem_api_internal.h @@ -165,6 +165,13 @@ typedef struct { * @param total_space pointer to total space value * @param free_space pointer to free space value * @return FS_Error error info + * + * @var FS_Common_Api::equivalent_path + * @brief Test whether two paths are equivalent (e.g differing case on a case-insensitive fs) + * @param path1 first path to be compared + * @param path2 second path to be compared + * @param truncate if set to true, compare only up to the path1's length + * @return true if path1 and path2 are considered equivalent */ typedef struct { FS_Error (*const stat)(void* context, const char* path, FileInfo* fileinfo); @@ -175,6 +182,7 @@ typedef struct { const char* fs_path, uint64_t* total_space, uint64_t* free_space); + bool (*const equivalent_path)(const char* path1, const char* path2); } FS_Common_Api; /** Full filesystem api structure */ diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index 1abc8ed0eb..3caa155c7d 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -1,4 +1,9 @@ +/** + * @file storage.h + * @brief APIs for working with storages, directories and files. + */ #pragma once + #include #include "filesystem_api_defines.h" #include "storage_sd_api.h" @@ -23,43 +28,62 @@ extern "C" { typedef struct Storage Storage; -/** Allocates and initializes a file descriptor - * @return File* +/** + * @brief Allocate and initialize a file instance. + * + * @param storage pointer to a storage API instance. + * @return pointer to the created instance. */ File* storage_file_alloc(Storage* storage); -/** Frees the file descriptor. Closes the file if it was open. +/** + * @brief Free the file instance. + * + * If the file was open, calling this function will close it automatically. + * @param file pointer to the file instance to be freed. */ void storage_file_free(File* file); +/** + * @brief Enumeration of events emitted by the storage through the PubSub system. + */ typedef enum { - StorageEventTypeCardMount, - StorageEventTypeCardUnmount, - StorageEventTypeCardMountError, - StorageEventTypeFileClose, - StorageEventTypeDirClose, + StorageEventTypeCardMount, /**< SD card was mounted. */ + StorageEventTypeCardUnmount, /**< SD card was unmounted. */ + StorageEventTypeCardMountError, /**< An error occurred during mounting of an SD card. */ + StorageEventTypeFileClose, /**< A file was closed. */ + StorageEventTypeDirClose, /**< A directory was closed. */ } StorageEventType; +/** + * @brief Storage event (passed to the PubSub callback). + */ typedef struct { - StorageEventType type; + StorageEventType type; /**< Type of the event. */ } StorageEvent; /** - * Get storage pubsub. + * @brief Get the storage pubsub instance. + * * Storage will send StorageEvent messages. - * @param storage - * @return FuriPubSub* + * + * @param storage pointer to a storage API instance. + * @return pointer to the pubsub instance. */ FuriPubSub* storage_get_pubsub(Storage* storage); /******************* File Functions *******************/ -/** Opens an existing file or create a new one. - * @param file pointer to file object. - * @param path path to file - * @param access_mode access mode from FS_AccessMode +/** + * @brief Open an existing file or create a new one. + * + * @warning The calling code MUST call storage_file_close() even if the open operation had failed. + * + * @param file pointer to the file instance to be opened. + * @param path pointer to a zero-terminated string containing the path to the file to be opened. + * @param access_mode access mode from FS_AccessMode. * @param open_mode open mode from FS_OpenMode - * @return success flag. You need to close the file even if the open operation failed. + * @return true if the file was successfully opened, false otherwise. */ bool storage_file_open( File* file, @@ -67,202 +91,267 @@ bool storage_file_open( FS_AccessMode access_mode, FS_OpenMode open_mode); -/** Close the file. - * @param file pointer to a file object, the file object will be freed. - * @return success flag +/** + * @brief Close the file. + * + * @param file pointer to the file instance to be closed. + * @return true if the file was successfully closed, false otherwise. */ bool storage_file_close(File* file); -/** Tells if the file is open - * @param file pointer to a file object - * @return bool true if file is open +/** + * @brief Check whether the file is open. + * + * @param file pointer to the file instance in question. + * @return true if the file is open, false otherwise. */ bool storage_file_is_open(File* file); -/** Tells if the file is a directory - * @param file pointer to a file object - * @return bool true if file is a directory +/** + * @brief Check whether a file instance represents a directory. + * + * @param file pointer to the file instance in question. + * @return true if the file instance represents a directory, false otherwise. */ bool storage_file_is_dir(File* file); -/** Reads bytes from a file into a buffer - * @param file pointer to file object. - * @param buff pointer to a buffer, for reading - * @param bytes_to_read how many bytes to read. Must be less than or equal to the size of the buffer. - * @return uint16_t how many bytes were actually read +/** + * @brief Read bytes from a file into a buffer. + * + * @param file pointer to the file instance to read from. + * @param buff pointer to the buffer to be filled with read data. + * @param bytes_to_read number of bytes to read. Must be less than or equal to the size of the buffer. + * @return actual number of bytes read (may be fewer than requested). */ uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read); -/** Writes bytes from a buffer to a file - * @param file pointer to file object. - * @param buff pointer to buffer, for writing - * @param bytes_to_write how many bytes to write. Must be less than or equal to the size of the buffer. - * @return uint16_t how many bytes were actually written +/** + * @brief Write bytes from a buffer to a file. + * + * @param file pointer to the file instance to write into. + * @param buff pointer to the buffer containing the data to be written. + * @param bytes_to_write number of bytes to write. Must be less than or equal to the size of the buffer. + * @return actual number of bytes written (may be fewer than requested). */ uint16_t storage_file_write(File* file, const void* buff, uint16_t bytes_to_write); -/** Moves the r/w pointer - * @param file pointer to file object. - * @param offset offset to move the r/w pointer - * @param from_start set an offset from the start or from the current position +/** + * @brief Change the current access position in a file. + * + * @param file pointer to the file instance in question. + * @param offset access position offset (meaning depends on from_start parameter). + * @param from_start if true, set the access position relative to the file start, otherwise relative to the current position. * @return success flag */ bool storage_file_seek(File* file, uint32_t offset, bool from_start); -/** Gets the position of the r/w pointer - * @param file pointer to file object. - * @return uint64_t position of the r/w pointer +/** + * @brief Get the current access position. + * + * @param file pointer to the file instance in question. + * @return current access position. */ uint64_t storage_file_tell(File* file); -/** Truncates the file size to the current position of the r/w pointer - * @param file pointer to file object. - * @return bool success flag +/** + * @brief Truncate the file size to the current access position. + * + * @param file pointer to the file instance to be truncated. + * @return true if the file was successfully truncated, false otherwise. */ bool storage_file_truncate(File* file); -/** Gets the size of the file - * @param file pointer to file object. - * @return uint64_t size of the file +/** + * @brief Get the file size. + * + * @param file pointer to the file instance in question. + * @return size of the file, in bytes. */ uint64_t storage_file_size(File* file); -/** Writes file cache to storage - * @param file pointer to file object. - * @return bool success flag +/** + * @brief Synchronise the file cache with the actual storage. + * + * @param file pointer to the file instance in question. + * @return true if the file was successfully synchronised, false otherwise. */ bool storage_file_sync(File* file); -/** Checks that the r/w pointer is at the end of the file - * @param file pointer to file object. - * @return bool success flag +/** + * @brief Check whether the current access position is at the end of the file. + * + * @param file pointer to a file instance in question. + * @return bool true if the current access position is at the end of the file, false otherwise. */ bool storage_file_eof(File* file); /** - * @brief Check that file exists + * @brief Check whether a file exists. * - * @param storage - * @param path - * @return true if file exists + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path to the file in question. + * @return true if the file exists, false otherwise. */ bool storage_file_exists(Storage* storage, const char* path); /** - * @brief Copy data from one opened file to another opened file - * Size bytes will be copied from current position of source file to current position of destination file + * @brief Copy data from a source file to the destination file. + * + * Both files must be opened prior to calling this function. + * + * The requested amount of bytes will be copied from the current access position + * in the source file to the current access position in the destination file. * - * @param source source file - * @param destination destination file - * @param size size of data to copy - * @return bool success flag + * @param source pointer to a source file instance. + * @param destination pointer to a destination file instance. + * @param size data size to be copied, in bytes. + * @return true if the data was successfully copied, false otherwise. */ bool storage_file_copy_to_file(File* source, File* destination, uint32_t size); -/******************* Dir Functions *******************/ +/******************* Directory Functions *******************/ -/** Opens a directory to get objects from it - * @param app pointer to the api - * @param file pointer to file object. - * @param path path to directory - * @return bool success flag. You need to close the directory even if the open operation failed. +/** + * @brief Open a directory. + * + * Opening a directory is necessary to be able to read its contents with storage_dir_read(). + * + * @warning The calling code MUST call storage_dir_close() even if the open operation had failed. + * + * @param file pointer to a file instance representing the directory in question. + * @param path pointer to a zero-terminated string containing the path of the directory in question. + * @return true if the directory was successfully opened, false otherwise. */ bool storage_dir_open(File* file, const char* path); -/** Close the directory. Also free file handle structure and point it to the NULL. - * @param file pointer to a file object. - * @return bool success flag +/** + * @brief Close the directory. + * + * @param file pointer to a file instance representing the directory in question. + * @return true if the directory was successfully closed, false otherwise. */ bool storage_dir_close(File* file); -/** Reads the next object in the directory - * @param file pointer to file object. - * @param fileinfo pointer to the read FileInfo, may be NULL - * @param name pointer to name buffer, may be NULL - * @param name_length name buffer length - * @return success flag (if the next object does not exist, it also returns false and sets the file error id to FSE_NOT_EXIST) +/** + * @brief Get the next item in the directory. + * + * If the next object does not exist, this function returns false as well + * and sets the file error id to FSE_NOT_EXIST. + * + * @param file pointer to a file instance representing the directory in question. + * @param fileinfo pointer to the FileInfo structure to contain the info (may be NULL). + * @param name pointer to the buffer to contain the name (may be NULL). + * @param name_length maximum capacity of the name buffer, in bytes. + * @return true if the next item was successfully read, false otherwise. */ bool storage_dir_read(File* file, FileInfo* fileinfo, char* name, uint16_t name_length); -/** Rewinds the read pointer to first item in the directory - * @param file pointer to file object. - * @return bool success flag +/** + * @brief Change the access position to first item in the directory. + * + * @param file pointer to a file instance representing the directory in question. + * @return true if the access position was successfully changed, false otherwise. */ bool storage_dir_rewind(File* file); /** - * @brief Check that dir exists + * @brief Check whether a directory exists. * - * @param storage - * @param path - * @return bool + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path of the directory in question. + * @return true if the directory exists, false otherwise. */ bool storage_dir_exists(Storage* storage, const char* path); /******************* Common Functions *******************/ -/** Retrieves unix timestamp of last access +/** + * @brief Get the last access time in UNIX format. * - * @param storage The storage instance - * @param path path to file/directory - * @param timestamp the timestamp pointer - * - * @return FS_Error operation result + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path of the item in question. + * @param timestamp pointer to a value to contain the timestamp. + * @return FSE_OK if the timestamp has been successfully received, any other error code on failure. */ FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t* timestamp); -/** Retrieves information about a file/directory - * @param app pointer to the api - * @param path path to file/directory - * @param fileinfo pointer to the read FileInfo, may be NULL - * @return FS_Error operation result +/** + * @brief Get information about a file or a directory. + * + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path of the item in question. + * @param fileinfo pointer to the FileInfo structure to contain the info (may be NULL). + * @return FSE_OK if the info has been successfully received, any other error code on failure. */ FS_Error storage_common_stat(Storage* storage, const char* path, FileInfo* fileinfo); -/** Removes a file/directory from the repository, the directory must be empty and the file/directory must not be open - * @param app pointer to the api - * @param path - * @return FS_Error operation result +/** + * @brief Remove a file or a directory. + * + * The directory must be empty. + * The file or the directory must NOT be open. + * + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path of the item to be removed. + * @return FSE_OK if the file or directory has been successfully removed, any other error code on failure. */ FS_Error storage_common_remove(Storage* storage, const char* path); -/** Renames file/directory, file/directory must not be open. Will overwrite existing file. - * @param app pointer to the api - * @param old_path old path - * @param new_path new path - * @return FS_Error operation result +/** + * @brief Rename a file or a directory. + * + * The file or the directory must NOT be open. + * Will overwrite the destination file if it already exists. + * + * Renaming a regular file to itself does nothing and always succeeds. + * Renaming a directory to itself or to a subdirectory of itself always fails. + * + * @param storage pointer to a storage API instance. + * @param old_path pointer to a zero-terminated string containing the source path. + * @param new_path pointer to a zero-terminated string containing the destination path. + * @return FSE_OK if the file or directory has been successfully renamed, any other error code on failure. */ FS_Error storage_common_rename(Storage* storage, const char* old_path, const char* new_path); -/** Copy file, file must not be open - * @param app pointer to the api - * @param old_path old path - * @param new_path new path - * @return FS_Error operation result +/** + * @brief Copy the file to a new location. + * + * The file must NOT be open at the time of calling this function. + * + * @param storage pointer to a storage API instance. + * @param old_path pointer to a zero-terminated string containing the source path. + * @param new_path pointer to a zero-terminated string containing the destination path. + * @return FSE_OK if the file has been successfully copied, any other error code on failure. */ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path); -/** Copy one folder contents into another with rename of all conflicting files - * @param app pointer to the api - * @param old_path old path - * @param new_path new path - * @return FS_Error operation result +/** + * @brief Copy the contents of one directory into another and rename all conflicting files. + * + * @param storage pointer to a storage API instance. + * @param old_path pointer to a zero-terminated string containing the source path. + * @param new_path pointer to a zero-terminated string containing the destination path. + * @return FSE_OK if the directories have been successfully merged, any other error code on failure. */ FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path); -/** Creates a directory - * @param app pointer to the api - * @param path directory path - * @return FS_Error operation result +/** + * @brief Create a directory. + * + * @param storage pointer to a storage API instance. + * @param fs_path pointer to a zero-terminated string containing the directory path. + * @return FSE_OK if the directory has been successfully created, any other error code on failure. */ FS_Error storage_common_mkdir(Storage* storage, const char* path); -/** Gets general information about the storage - * @param app pointer to the api - * @param fs_path the path to the storage of interest - * @param total_space pointer to total space record, will be filled - * @param free_space pointer to free space record, will be filled - * @return FS_Error operation result +/** + * @brief Get the general information about the storage. + * + * @param storage pointer to a storage API instance. + * @param fs_path pointer to a zero-terminated string containing the path to the storage question. + * @param total_space pointer to the value to contain the total capacity, in bytes. + * @param free_space pointer to the value to contain the available space, in bytes. + * @return FSE_OK if the information has been successfully received, any other error code on failure. */ FS_Error storage_common_fs_info( Storage* storage, @@ -271,150 +360,242 @@ FS_Error storage_common_fs_info( uint64_t* free_space); /** - * @brief Parse aliases in path and replace them with real path - * Also will create special folders if they are not exist + * @brief Parse aliases in a path and replace them with the real path. + * + * Necessary special directories will be created automatically if they did not exist. * - * @param storage - * @param path - * @return bool + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path in question. + * @return true if the path was successfully resolved, false otherwise. */ void storage_common_resolve_path_and_ensure_app_directory(Storage* storage, FuriString* path); /** - * @brief Move content of one folder to another, with rename of all conflicting files. - * Source folder will be deleted if the migration is successful. + * @brief Move the contents of source folder to destination one and rename all conflicting files. + * + * Source folder will be deleted if the migration was successful. * - * @param storage - * @param source - * @param dest - * @return FS_Error + * @param storage pointer to a storage API instance. + * @param source pointer to a zero-terminated string containing the source path. + * @param dest pointer to a zero-terminated string containing the destination path. + * @return FSE_OK if the migration was successfull completed, any other error code on failure. */ FS_Error storage_common_migrate(Storage* storage, const char* source, const char* dest); /** - * @brief Check that file or dir exists + * @brief Check whether a file or a directory exists. * - * @param storage - * @param path - * @return bool + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the path in question. + * @return true if a file or a directory exists, false otherwise. */ bool storage_common_exists(Storage* storage, const char* path); +/** + * @brief Check whether two paths are equivalent. + * + * This function will resolve aliases and apply filesystem-specific + * rules to determine whether the two given paths are equivalent. + * + * Examples: + * - /int/text and /ext/test -> false (Different storages), + * - /int/Test and /int/test -> false (Case-sensitive storage), + * - /ext/Test and /ext/test -> true (Case-insensitive storage). + * + * If the truncate parameter is set to true, the second path will be + * truncated to be no longer than the first one. It is useful to determine + * whether path2 is a subdirectory of path1. + * + * @param storage pointer to a storage API instance. + * @param path1 pointer to a zero-terminated string containing the first path. + * @param path2 pointer to a zero-terminated string containing the second path. + * @param truncate whether to truncate path2 to be no longer than path1. + * @return true if paths are equivalent, false otherwise. + */ +bool storage_common_equivalent_path( + Storage* storage, + const char* path1, + const char* path2, + bool truncate); + /******************* Error Functions *******************/ -/** Retrieves the error text from the error id - * @param error_id error id - * @return const char* error text +/** + * @brief Get the textual description of a numeric error identifer. + * + * @param error_id numeric identifier of the error in question. + * @return pointer to a statically allocated zero-terminated string containing the respective error text. */ const char* storage_error_get_desc(FS_Error error_id); -/** Retrieves the error id from the file object - * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETRIEVE THE ERROR ID IF THE FILE HAS BEEN CLOSED - * @return FS_Error error id +/** + * @brief Get the numeric error identifier from a file instance. + * + * @warning It is not possible to get the error identifier after the file has been closed. + * + * @param file pointer to the file instance in question (must NOT be NULL). + * @return numeric identifier of the last error associated with the file instance. */ FS_Error storage_file_get_error(File* file); -/** Retrieves the internal (storage-specific) error id from the file object - * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETRIEVE THE INTERNAL ERROR ID IF THE FILE HAS BEEN CLOSED - * @return FS_Error error id +/** + * @brief Get the internal (storage-specific) numeric error identifier from a file instance. + * + * @warning It is not possible to get the internal error identifier after the file has been closed. + * + * @param file pointer to the file instance in question (must NOT be NULL). + * @return numeric identifier of the last internal error associated with the file instance. */ int32_t storage_file_get_internal_error(File* file); -/** Retrieves the error text from the file object - * @param file pointer to file object. Pointer must not point to NULL. YOU CANNOT RETRIEVE THE ERROR TEXT IF THE FILE HAS BEEN CLOSED - * @return const char* error text +/** + * @brief Get the textual description of a the last error associated with a file instance. + * + * @warning It is not possible to get the error text after the file has been closed. + * + * @param file pointer to the file instance in question (must NOT be NULL). + * @return pointer to a statically allocated zero-terminated string containing the respective error text. */ const char* storage_file_get_error_desc(File* file); /******************* SD Card Functions *******************/ -/** Formats SD Card - * @param api pointer to the api - * @return FS_Error operation result +/** + * @brief Format the SD Card. + * + * @param storage pointer to a storage API instance. + * @return FSE_OK if the card was successfully formatted, any other error code on failure. */ -FS_Error storage_sd_format(Storage* api); +FS_Error storage_sd_format(Storage* storage); -/** Will unmount the SD card. - * Will return FSE_NOT_READY if the SD card is not mounted. - * Will return FSE_DENIED if there are open files on the SD card. - * @param api pointer to the api - * @return FS_Error operation result +/** + * @brief Unmount the SD card. + * + * These return values have special meaning: + * - FSE_NOT_READY if the SD card is not mounted. + * - FSE_DENIED if there are open files on the SD card. + * + * @param storage pointer to a storage API instance. + * @return FSE_OK if the card was successfully formatted, any other error code on failure. */ -FS_Error storage_sd_unmount(Storage* api); +FS_Error storage_sd_unmount(Storage* storage); -/** Will mount the SD card - * @param api pointer to the api - * @return FS_Error operation result +/** + * @brief Mount the SD card. + * + * @param storage pointer to a storage API instance. + * @return FSE_OK if the card was successfully mounted, any other error code on failure. */ -FS_Error storage_sd_mount(Storage* api); +FS_Error storage_sd_mount(Storage* storage); -/** Retrieves SD card information - * @param api pointer to the api - * @param info pointer to the info - * @return FS_Error operation result +/** + * @brief Get SD card information. + * + * @param storage pointer to a storage API instance. + * @param info pointer to the info object to contain the requested information. + * @return FSE_OK if the info was successfully received, any other error code on failure. */ -FS_Error storage_sd_info(Storage* api, SDInfo* info); +FS_Error storage_sd_info(Storage* storage, SDInfo* info); -/** Retrieves SD card status - * @param api pointer to the api - * @return FS_Error operation result +/** + * @brief Get SD card status. + * + * @param storage pointer to a storage API instance. + * @return storage status in the form of a numeric error identifier. */ -FS_Error storage_sd_status(Storage* api); +FS_Error storage_sd_status(Storage* storage); /******************* Internal LFS Functions *******************/ typedef void (*Storage_name_converter)(FuriString*); -/** Backs up internal storage to a tar archive - * @param api pointer to the api - * @param dstmane destination archive path - * @return FS_Error operation result +/** + * @brief Back up the internal storage contents to a *.tar archive. + * + * @param storage pointer to a storage API instance. + * @param dstname pointer to a zero-terminated string containing the archive file path. + * @return FSE_OK if the storage was successfully backed up, any other error code on failure. */ -FS_Error storage_int_backup(Storage* api, const char* dstname); +FS_Error storage_int_backup(Storage* storage, const char* dstname); -/** Restores internal storage from a tar archive - * @param api pointer to the api - * @param dstmane archive path - * @param converter pointer to filename conversion function, may be NULL - * @return FS_Error operation result +/** + * @brief Restore the internal storage contents from a *.tar archive. + * + * @param storage pointer to a storage API instance. + * @param dstname pointer to a zero-terminated string containing the archive file path. + * @param converter pointer to a filename conversion function (may be NULL). + * @return FSE_OK if the storage was successfully restored, any other error code on failure. */ FS_Error storage_int_restore(Storage* api, const char* dstname, Storage_name_converter converter); /***************** Simplified Functions ******************/ /** - * Removes a file/directory, the directory must be empty and the file/directory must not be open - * @param storage pointer to the api - * @param path - * @return true on success or if file/dir is not exist + * @brief Remove a file or a directory. + * + * The following conditions must be met: + * - the directory must be empty. + * - the file or the directory must NOT be open. + * + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the item path. + * @return true on success or if the item does not exist, false otherwise. */ bool storage_simply_remove(Storage* storage, const char* path); /** - * Recursively removes a file/directory, the directory can be not empty - * @param storage pointer to the api - * @param path - * @return true on success or if file/dir is not exist + * @brief Recursively remove a file or a directory. + * + * Unlike storage_simply_remove(), the directory does not need to be empty. + * + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the item path. + * @return true on success or if the item does not exist, false otherwise. */ bool storage_simply_remove_recursive(Storage* storage, const char* path); /** - * Creates a directory - * @param storage - * @param path - * @return true on success or if directory is already exist + * @brief Create a directory. + * + * @param storage pointer to a storage API instance. + * @param path pointer to a zero-terminated string containing the directory path. + * @return true on success or if directory does already exist, false otherwise. */ bool storage_simply_mkdir(Storage* storage, const char* path); /** - * @brief Get next free filename. + * @brief Get the next free filename in a directory. + * + * Usage example: + * ```c + * FuriString* file_name = furi_string_alloc(); + * Storage* storage = furi_record_open(RECORD_STORAGE); + * + * storage_get_next_filename(storage, + * "/ext/test", + * "cookies", + * ".yum", + * 20); + * + * furi_record_close(RECORD_STORAGE); + * + * use_file_name(file_name); + * + * furi_string_free(file_name); + * ``` + * Possible file_name values after calling storage_get_next_filename(): + * "cookies", "cookies1", "cookies2", ... etc depending on whether any of + * these files have already existed in the directory. + * + * @note If the resulting next file name length is greater than set by the max_len + * parameter, the original filename will be returned instead. * - * @param storage - * @param dirname - * @param filename - * @param fileextension - * @param nextfilename return name - * @param max_len max len name + * @param storage pointer to a storage API instance. + * @param dirname pointer to a zero-terminated string containing the directory path. + * @param filename pointer to a zero-terminated string containing the file name. + * @param fileextension pointer to a zero-terminated string containing the file extension. + * @param nextfilename pointer to a dynamic string containing the resulting file name. + * @param max_len maximum length of the new name. */ void storage_get_next_filename( Storage* storage, diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index ed69b49a57..1027d43101 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -431,17 +431,22 @@ FS_Error storage_common_rename(Storage* storage, const char* old_path, const cha } if(storage_dir_exists(storage, old_path)) { - FuriString* dir_path = furi_string_alloc_set_str(old_path); - if(!furi_string_end_with_str(dir_path, "/")) { - furi_string_cat_str(dir_path, "/"); - } - const char* dir_path_s = furi_string_get_cstr(dir_path); - if(strncmp(new_path, dir_path_s, strlen(dir_path_s)) == 0) { + // Cannot overwrite a file with a directory + if(storage_file_exists(storage, new_path)) { error = FSE_INVALID_NAME; - furi_string_free(dir_path); break; } - furi_string_free(dir_path); + + // Cannot rename a directory to itself or to a nested directory + if(storage_common_equivalent_path(storage, old_path, new_path, true)) { + error = FSE_INVALID_NAME; + break; + } + + // Renaming a regular file to itself does nothing and always succeeds + } else if(storage_common_equivalent_path(storage, old_path, new_path, false)) { + error = FSE_OK; + break; } if(storage_file_exists(storage, new_path)) { @@ -742,6 +747,27 @@ bool storage_common_exists(Storage* storage, const char* path) { return storage_common_stat(storage, path, &file_info) == FSE_OK; } +bool storage_common_equivalent_path( + Storage* storage, + const char* path1, + const char* path2, + bool truncate) { + S_API_PROLOGUE; + + SAData data = { + .cequivpath = { + .path1 = path1, + .path2 = path2, + .truncate = truncate, + .thread_id = furi_thread_get_current_id(), + }}; + + S_API_MESSAGE(StorageCommandCommonEquivalentPath); + S_API_EPILOGUE; + + return S_RETURN_BOOL; +} + /****************** ERROR ******************/ const char* storage_error_get_desc(FS_Error error_id) { diff --git a/applications/services/storage/storage_message.h b/applications/services/storage/storage_message.h index 01bc203801..cd45906d4a 100644 --- a/applications/services/storage/storage_message.h +++ b/applications/services/storage/storage_message.h @@ -69,6 +69,13 @@ typedef struct { FuriThreadId thread_id; } SADataCResolvePath; +typedef struct { + const char* path1; + const char* path2; + bool truncate; + FuriThreadId thread_id; +} SADataCEquivPath; + typedef struct { uint32_t id; } SADataError; @@ -99,6 +106,7 @@ typedef union { SADataCStat cstat; SADataCFSInfo cfsinfo; SADataCResolvePath cresolvepath; + SADataCEquivPath cequivpath; SADataError error; @@ -142,6 +150,7 @@ typedef enum { StorageCommandSDStatus, StorageCommandCommonResolvePath, StorageCommandSDMount, + StorageCommandCommonEquivalentPath, } StorageCommand; typedef struct { diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index 00126af6f3..9e96765b62 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -98,6 +98,12 @@ static FS_Error storage_get_data(Storage* app, FuriString* path, StorageData** s } } +static void storage_path_trim_trailing_slashes(FuriString* path) { + while(furi_string_end_with(path, "/")) { + furi_string_left(path, furi_string_size(path) - 1); + } +} + /******************* File Functions *******************/ bool storage_process_file_open( @@ -357,6 +363,8 @@ static FS_Error storage_process_common_remove(Storage* app, FuriString* path) { FS_Error ret = storage_get_data(app, path, &storage); do { + if(ret != FSE_OK) break; + if(storage_path_already_open(path, storage)) { ret = FSE_ALREADY_OPEN; break; @@ -398,6 +406,31 @@ static FS_Error storage_process_common_fs_info( return ret; } +static bool + storage_process_common_equivalent_path(Storage* app, FuriString* path1, FuriString* path2) { + bool ret = false; + + do { + const StorageType storage_type1 = storage_get_type_by_path(path1); + const StorageType storage_type2 = storage_get_type_by_path(path2); + + // Paths on different storages are of course not equal + if(storage_type1 != storage_type2) break; + + StorageData* storage; + const FS_Error status = storage_get_data(app, path1, &storage); + + if(status != FSE_OK) break; + + FS_CALL( + storage, + common.equivalent_path(furi_string_get_cstr(path1), furi_string_get_cstr(path2))); + + } while(false); + + return ret; +} + /****************** Raw SD API ******************/ // TODO FL-3521: think about implementing a custom storage API to split that kind of api linkage #include "storages/storage_ext.h" @@ -649,6 +682,23 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) { app, message->data->cresolvepath.path, message->data->cresolvepath.thread_id, true); break; + case StorageCommandCommonEquivalentPath: { + FuriString* path1 = furi_string_alloc_set(message->data->cequivpath.path1); + FuriString* path2 = furi_string_alloc_set(message->data->cequivpath.path2); + storage_path_trim_trailing_slashes(path1); + storage_path_trim_trailing_slashes(path2); + storage_process_alias(app, path1, message->data->cequivpath.thread_id, false); + storage_process_alias(app, path2, message->data->cequivpath.thread_id, false); + if(message->data->cequivpath.truncate) { + furi_string_left(path2, furi_string_size(path1)); + } + message->return_data->bool_value = + storage_process_common_equivalent_path(app, path1, path2); + furi_string_free(path1); + furi_string_free(path2); + break; + } + // SD operations case StorageCommandSDFormat: message->return_data->error_value = storage_process_sd_format(app); diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index 4630d99ea7..7e617c0ff2 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -596,6 +596,16 @@ static FS_Error storage_ext_common_fs_info( #endif } +static bool storage_ext_common_equivalent_path(const char* path1, const char* path2) { +#ifdef FURI_RAM_EXEC + UNUSED(path1); + UNUSED(path2); + return false; +#else + return strcasecmp(path1, path2) == 0; +#endif +} + /******************* Init Storage *******************/ static const FS_Api fs_api = { .file = @@ -624,6 +634,7 @@ static const FS_Api fs_api = { .mkdir = storage_ext_common_mkdir, .remove = storage_ext_common_remove, .fs_info = storage_ext_common_fs_info, + .equivalent_path = storage_ext_common_equivalent_path, }, }; diff --git a/applications/services/storage/storages/storage_int.c b/applications/services/storage/storages/storage_int.c index 2534d47a11..39b092c1d1 100644 --- a/applications/services/storage/storages/storage_int.c +++ b/applications/services/storage/storages/storage_int.c @@ -686,6 +686,10 @@ static FS_Error storage_int_common_fs_info( return storage_int_parse_error(result); } +static bool storage_int_common_equivalent_path(const char* path1, const char* path2) { + return strcmp(path1, path2) == 0; +} + /******************* Init Storage *******************/ static const FS_Api fs_api = { .file = @@ -714,6 +718,7 @@ static const FS_Api fs_api = { .mkdir = storage_int_common_mkdir, .remove = storage_int_common_remove, .fs_info = storage_int_common_fs_info, + .equivalent_path = storage_int_common_equivalent_path, }, }; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 44829c264d..8ed8f403c7 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,45.0,, +Version,+,45.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -2071,6 +2071,7 @@ Function,+,st25r3916_write_pttsn_mem,void,"FuriHalSpiBusHandle*, uint8_t*, size_ Function,+,st25r3916_write_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" Function,+,st25r3916_write_test_reg,void,"FuriHalSpiBusHandle*, uint8_t, uint8_t" Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_equivalent_path,_Bool,"Storage*, const char*, const char*, _Bool" Function,+,storage_common_exists,_Bool,"Storage*, const char*" Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 514f332868..64695c2dbc 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,45.0,, +Version,+,45.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2698,6 +2698,7 @@ Function,+,st25tb_save,_Bool,"const St25tbData*, FlipperFormat*" Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t" Function,+,st25tb_verify,_Bool,"St25tbData*, const FuriString*" Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" +Function,+,storage_common_equivalent_path,_Bool,"Storage*, const char*, const char*, _Bool" Function,+,storage_common_exists,_Bool,"Storage*, const char*" Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" Function,+,storage_common_merge,FS_Error,"Storage*, const char*, const char*" From a61b5d4b4cd7f11f4b836ba085860f58689905b8 Mon Sep 17 00:00:00 2001 From: Flipper Zelebro <149575765+flipperzelebro@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:04:45 +0100 Subject: [PATCH 24/40] Add Mastercode SubGHz Protocol (#3187) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Mastercode SubGHz Protocol * Add 2 valid raw files and cleanup code * Add tests to the two Raw Files * Remove extra test & delete comments * Fixes pulse length and shows correct Key Co-authored-by: FlipperZelebro Co-authored-by: あく --- .../unit_tests/subghz/mastercode.sub | 7 + .../unit_tests/subghz/mastercode_raw.sub | 6 + .../debug/unit_tests/subghz/subghz_test.c | 15 + lib/subghz/protocols/mastercode.c | 360 ++++++++++++++++++ lib/subghz/protocols/mastercode.h | 109 ++++++ lib/subghz/protocols/protocol_items.c | 1 + lib/subghz/protocols/protocol_items.h | 1 + 7 files changed, 499 insertions(+) create mode 100644 applications/debug/unit_tests/resources/unit_tests/subghz/mastercode.sub create mode 100644 applications/debug/unit_tests/resources/unit_tests/subghz/mastercode_raw.sub create mode 100644 lib/subghz/protocols/mastercode.c create mode 100644 lib/subghz/protocols/mastercode.h diff --git a/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode.sub new file mode 100644 index 0000000000..f50abbfe8f --- /dev/null +++ b/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode.sub @@ -0,0 +1,7 @@ +Filetype: Flipper SubGhz Key File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok270Async +Protocol: Mastercode +Bit: 36 +Key: 00 00 00 0B 7E 00 3C 08 diff --git a/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode_raw.sub b/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode_raw.sub new file mode 100644 index 0000000000..69d3f396cd --- /dev/null +++ b/applications/debug/unit_tests/resources/unit_tests/subghz/mastercode_raw.sub @@ -0,0 +1,6 @@ +Filetype: Flipper SubGhz RAW File +Version: 1 +Frequency: 433920000 +Preset: FuriHalSubGhzPresetOok270Async +Protocol: RAW +RAW_Data: 10389 -66 405095 -102 207 -106 1165 -130 963739 -1232 899 -2250 2003 -1190 2017 -1202 911 -2256 2021 -1162 2045 -1134 2047 -1164 2047 -1138 2031 -1180 2039 -1182 949 -2190 995 -2214 961 -2228 963 -2198 963 -2214 977 -2212 975 -2210 975 -2208 971 -2200 963 -2210 993 -2184 2075 -1130 2051 -1142 2055 -1136 2047 -1178 965 -2236 933 -2220 975 -2184 999 -2222 967 -2208 969 -2214 979 -2202 2027 -1156 975 -2242 943 -16080 2023 -1162 967 -2220 2057 -1114 2061 -1124 1007 -2242 2025 -1134 2055 -1168 2017 -1138 2075 -1134 2053 -1136 2075 -1130 979 -2214 979 -2174 999 -2182 1001 -2204 977 -2206 1003 -2188 979 -2176 999 -2182 1009 -2176 1009 -2176 1001 -2212 2029 -1116 2091 -1102 2109 -1092 2095 -1126 1001 -2150 1011 -2180 1011 -2180 1009 -2178 1009 -2172 1009 -2166 1001 -2198 2065 -1136 975 -2220 971 -16018 2097 -1166 951 -2240 2009 -1186 2011 -1160 979 -2208 2035 -1134 2053 -1138 2061 -1158 2045 -1152 2029 -1152 2051 -1166 963 -2188 993 -2222 951 -2214 963 -2220 965 -2212 979 -2212 977 -2180 1003 -2202 965 -2218 975 -2216 967 -2188 2061 -1124 2083 -1126 2071 -1130 2059 -1134 993 -2188 979 -2240 947 -2204 979 -2214 971 -2214 973 -2210 971 -2206 2053 -1130 979 -2216 969 -16056 2053 -1134 1001 -2224 2021 -1150 2051 -1154 953 -2240 2045 -1146 2023 -1168 2033 -1144 2065 -1146 2055 -1130 2071 -1160 961 -2192 973 -2190 1005 -2214 975 -2206 967 -2206 975 -2206 967 -2208 975 -2212 967 -2212 979 -2218 977 -2178 2063 -1156 2035 -1160 2061 -1126 2065 -1130 981 -2186 1003 -2210 977 -2208 973 -2202 977 -2200 965 -2248 943 -2206 2039 -1190 941 -48536 65 -7254 263 -68 363 -102 131 -232 263 -264 751 -230 225 -822 397 -634 231 -268 263 -134 267 -64 867 -132 305 -138 67 -100 331 -98 891 -66 455 -66 531 -100 299 -134 897 -98 693 -132 291 -132 333 -98 337 -68 331 diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index 64e0591dfa..2f2b9e9811 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -654,6 +654,13 @@ MU_TEST(subghz_decoder_kinggates_stylo4k_test) { "Test decoder " SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME " error\r\n"); } +MU_TEST(subghz_decoder_mastercode_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/mastercode_raw.sub"), SUBGHZ_PROTOCOL_MASTERCODE_NAME), + "Test decoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -805,6 +812,12 @@ MU_TEST(subghz_encoder_dooya_test) { "Test encoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n"); } +MU_TEST(subghz_encoder_mastercode_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/mastercode.sub")), + "Test encoder " SUBGHZ_PROTOCOL_MASTERCODE_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -855,6 +868,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_alutech_at_4n_test); MU_RUN_TEST(subghz_decoder_nice_one_test); MU_RUN_TEST(subghz_decoder_kinggates_stylo4k_test); + MU_RUN_TEST(subghz_decoder_mastercode_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -881,6 +895,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_smc5326_test); MU_RUN_TEST(subghz_encoder_holtek_ht12x_test); MU_RUN_TEST(subghz_encoder_dooya_test); + MU_RUN_TEST(subghz_encoder_mastercode_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/lib/subghz/protocols/mastercode.c b/lib/subghz/protocols/mastercode.c new file mode 100644 index 0000000000..54ad5bfaa4 --- /dev/null +++ b/lib/subghz/protocols/mastercode.c @@ -0,0 +1,360 @@ +#include "mastercode.h" + +#include "../blocks/const.h" +#include "../blocks/decoder.h" +#include "../blocks/encoder.h" +#include "../blocks/generic.h" +#include "../blocks/math.h" + +// protocol MASTERCODE Clemsa MV1/MV12 +#define TAG "SubGhzProtocolMastercode" + +#define DIP_P 0b11 //(+) +#define DIP_O 0b10 //(0) +#define DIP_N 0b00 //(-) + +#define DIP_PATTERN "%c%c%c%c%c%c%c%c" + +#define SHOW_DIP_P(dip, check_dip) \ + ((((dip >> 0x0) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x2) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x4) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x6) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0x8) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xA) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xC) & 0x3) == check_dip) ? '*' : '_'), \ + ((((dip >> 0xE) & 0x3) == check_dip) ? '*' : '_') + +static const SubGhzBlockConst subghz_protocol_mastercode_const = { + .te_short = 1072, + .te_long = 2145, + .te_delta = 150, + .min_count_bit_for_found = 36, +}; + +struct SubGhzProtocolDecoderMastercode { + SubGhzProtocolDecoderBase base; + SubGhzBlockDecoder decoder; + SubGhzBlockGeneric generic; +}; + +struct SubGhzProtocolEncoderMastercode { + SubGhzProtocolEncoderBase base; + SubGhzProtocolBlockEncoder encoder; + SubGhzBlockGeneric generic; +}; + +typedef enum { + MastercodeDecoderStepReset = 0, + MastercodeDecoderStepSaveDuration, + MastercodeDecoderStepCheckDuration, +} MastercodeDecoderStep; + +const SubGhzProtocolDecoder subghz_protocol_mastercode_decoder = { + .alloc = subghz_protocol_decoder_mastercode_alloc, + .free = subghz_protocol_decoder_mastercode_free, + + .feed = subghz_protocol_decoder_mastercode_feed, + .reset = subghz_protocol_decoder_mastercode_reset, + + .get_hash_data = subghz_protocol_decoder_mastercode_get_hash_data, + .serialize = subghz_protocol_decoder_mastercode_serialize, + .deserialize = subghz_protocol_decoder_mastercode_deserialize, + .get_string = subghz_protocol_decoder_mastercode_get_string, +}; + +const SubGhzProtocolEncoder subghz_protocol_mastercode_encoder = { + .alloc = subghz_protocol_encoder_mastercode_alloc, + .free = subghz_protocol_encoder_mastercode_free, + + .deserialize = subghz_protocol_encoder_mastercode_deserialize, + .stop = subghz_protocol_encoder_mastercode_stop, + .yield = subghz_protocol_encoder_mastercode_yield, +}; + +const SubGhzProtocol subghz_protocol_mastercode = { + .name = SUBGHZ_PROTOCOL_MASTERCODE_NAME, + .type = SubGhzProtocolTypeStatic, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | + SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send, + + .decoder = &subghz_protocol_mastercode_decoder, + .encoder = &subghz_protocol_mastercode_encoder, +}; + +void* subghz_protocol_encoder_mastercode_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolEncoderMastercode* instance = malloc(sizeof(SubGhzProtocolEncoderMastercode)); + + instance->base.protocol = &subghz_protocol_mastercode; + instance->generic.protocol_name = instance->base.protocol->name; + + instance->encoder.repeat = 10; + instance->encoder.size_upload = 72; + instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); + instance->encoder.is_running = false; + return instance; +} + +void subghz_protocol_encoder_mastercode_free(void* context) { + furi_assert(context); + SubGhzProtocolEncoderMastercode* instance = context; + free(instance->encoder.upload); + free(instance); +} + +/** + * Generating an upload from data. + * @param instance Pointer to a SubGhzProtocolEncoderMastercode instance + * @return true On success + */ +static bool + subghz_protocol_encoder_mastercode_get_upload(SubGhzProtocolEncoderMastercode* instance) { + furi_assert(instance); + size_t index = 0; + size_t size_upload = (instance->generic.data_count_bit * 2); + if(size_upload > instance->encoder.size_upload) { + FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); + return false; + } else { + instance->encoder.size_upload = size_upload; + } + + for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) { + if(bit_read(instance->generic.data, i - 1)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_mastercode_const.te_long); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_mastercode_const.te_short); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_mastercode_const.te_short); + instance->encoder.upload[index++] = + level_duration_make(false, (uint32_t)subghz_protocol_mastercode_const.te_long); + } + } + if(bit_read(instance->generic.data, 0)) { + //send bit 1 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_mastercode_const.te_long); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_mastercode_const.te_short + + subghz_protocol_mastercode_const.te_short * 13); + } else { + //send bit 0 + instance->encoder.upload[index++] = + level_duration_make(true, (uint32_t)subghz_protocol_mastercode_const.te_short); + instance->encoder.upload[index++] = level_duration_make( + false, + (uint32_t)subghz_protocol_mastercode_const.te_long + + subghz_protocol_mastercode_const.te_short * 13); + } + return true; +} + +SubGhzProtocolStatus + subghz_protocol_encoder_mastercode_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolEncoderMastercode* instance = context; + SubGhzProtocolStatus ret = SubGhzProtocolStatusError; + do { + ret = subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_mastercode_const.min_count_bit_for_found); + if(ret != SubGhzProtocolStatusOk) { + break; + } + //optional parameter parameter + flipper_format_read_uint32( + flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1); + + if(!subghz_protocol_encoder_mastercode_get_upload(instance)) { + ret = SubGhzProtocolStatusErrorEncoderGetUpload; + break; + } + instance->encoder.is_running = true; + + } while(false); + + return ret; +} + +void subghz_protocol_encoder_mastercode_stop(void* context) { + SubGhzProtocolEncoderMastercode* instance = context; + instance->encoder.is_running = false; +} + +LevelDuration subghz_protocol_encoder_mastercode_yield(void* context) { + SubGhzProtocolEncoderMastercode* instance = context; + + if(instance->encoder.repeat == 0 || !instance->encoder.is_running) { + instance->encoder.is_running = false; + return level_duration_reset(); + } + + LevelDuration ret = instance->encoder.upload[instance->encoder.front]; + + if(++instance->encoder.front == instance->encoder.size_upload) { + instance->encoder.repeat--; + instance->encoder.front = 0; + } + + return ret; +} + +void* subghz_protocol_decoder_mastercode_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + SubGhzProtocolDecoderMastercode* instance = malloc(sizeof(SubGhzProtocolDecoderMastercode)); + instance->base.protocol = &subghz_protocol_mastercode; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void subghz_protocol_decoder_mastercode_free(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + free(instance); +} + +void subghz_protocol_decoder_mastercode_reset(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + instance->decoder.parser_step = MastercodeDecoderStepReset; +} + +void subghz_protocol_decoder_mastercode_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + + switch(instance->decoder.parser_step) { + case MastercodeDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, subghz_protocol_mastercode_const.te_short * 15) < + subghz_protocol_mastercode_const.te_delta * 15)) { + instance->decoder.parser_step = MastercodeDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + break; + + case MastercodeDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = MastercodeDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = MastercodeDecoderStepReset; + } + break; + + case MastercodeDecoderStepCheckDuration: + if(!level) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_mastercode_const.te_short) < + subghz_protocol_mastercode_const.te_delta) && + (DURATION_DIFF(duration, subghz_protocol_mastercode_const.te_long) < + subghz_protocol_mastercode_const.te_delta * 8)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = MastercodeDecoderStepSaveDuration; + } else if( + (DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_mastercode_const.te_long) < + subghz_protocol_mastercode_const.te_delta * 8) && + (DURATION_DIFF(duration, subghz_protocol_mastercode_const.te_short) < + subghz_protocol_mastercode_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = MastercodeDecoderStepSaveDuration; + } else if( + DURATION_DIFF(duration, subghz_protocol_mastercode_const.te_short * 15) < + subghz_protocol_mastercode_const.te_delta * 15) { + if((DURATION_DIFF( + instance->decoder.te_last, subghz_protocol_mastercode_const.te_short) < + subghz_protocol_mastercode_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + } else if((DURATION_DIFF( + instance->decoder.te_last, + subghz_protocol_mastercode_const.te_long) < + subghz_protocol_mastercode_const.te_delta * 8)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + } else { + instance->decoder.parser_step = MastercodeDecoderStepReset; + } + + if(instance->decoder.decode_count_bit == + subghz_protocol_mastercode_const.min_count_bit_for_found) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + } + instance->decoder.parser_step = MastercodeDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + + } else { + instance->decoder.parser_step = MastercodeDecoderStepReset; + } + } else { + instance->decoder.parser_step = MastercodeDecoderStepReset; + } + break; + } +} + +/** + * Analysis of received data + * @param instance Pointer to a SubGhzBlockGeneric* instance + */ +static void subghz_protocol_mastercode_check_remote_controller(SubGhzBlockGeneric* instance) { + instance->serial = (instance->data >> 4) & 0xFFFF; + instance->btn = (instance->data >> 2 & 0x03); +} + +uint8_t subghz_protocol_decoder_mastercode_get_hash_data(void* context) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +SubGhzProtocolStatus subghz_protocol_decoder_mastercode_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + return subghz_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +SubGhzProtocolStatus + subghz_protocol_decoder_mastercode_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + return subghz_block_generic_deserialize_check_count_bit( + &instance->generic, + flipper_format, + subghz_protocol_mastercode_const.min_count_bit_for_found); +} + +void subghz_protocol_decoder_mastercode_get_string(void* context, FuriString* output) { + furi_assert(context); + SubGhzProtocolDecoderMastercode* instance = context; + subghz_protocol_mastercode_check_remote_controller(&instance->generic); + furi_string_cat_printf( + output, + "%s %dbit\r\n" + "Key:%llX Btn %X\r\n" + " +: " DIP_PATTERN "\r\n" + " o: " DIP_PATTERN "\r\n" + " -: " DIP_PATTERN "\r\n", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint64_t)(instance->generic.data), + instance->generic.btn, + SHOW_DIP_P(instance->generic.serial, DIP_P), + SHOW_DIP_P(instance->generic.serial, DIP_O), + SHOW_DIP_P(instance->generic.serial, DIP_N)); +} diff --git a/lib/subghz/protocols/mastercode.h b/lib/subghz/protocols/mastercode.h new file mode 100644 index 0000000000..c5c73db989 --- /dev/null +++ b/lib/subghz/protocols/mastercode.h @@ -0,0 +1,109 @@ +#pragma once + +#include "base.h" + +#define SUBGHZ_PROTOCOL_MASTERCODE_NAME "Mastercode" + +typedef struct SubGhzProtocolDecoderMastercode SubGhzProtocolDecoderMastercode; +typedef struct SubGhzProtocolEncoderMastercode SubGhzProtocolEncoderMastercode; + +extern const SubGhzProtocolDecoder subghz_protocol_mastercode_decoder; +extern const SubGhzProtocolEncoder subghz_protocol_mastercode_encoder; +extern const SubGhzProtocol subghz_protocol_mastercode; + +/** + * Allocate SubGhzProtocolEncoderMastercode. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolEncoderMastercode* pointer to a SubGhzProtocolEncoderMastercode instance + */ +void* subghz_protocol_encoder_mastercode_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolEncoderMastercode. + * @param context Pointer to a SubGhzProtocolEncoderMastercode instance + */ +void subghz_protocol_encoder_mastercode_free(void* context); + +/** + * Deserialize and generating an upload to send. + * @param context Pointer to a SubGhzProtocolEncoderMastercode instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_encoder_mastercode_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Forced transmission stop. + * @param context Pointer to a SubGhzProtocolEncoderMastercode instance + */ +void subghz_protocol_encoder_mastercode_stop(void* context); + +/** + * Getting the level and duration of the upload to be loaded into DMA. + * @param context Pointer to a SubGhzProtocolEncoderMastercode instance + * @return LevelDuration + */ +LevelDuration subghz_protocol_encoder_mastercode_yield(void* context); + +/** + * Allocate SubGhzProtocolDecoderMastercode. + * @param environment Pointer to a SubGhzEnvironment instance + * @return SubGhzProtocolDecoderMastercode* pointer to a SubGhzProtocolDecoderMastercode instance + */ +void* subghz_protocol_decoder_mastercode_alloc(SubGhzEnvironment* environment); + +/** + * Free SubGhzProtocolDecoderMastercode. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + */ +void subghz_protocol_decoder_mastercode_free(void* context); + +/** + * Reset decoder SubGhzProtocolDecoderMastercode. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + */ +void subghz_protocol_decoder_mastercode_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void subghz_protocol_decoder_mastercode_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @return hash Hash sum + */ +uint8_t subghz_protocol_decoder_mastercode_get_hash_data(void* context); + +/** + * Serialize data SubGhzProtocolDecoderMastercode. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return status + */ +SubGhzProtocolStatus subghz_protocol_decoder_mastercode_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data SubGhzProtocolDecoderMastercode. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return status + */ +SubGhzProtocolStatus + subghz_protocol_decoder_mastercode_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a SubGhzProtocolDecoderMastercode instance + * @param output Resulting text + */ +void subghz_protocol_decoder_mastercode_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/protocol_items.c b/lib/subghz/protocols/protocol_items.c index 74244c5ff4..472a354e38 100644 --- a/lib/subghz/protocols/protocol_items.c +++ b/lib/subghz/protocols/protocol_items.c @@ -43,6 +43,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = { &subghz_protocol_alutech_at_4n, &subghz_protocol_kinggates_stylo_4k, &subghz_protocol_bin_raw, + &subghz_protocol_mastercode, }; const SubGhzProtocolRegistry subghz_protocol_registry = { diff --git a/lib/subghz/protocols/protocol_items.h b/lib/subghz/protocols/protocol_items.h index f1a28ac9b5..c5a090e993 100644 --- a/lib/subghz/protocols/protocol_items.h +++ b/lib/subghz/protocols/protocol_items.h @@ -44,3 +44,4 @@ #include "alutech_at_4n.h" #include "kinggates_stylo_4k.h" #include "bin_raw.h" +#include "mastercode.h" From 457aa5331fe8cbd72d2a17586ff903390f779fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 16 Nov 2023 01:11:05 +0900 Subject: [PATCH 25/40] Various Fixes for 0.95 (#3215) * FuriHal: retry gauge/charger initialization * FuriHal: lower logging level for flash known errata * FuriHal: graceful fail if subghz chip is not working * Furi: issue stop command even if timer is not active, document timer behavior --- furi/core/timer.c | 11 +--- furi/core/timer.h | 13 +++++ targets/f7/furi_hal/furi_hal_flash.c | 2 +- targets/f7/furi_hal/furi_hal_power.c | 33 ++++++++++-- targets/f7/furi_hal/furi_hal_subghz.c | 78 +++++++++++++++++---------- 5 files changed, 95 insertions(+), 42 deletions(-) diff --git a/furi/core/timer.c b/furi/core/timer.c index 17347e5c7d..027e4cf40d 100644 --- a/furi/core/timer.c +++ b/furi/core/timer.c @@ -122,17 +122,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance) { furi_assert(instance); TimerHandle_t hTimer = (TimerHandle_t)instance; - FuriStatus stat; - if(xTimerIsTimerActive(hTimer) == pdFALSE) { - stat = FuriStatusErrorResource; - } else { - furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); - stat = FuriStatusOk; - } + furi_check(xTimerStop(hTimer, portMAX_DELAY) == pdPASS); - /* Return execution status */ - return (stat); + return FuriStatusOk; } uint32_t furi_timer_is_running(FuriTimer* instance) { diff --git a/furi/core/timer.h b/furi/core/timer.h index d27ef5025e..f8f40c5626 100644 --- a/furi/core/timer.h +++ b/furi/core/timer.h @@ -32,6 +32,9 @@ FuriTimer* furi_timer_alloc(FuriTimerCallback func, FuriTimerType type, void* co void furi_timer_free(FuriTimer* instance); /** Start timer + * + * @warning This is asynchronous call, real operation will happen as soon as + * timer service process this request. * * @param instance The pointer to FuriTimer instance * @param[in] ticks The interval in ticks @@ -41,6 +44,9 @@ void furi_timer_free(FuriTimer* instance); FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks); /** Restart timer with previous timeout value + * + * @warning This is asynchronous call, real operation will happen as soon as + * timer service process this request. * * @param instance The pointer to FuriTimer instance * @param[in] ticks The interval in ticks @@ -50,6 +56,9 @@ FuriStatus furi_timer_start(FuriTimer* instance, uint32_t ticks); FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks); /** Stop timer + * + * @warning This is asynchronous call, real operation will happen as soon as + * timer service process this request. * * @param instance The pointer to FuriTimer instance * @@ -58,6 +67,10 @@ FuriStatus furi_timer_restart(FuriTimer* instance, uint32_t ticks); FuriStatus furi_timer_stop(FuriTimer* instance); /** Is timer running + * + * @warning This cal may and will return obsolete timer state if timer + * commands are still in the queue. Please read FreeRTOS timer + * documentation first. * * @param instance The pointer to FuriTimer instance * diff --git a/targets/f7/furi_hal/furi_hal_flash.c b/targets/f7/furi_hal/furi_hal_flash.c index 284d48bf53..7ac7a8bd12 100644 --- a/targets/f7/furi_hal/furi_hal_flash.c +++ b/targets/f7/furi_hal/furi_hal_flash.c @@ -101,7 +101,7 @@ void furi_hal_flash_init() { // WRITE_REG(FLASH->SR, FLASH_SR_OPTVERR); /* Actually, reset all error flags on start */ if(READ_BIT(FLASH->SR, FURI_HAL_FLASH_SR_ERRORS)) { - FURI_LOG_E(TAG, "FLASH->SR 0x%08lX", FLASH->SR); + FURI_LOG_W(TAG, "FLASH->SR 0x%08lX(Known ERRATA)", FLASH->SR); WRITE_REG(FLASH->SR, FURI_HAL_FLASH_SR_ERRORS); } } diff --git a/targets/f7/furi_hal/furi_hal_power.c b/targets/f7/furi_hal/furi_hal_power.c index 119dee81f9..9e3a70da73 100644 --- a/targets/f7/furi_hal/furi_hal_power.c +++ b/targets/f7/furi_hal/furi_hal_power.c @@ -71,12 +71,37 @@ void furi_hal_power_init() { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); // Find and init gauge - if(bq27220_init(&furi_hal_i2c_handle_power)) { - furi_hal_power.gauge_ok = bq27220_apply_data_memory( - &furi_hal_i2c_handle_power, furi_hal_power_gauge_data_memory); + size_t retry = 2; + while(retry > 0) { + furi_hal_power.gauge_ok = bq27220_init(&furi_hal_i2c_handle_power); + if(furi_hal_power.gauge_ok) { + furi_hal_power.gauge_ok = bq27220_apply_data_memory( + &furi_hal_i2c_handle_power, furi_hal_power_gauge_data_memory); + } + if(furi_hal_power.gauge_ok) { + break; + } else { + // Normal startup time is 250ms + // But if we try to access gauge at that stage it will become unresponsive + // 2 seconds timeout needed to restart communication + furi_delay_us(2020202); + } + retry--; } // Find and init charger - furi_hal_power.charger_ok = bq25896_init(&furi_hal_i2c_handle_power); + retry = 2; + while(retry > 0) { + furi_hal_power.charger_ok = bq25896_init(&furi_hal_i2c_handle_power); + if(furi_hal_power.charger_ok) { + break; + } else { + // Most likely I2C communication error + // 2 seconds should be enough for all chips on the line to timeout + // Also timing out here is very abnormal + furi_delay_us(2020202); + } + retry--; + } furi_hal_i2c_release(&furi_hal_i2c_handle_power); FURI_LOG_I(TAG, "Init OK"); diff --git a/targets/f7/furi_hal/furi_hal_subghz.c b/targets/f7/furi_hal/furi_hal_subghz.c index f751463532..a00ca7bf6d 100644 --- a/targets/f7/furi_hal/furi_hal_subghz.c +++ b/targets/f7/furi_hal/furi_hal_subghz.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ static uint32_t furi_hal_subghz_debug_gpio_buff[2]; /** SubGhz state */ typedef enum { SubGhzStateInit, /**< Init pending */ - + SubGhzStateBroken, /**< Chip power-on self test failed */ SubGhzStateIdle, /**< Idle, energy save mode */ SubGhzStateAsyncRx, /**< Async RX started */ @@ -69,46 +70,67 @@ const GpioPin* furi_hal_subghz_get_data_gpio() { void furi_hal_subghz_init() { furi_assert(furi_hal_subghz.state == SubGhzStateInit); - furi_hal_subghz.state = SubGhzStateIdle; + furi_hal_subghz.state = SubGhzStateBroken; furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); - + do { #ifdef FURI_HAL_SUBGHZ_TX_GPIO - furi_hal_gpio_init(&FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_init( + &FURI_HAL_SUBGHZ_TX_GPIO, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); #endif - // Reset - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); - cc1101_reset(&furi_hal_spi_bus_handle_subghz); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); + // Reset + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_reset(&furi_hal_spi_bus_handle_subghz); + cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); - // Prepare GD0 for power on self test - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + // Prepare GD0 for power on self test + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - // GD0 low - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW); - while(furi_hal_gpio_read(&gpio_cc1101_g0) != false) - ; + // GD0 low + FuriHalCortexTimer timeout = furi_hal_cortex_timer_get(10000); + cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW); + while(furi_hal_gpio_read(&gpio_cc1101_g0) != false && + !furi_hal_cortex_timer_is_expired(timeout)) + ; - // GD0 high - cc1101_write_reg( - &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); - while(furi_hal_gpio_read(&gpio_cc1101_g0) != true) - ; + if(furi_hal_gpio_read(&gpio_cc1101_g0) != false) { + break; + } - // Reset GD0 to floating state - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + // GD0 high + timeout = furi_hal_cortex_timer_get(10000); + cc1101_write_reg( + &furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHW | CC1101_IOCFG_INV); + while(furi_hal_gpio_read(&gpio_cc1101_g0) != true && + !furi_hal_cortex_timer_is_expired(timeout)) + ; - // RF switches - furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); + if(furi_hal_gpio_read(&gpio_cc1101_g0) != true) { + break; + } - // Go to sleep - cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); + // Reset GD0 to floating state + cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + // RF switches + furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + cc1101_write_reg(&furi_hal_spi_bus_handle_subghz, CC1101_IOCFG2, CC1101IocfgHW); + + // Go to sleep + cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); + + furi_hal_subghz.state = SubGhzStateIdle; + } while(false); furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); - FURI_LOG_I(TAG, "Init OK"); + + if(furi_hal_subghz.state == SubGhzStateIdle) { + FURI_LOG_I(TAG, "Init OK"); + } else { + FURI_LOG_E(TAG, "Init Fail"); + } } void furi_hal_subghz_sleep() { From 98d5718ec9e39824745a2ca364f4d06a5a05c828 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 15 Nov 2023 20:27:35 +0400 Subject: [PATCH 26/40] fbt: improvements (#3217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fbt: changed cdefines & lib handling for external apps; added extra checks for app manifest fields; moved around AppsC generator * fbt: commandline fixes for spaces in paths * fbt: fixed stringification for FAP_VERSION * fbt: Removed excessive quoting for gdb * docs: update for cdefines; fbt: typo fix * fbt: enforcing at least 2 components in app version= Co-authored-by: あく --- SConstruct | 36 +++-- applications/debug/accessor/application.fam | 1 - .../debug/battery_test_app/application.fam | 1 - applications/debug/blink_test/application.fam | 1 - applications/debug/ccid_test/application.fam | 1 - applications/debug/crash_test/application.fam | 1 - .../debug/display_test/application.fam | 1 - .../debug/file_browser_test/application.fam | 1 - .../debug/keypad_test/application.fam | 1 - .../debug/locale_test/application.fam | 1 - .../debug/text_box_test/application.fam | 1 - applications/debug/uart_echo/application.fam | 1 - applications/debug/usb_mouse/application.fam | 1 - applications/debug/usb_test/application.fam | 1 - applications/debug/vibro_test/application.fam | 1 - documentation/AppManifests.md | 2 +- firmware.scons | 4 +- scripts/fbt/appmanifest.py | 129 ++++-------------- scripts/fbt_tools/fbt_apps.py | 103 +++++++++++++- scripts/fbt_tools/fbt_extapps.py | 21 ++- scripts/fbt_tools/fbt_sdk.py | 15 +- scripts/fbt_tools/fbt_version.py | 20 ++- scripts/fbt_tools/fwbin.py | 19 ++- scripts/fbt_tools/jflash.py | 13 +- scripts/fbt_tools/objdump.py | 3 +- scripts/fbt_tools/openocd.py | 1 + scripts/fbt_tools/pvsstudio.py | 24 +++- scripts/fbt_tools/strip.py | 3 +- scripts/ufbt/SConstruct | 24 +++- scripts/version.py | 2 +- site_scons/environ.scons | 4 +- 31 files changed, 271 insertions(+), 166 deletions(-) diff --git a/SConstruct b/SConstruct index 97d7e5e5e2..a2c5cd9e7a 100644 --- a/SConstruct +++ b/SConstruct @@ -172,17 +172,19 @@ Alias("fap_dist", fap_dist) fap_deploy = distenv.PhonyTarget( "fap_deploy", - [ + Action( [ - "${PYTHON3}", - "${FBT_SCRIPT_DIR}/storage.py", - "-p", - "${FLIP_PORT}", - "send", - "${SOURCE}", - "/ext/apps", + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/storage.py", + "-p", + "${FLIP_PORT}", + "send", + "${SOURCE}", + "/ext/apps", + ] ] - ], + ), source=firmware_env.Dir(("${RESOURCES_ROOT}/apps")), ) Depends(fap_deploy, firmware_env["FW_RESOURCES_MANIFEST"]) @@ -261,7 +263,7 @@ distenv.PhonyTarget( distenv.PhonyTarget( "debug_other_blackmagic", "${GDBPYCOM}", - GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", + GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", GDBREMOTE="${BLACKMAGIC_ADDR}", GDBPYOPTS=debug_other_opts, ) @@ -276,13 +278,13 @@ distenv.PhonyTarget( # Linter distenv.PhonyTarget( "lint", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "check", "${LINT_SOURCES}"]], LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]], ) distenv.PhonyTarget( "format", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py format ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "format", "${LINT_SOURCES}"]], LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]], ) @@ -323,10 +325,14 @@ distenv.PhonyTarget( ) # Start Flipper CLI via PySerial's miniterm -distenv.PhonyTarget("cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}") +distenv.PhonyTarget( + "cli", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/serial_cli.py", "-p", "${FLIP_PORT}"]] +) # Update WiFi devboard firmware -distenv.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py") +distenv.PhonyTarget( + "devboard_flash", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/wifi_board.py"]] +) # Find blackmagic probe @@ -361,5 +367,5 @@ distenv.Alias("vscode_dist", vscode_dist) # Configure shell with build tools distenv.PhonyTarget( "env", - "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", + "@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", ) diff --git a/applications/debug/accessor/application.fam b/applications/debug/accessor/application.fam index 6b84727112..65a6c86663 100644 --- a/applications/debug/accessor/application.fam +++ b/applications/debug/accessor/application.fam @@ -4,7 +4,6 @@ App( apptype=FlipperAppType.DEBUG, targets=["f7"], entry_point="accessor_app", - cdefines=["APP_ACCESSOR"], requires=["gui"], stack_size=4 * 1024, order=40, diff --git a/applications/debug/battery_test_app/application.fam b/applications/debug/battery_test_app/application.fam index f97d102791..5f4acd83d5 100644 --- a/applications/debug/battery_test_app/application.fam +++ b/applications/debug/battery_test_app/application.fam @@ -3,7 +3,6 @@ App( name="Battery Test", apptype=FlipperAppType.DEBUG, entry_point="battery_test_app", - cdefines=["APP_BATTERY_TEST"], requires=[ "gui", "power", diff --git a/applications/debug/blink_test/application.fam b/applications/debug/blink_test/application.fam index c6a8a922a4..d7d873fb9a 100644 --- a/applications/debug/blink_test/application.fam +++ b/applications/debug/blink_test/application.fam @@ -3,7 +3,6 @@ App( name="Blink Test", apptype=FlipperAppType.DEBUG, entry_point="blink_test_app", - cdefines=["APP_BLINK"], requires=["gui"], stack_size=1 * 1024, order=10, diff --git a/applications/debug/ccid_test/application.fam b/applications/debug/ccid_test/application.fam index e0cbc8d85e..ad90767708 100644 --- a/applications/debug/ccid_test/application.fam +++ b/applications/debug/ccid_test/application.fam @@ -3,7 +3,6 @@ App( name="CCID Debug", apptype=FlipperAppType.DEBUG, entry_point="ccid_test_app", - cdefines=["CCID_TEST"], requires=[ "gui", ], diff --git a/applications/debug/crash_test/application.fam b/applications/debug/crash_test/application.fam index 55f62f86d8..357efe667a 100644 --- a/applications/debug/crash_test/application.fam +++ b/applications/debug/crash_test/application.fam @@ -3,7 +3,6 @@ App( name="Crash Test", apptype=FlipperAppType.DEBUG, entry_point="crash_test_app", - cdefines=["APP_CRASH_TEST"], requires=["gui"], stack_size=1 * 1024, fap_category="Debug", diff --git a/applications/debug/display_test/application.fam b/applications/debug/display_test/application.fam index e8a00d2ae1..6a2d9c20c1 100644 --- a/applications/debug/display_test/application.fam +++ b/applications/debug/display_test/application.fam @@ -3,7 +3,6 @@ App( name="Display Test", apptype=FlipperAppType.DEBUG, entry_point="display_test_app", - cdefines=["APP_DISPLAY_TEST"], requires=["gui"], fap_libs=["misc"], stack_size=1 * 1024, diff --git a/applications/debug/file_browser_test/application.fam b/applications/debug/file_browser_test/application.fam index 4a401a649d..bb08ad2c55 100644 --- a/applications/debug/file_browser_test/application.fam +++ b/applications/debug/file_browser_test/application.fam @@ -3,7 +3,6 @@ App( name="File Browser Test", apptype=FlipperAppType.DEBUG, entry_point="file_browser_app", - cdefines=["APP_FILE_BROWSER_TEST"], requires=["gui"], stack_size=2 * 1024, order=150, diff --git a/applications/debug/keypad_test/application.fam b/applications/debug/keypad_test/application.fam index 6859af26f6..90851950b2 100644 --- a/applications/debug/keypad_test/application.fam +++ b/applications/debug/keypad_test/application.fam @@ -3,7 +3,6 @@ App( name="Keypad Test", apptype=FlipperAppType.DEBUG, entry_point="keypad_test_app", - cdefines=["APP_KEYPAD_TEST"], requires=["gui"], stack_size=1 * 1024, order=30, diff --git a/applications/debug/locale_test/application.fam b/applications/debug/locale_test/application.fam index e46eeff51c..d341122f99 100644 --- a/applications/debug/locale_test/application.fam +++ b/applications/debug/locale_test/application.fam @@ -3,7 +3,6 @@ App( name="Locale Test", apptype=FlipperAppType.DEBUG, entry_point="locale_test_app", - cdefines=["APP_LOCALE"], requires=["gui", "locale"], stack_size=2 * 1024, order=70, diff --git a/applications/debug/text_box_test/application.fam b/applications/debug/text_box_test/application.fam index 3e54df9cc5..823c21d068 100644 --- a/applications/debug/text_box_test/application.fam +++ b/applications/debug/text_box_test/application.fam @@ -3,7 +3,6 @@ App( name="Text Box Test", apptype=FlipperAppType.DEBUG, entry_point="text_box_test_app", - cdefines=["APP_TEXT_BOX_TEST"], requires=["gui"], stack_size=1 * 1024, order=140, diff --git a/applications/debug/uart_echo/application.fam b/applications/debug/uart_echo/application.fam index 8863a1a942..7b030bcfa6 100644 --- a/applications/debug/uart_echo/application.fam +++ b/applications/debug/uart_echo/application.fam @@ -3,7 +3,6 @@ App( name="UART Echo", apptype=FlipperAppType.DEBUG, entry_point="uart_echo_app", - cdefines=["APP_UART_ECHO"], requires=["gui"], stack_size=2 * 1024, order=70, diff --git a/applications/debug/usb_mouse/application.fam b/applications/debug/usb_mouse/application.fam index 5c43400451..7747613d58 100644 --- a/applications/debug/usb_mouse/application.fam +++ b/applications/debug/usb_mouse/application.fam @@ -3,7 +3,6 @@ App( name="USB Mouse Demo", apptype=FlipperAppType.DEBUG, entry_point="usb_mouse_app", - cdefines=["APP_USB_MOUSE"], requires=["gui"], stack_size=1 * 1024, order=60, diff --git a/applications/debug/usb_test/application.fam b/applications/debug/usb_test/application.fam index 27395c34d4..463bb4a26e 100644 --- a/applications/debug/usb_test/application.fam +++ b/applications/debug/usb_test/application.fam @@ -3,7 +3,6 @@ App( name="USB Test", apptype=FlipperAppType.DEBUG, entry_point="usb_test_app", - cdefines=["APP_USB_TEST"], requires=["gui"], stack_size=1 * 1024, order=50, diff --git a/applications/debug/vibro_test/application.fam b/applications/debug/vibro_test/application.fam index f7115cc962..c35a7223f8 100644 --- a/applications/debug/vibro_test/application.fam +++ b/applications/debug/vibro_test/application.fam @@ -3,7 +3,6 @@ App( name="Vibro Test", apptype=FlipperAppType.DEBUG, entry_point="vibro_test_app", - cdefines=["APP_VIBRO_TEST"], requires=["gui"], stack_size=1 * 1024, order=20, diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index d190a798ba..9afdccb0e4 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -32,7 +32,7 @@ Only two parameters are mandatory: **_appid_** and **_apptype_**. Others are opt - **name**: name displayed in menus. - **entry_point**: C function to be used as the application's entry point. Note that C++ function names are mangled, so you need to wrap them in `extern "C"` to use them as entry points. - **flags**: internal flags for system apps. Do not use. -- **cdefines**: C preprocessor definitions to declare globally for other apps when the current application is included in the active build configuration. +- **cdefines**: C preprocessor definitions to declare globally for other apps when the current application is included in the active build configuration. **For external applications**: specified definitions are used when building the application itself. - **requires**: list of application IDs to include in the build configuration when the current application is referenced in the list of applications to build. - **conflicts**: list of application IDs with which the current application conflicts. If any of them is found in the constructed application list, **`fbt`** will abort the firmware build process. - **provides**: functionally identical to **_requires_** field. diff --git a/firmware.scons b/firmware.scons index eca6afc4c7..004def9a99 100644 --- a/firmware.scons +++ b/firmware.scons @@ -219,7 +219,7 @@ AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) AddPostAction( fwelf, Action( - '${PYTHON3} "${BIN_SIZE_SCRIPT}" elf ${TARGET}', + [["${PYTHON3}", "${BIN_SIZE_SCRIPT}", "elf", "${TARGET}"]], "Firmware size", ), ) @@ -229,7 +229,7 @@ fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") AddPostAction( fwbin, - Action('@${PYTHON3} "${BIN_SIZE_SCRIPT}" bin ${TARGET}'), + Action([["@${PYTHON3}", "${BIN_SIZE_SCRIPT}", "bin", "${TARGET}"]]), ) fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index bef4eb02b1..d32869b106 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -33,6 +33,8 @@ class FlipperAppType(Enum): @dataclass class FlipperApplication: APP_ID_REGEX: ClassVar[re.Pattern] = re.compile(r"^[a-z0-9_]+$") + PRIVATE_FIELD_PREFIX: ClassVar[str] = "_" + APP_MANIFEST_DEFAULT_NAME: ClassVar[str] = "application.fam" @dataclass class ExternallyBuiltFile: @@ -48,8 +50,6 @@ class FlipperApplication: cdefines: List[str] = field(default_factory=list) cincludes: List[str] = field(default_factory=list) - PRIVATE_FIELD_PREFIX = "_" - appid: str apptype: FlipperAppType name: Optional[str] = "" @@ -117,8 +117,10 @@ class FlipperApplication: self.fap_version = tuple(int(v) for v in self.fap_version.split(".")) except ValueError: raise FlipperManifestException( - f"Invalid version string '{self.fap_version}'. Must be in the form 'major.minor'" + f"Invalid version '{self.fap_version}'. Must be in the form 'major.minor'" ) + if len(self.fap_version) < 2: + raise ValueError("Not enough version components") class AppManager: @@ -155,11 +157,20 @@ class AppManager: raise FlipperManifestException( f"App {kw.get('appid')} cannot have fal_embedded set" ) - # Harmless - cdefines for external apps are meaningless - # if apptype == FlipperAppType.EXTERNAL and kw.get("cdefines"): - # raise FlipperManifestException( - # f"External app {kw.get('appid')} must not have 'cdefines' in manifest" - # ) + + if apptype in AppBuildset.dist_app_types: + # For distributing .fap's resources, there's "fap_file_assets" + for app_property in ("resources",): + if kw.get(app_property): + raise FlipperManifestException( + f"App {kw.get('appid')} of type {apptype} cannot have '{app_property}' in manifest" + ) + else: + for app_property in ("fap_extbuild", "fap_private_libs", "fap_icon_assets"): + if kw.get(app_property): + raise FlipperManifestException( + f"App {kw.get('appid')} of type {apptype} must not have '{app_property}' in manifest" + ) def load_manifest(self, app_manifest_path: str, app_dir_node: object): if not os.path.exists(app_manifest_path): @@ -241,12 +252,21 @@ class AppBuildset: FlipperAppType.STARTUP, ) EXTERNAL_APP_TYPES_MAP = { + # AppType -> bool: true if always deploy, false if obey app set FlipperAppType.EXTERNAL: True, FlipperAppType.PLUGIN: True, FlipperAppType.DEBUG: True, FlipperAppType.MENUEXTERNAL: False, } + @classmethod + @property + def dist_app_types(cls): + """Applications that are installed on SD card""" + return list( + entry[0] for entry in cls.EXTERNAL_APP_TYPES_MAP.items() if entry[1] + ) + @staticmethod def print_writer(message): print(message) @@ -432,96 +452,3 @@ class AppBuildset: for source_type in app.sources ) ) - - -class ApplicationsCGenerator: - APP_TYPE_MAP = { - FlipperAppType.SERVICE: ("FlipperInternalApplication", "FLIPPER_SERVICES"), - FlipperAppType.SYSTEM: ("FlipperInternalApplication", "FLIPPER_SYSTEM_APPS"), - FlipperAppType.APP: ("FlipperInternalApplication", "FLIPPER_APPS"), - FlipperAppType.DEBUG: ("FlipperInternalApplication", "FLIPPER_DEBUG_APPS"), - FlipperAppType.SETTINGS: ( - "FlipperInternalApplication", - "FLIPPER_SETTINGS_APPS", - ), - FlipperAppType.STARTUP: ( - "FlipperInternalOnStartHook", - "FLIPPER_ON_SYSTEM_START", - ), - } - - APP_EXTERNAL_TYPE = ( - "FlipperExternalApplication", - "FLIPPER_EXTERNAL_APPS", - ) - - def __init__(self, buildset: AppBuildset, autorun_app: str = ""): - self.buildset = buildset - self.autorun = autorun_app - - def get_app_ep_forward(self, app: FlipperApplication): - if app.apptype == FlipperAppType.STARTUP: - return f"extern void {app.entry_point}();" - return f"extern int32_t {app.entry_point}(void* p);" - - def get_app_descr(self, app: FlipperApplication): - if app.apptype == FlipperAppType.STARTUP: - return app.entry_point - return f""" - {{.app = {app.entry_point}, - .name = "{app.name}", - .appid = "{app.appid}", - .stack_size = {app.stack_size}, - .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}""" - - def get_external_app_descr(self, app: FlipperApplication): - app_path = "/ext/apps" - if app.fap_category: - app_path += f"/{app.fap_category}" - app_path += f"/{app.appid}.fap" - return f""" - {{ - .name = "{app.name}", - .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .path = "{app_path}" }}""" - - def generate(self): - contents = [ - '#include "applications.h"', - "#include ", - f'const char* FLIPPER_AUTORUN_APP_NAME = "{self.autorun}";', - ] - for apptype in self.APP_TYPE_MAP: - contents.extend( - map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) - ) - entry_type, entry_block = self.APP_TYPE_MAP[apptype] - contents.append(f"const {entry_type} {entry_block}[] = {{") - contents.append( - ",\n".join( - map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) - ) - ) - contents.append("};") - contents.append( - f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" - ) - - archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) - if archive_app: - contents.extend( - [ - self.get_app_ep_forward(archive_app[0]), - f"const FlipperInternalApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", - ] - ) - - entry_type, entry_block = self.APP_EXTERNAL_TYPE - external_apps = self.buildset.get_apps_of_type(FlipperAppType.MENUEXTERNAL) - contents.append(f"const {entry_type} {entry_block}[] = {{") - contents.append(",\n".join(map(self.get_external_app_descr, external_apps))) - contents.append("};") - contents.append(f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});") - - return "\n".join(contents) diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index edce194f07..dadf6dc0c8 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -1,25 +1,118 @@ from ansi.color import fg from fbt.appmanifest import ( - ApplicationsCGenerator, AppManager, + AppBuildset, + FlipperApplication, FlipperAppType, FlipperManifestException, ) from SCons.Action import Action from SCons.Builder import Builder from SCons.Errors import StopError -from SCons.Warnings import WarningOnByDefault, warn from SCons.Script import GetOption +from SCons.Warnings import WarningOnByDefault, warn # Adding objects for application management to env # AppManager env["APPMGR"] - loads all manifests; manages list of known apps # AppBuildset env["APPBUILD"] - contains subset of apps, filtered for current config +class ApplicationsCGenerator: + APP_TYPE_MAP = { + FlipperAppType.SERVICE: ("FlipperInternalApplication", "FLIPPER_SERVICES"), + FlipperAppType.SYSTEM: ("FlipperInternalApplication", "FLIPPER_SYSTEM_APPS"), + FlipperAppType.APP: ("FlipperInternalApplication", "FLIPPER_APPS"), + FlipperAppType.DEBUG: ("FlipperInternalApplication", "FLIPPER_DEBUG_APPS"), + FlipperAppType.SETTINGS: ( + "FlipperInternalApplication", + "FLIPPER_SETTINGS_APPS", + ), + FlipperAppType.STARTUP: ( + "FlipperInternalOnStartHook", + "FLIPPER_ON_SYSTEM_START", + ), + } + + APP_EXTERNAL_TYPE = ( + "FlipperExternalApplication", + "FLIPPER_EXTERNAL_APPS", + ) + + def __init__(self, buildset: AppBuildset, autorun_app: str = ""): + self.buildset = buildset + self.autorun = autorun_app + + def get_app_ep_forward(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return f"extern void {app.entry_point}();" + return f"extern int32_t {app.entry_point}(void* p);" + + def get_app_descr(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return app.entry_point + return f""" + {{.app = {app.entry_point}, + .name = "{app.name}", + .appid = "{app.appid}", + .stack_size = {app.stack_size}, + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}""" + + def get_external_app_descr(self, app: FlipperApplication): + app_path = "/ext/apps" + if app.fap_category: + app_path += f"/{app.fap_category}" + app_path += f"/{app.appid}.fap" + return f""" + {{ + .name = "{app.name}", + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .path = "{app_path}" }}""" + + def generate(self): + contents = [ + '#include "applications.h"', + "#include ", + f'const char* FLIPPER_AUTORUN_APP_NAME = "{self.autorun}";', + ] + for apptype in self.APP_TYPE_MAP: + contents.extend( + map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) + ) + entry_type, entry_block = self.APP_TYPE_MAP[apptype] + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append( + ",\n".join( + map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) + ) + ) + contents.append("};") + contents.append( + f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" + ) + + archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) + if archive_app: + contents.extend( + [ + self.get_app_ep_forward(archive_app[0]), + f"const FlipperInternalApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", + ] + ) + + entry_type, entry_block = self.APP_EXTERNAL_TYPE + external_apps = self.buildset.get_apps_of_type(FlipperAppType.MENUEXTERNAL) + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append(",\n".join(map(self.get_external_app_descr, external_apps))) + contents.append("};") + contents.append(f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});") + + return "\n".join(contents) + + def LoadAppManifest(env, entry): try: - APP_MANIFEST_NAME = "application.fam" - manifest_glob = entry.glob(APP_MANIFEST_NAME) + manifest_glob = entry.glob(FlipperApplication.APP_MANIFEST_DEFAULT_NAME) if len(manifest_glob) == 0: try: disk_node = next(filter(lambda d: d.exists(), entry.get_all_rdirs())) @@ -27,7 +120,7 @@ def LoadAppManifest(env, entry): disk_node = entry raise FlipperManifestException( - f"App folder '{disk_node.abspath}': missing manifest ({APP_MANIFEST_NAME})" + f"App folder '{disk_node.abspath}': missing manifest ({FlipperApplication.APP_MANIFEST_DEFAULT_NAME})" ) app_manifest_file_path = manifest_glob[0].rfile().abspath diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index b88fa79291..a7914c4f87 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -58,7 +58,8 @@ class AppBuilder: ) self.app_env.Append( CPPDEFINES=[ - ("FAP_VERSION", f'"{".".join(map(str, self.app.fap_version))}"') + ("FAP_VERSION", f'\\"{".".join(map(str, self.app.fap_version))}\\"'), + *self.app.cdefines, ], ) self.app_env.VariantDir(self.app_work_dir, self.app._appdir, duplicate=False) @@ -143,8 +144,8 @@ class AppBuilder: self.app._assets_dirs = [self.app._appdir.Dir(self.app.fap_file_assets)] self.app_env.Append( - LIBS=[*self.app.fap_libs, *self.private_libs], - CPPPATH=[self.app_work_dir, self.app._appdir], + LIBS=[*self.app.fap_libs, *self.private_libs, *self.app.fap_libs], + CPPPATH=[self.app_env.Dir(self.app_work_dir), self.app._appdir], ) app_sources = self.app_env.GatherSources( @@ -472,7 +473,19 @@ def AddAppLaunchTarget(env, appname, launch_target_name): components = _gather_app_components(env, appname) target = env.PhonyTarget( launch_target_name, - '${PYTHON3} "${APP_RUN_SCRIPT}" -p ${FLIP_PORT} ${EXTRA_ARGS} -s ${SOURCES} -t ${FLIPPER_FILE_TARGETS}', + [ + [ + "${PYTHON3}", + "${APP_RUN_SCRIPT}", + "-p", + "${FLIP_PORT}", + "${EXTRA_ARGS}", + "-s", + "${SOURCES}", + "-t", + "${FLIPPER_FILE_TARGETS}", + ] + ], source=components.deploy_sources.values(), FLIPPER_FILE_TARGETS=components.deploy_sources.keys(), EXTRA_ARGS=components.extra_launch_args, diff --git a/scripts/fbt_tools/fbt_sdk.py b/scripts/fbt_tools/fbt_sdk.py index 6350f14b8b..17acc8cf1a 100644 --- a/scripts/fbt_tools/fbt_sdk.py +++ b/scripts/fbt_tools/fbt_sdk.py @@ -285,7 +285,20 @@ def generate(env, **kw): "$SDK_AMALGAMATE_HEADER_COMSTR", ), Action( - "$CC -o $TARGET -E -P $CCFLAGS $_CCCOMCOM $SDK_PP_FLAGS -MMD ${TARGET}.c", + [ + [ + "$CC", + "-o", + "$TARGET", + "-E", + "-P", + "$CCFLAGS", + "$_CCCOMCOM", + "$SDK_PP_FLAGS", + "-MMD", + "${TARGET}.c", + ] + ], "$SDK_AMALGAMATE_PP_COMSTR", ), ], diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index f1a782523f..e64167b3dc 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -19,10 +19,22 @@ def generate(env): BUILDERS={ "VersionBuilder": Builder( action=Action( - '${PYTHON3} "${VERSION_SCRIPT}" generate ' - "-t ${TARGET_HW} -fw-origin ${FIRMWARE_ORIGIN} " - '-o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', - "${VERSIONCOMSTR}", + [ + [ + "${PYTHON3}", + "${VERSION_SCRIPT}", + "generate", + "-t", + "${TARGET_HW}", + "--fw-origin", + "${FIRMWARE_ORIGIN}", + "-o", + "${TARGET.dir.posix}", + "--dir", + "${ROOT_DIR}", + "${VERSIONCOMSTR}", + ] + ] ), emitter=_version_emitter, ), diff --git a/scripts/fbt_tools/fwbin.py b/scripts/fbt_tools/fwbin.py index 06a435b6db..860f83b1b9 100644 --- a/scripts/fbt_tools/fwbin.py +++ b/scripts/fbt_tools/fwbin.py @@ -25,7 +25,7 @@ def generate(env): BUILDERS={ "HEXBuilder": Builder( action=Action( - '${OBJCOPY} -O ihex "${SOURCE}" "${TARGET}"', + [["${OBJCOPY}", "-O", "ihex", "${SOURCE}", "${TARGET}"]], "${HEXCOMSTR}", ), suffix=".hex", @@ -33,7 +33,7 @@ def generate(env): ), "BINBuilder": Builder( action=Action( - '${OBJCOPY} -O binary -S "${SOURCE}" "${TARGET}"', + [["${OBJCOPY}", "-O", "binary", "-S", "${SOURCE}", "${TARGET}"]], "${BINCOMSTR}", ), suffix=".bin", @@ -41,7 +41,20 @@ def generate(env): ), "DFUBuilder": Builder( action=Action( - '${PYTHON3} "${BIN2DFU}" -i "${SOURCE}" -o "${TARGET}" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"', + [ + [ + "${PYTHON3}", + "${BIN2DFU}", + "-i", + "${SOURCE}", + "-o", + "${TARGET}", + "-a", + "${IMAGE_BASE_ADDRESS}", + "-l", + "Flipper Zero F${TARGET_HW}", + ] + ], "${DFUCOMSTR}", ), suffix=".dfu", diff --git a/scripts/fbt_tools/jflash.py b/scripts/fbt_tools/jflash.py index aea7279b63..5eb9f2c193 100644 --- a/scripts/fbt_tools/jflash.py +++ b/scripts/fbt_tools/jflash.py @@ -1,5 +1,6 @@ from SCons.Builder import Builder from SCons.Defaults import Touch +from SCons.Action import Action def generate(env): @@ -9,13 +10,21 @@ def generate(env): "-auto", "-exit", ], - JFLASHCOM="${JFLASH} -openprj${JFLASHPROJECT} -open${SOURCE},${JFLASHADDR} ${JFLASHFLAGS}", ) env.Append( BUILDERS={ "JFlash": Builder( action=[ - "${JFLASHCOM}", + Action( + [ + [ + "${JFLASH}", + "-openprj${JFLASHPROJECT}", + "-open${SOURCE},${JFLASHADDR}", + "${JFLASHFLAGS}", + ] + ] + ), Touch("${TARGET}"), ], ), diff --git a/scripts/fbt_tools/objdump.py b/scripts/fbt_tools/objdump.py index 31f8176484..e3dbc6d875 100644 --- a/scripts/fbt_tools/objdump.py +++ b/scripts/fbt_tools/objdump.py @@ -6,13 +6,12 @@ def generate(env): env.SetDefault( OBJDUMP="objdump", OBJDUMPFLAGS=[], - OBJDUMPCOM="$OBJDUMP $OBJDUMPFLAGS -S $SOURCES > $TARGET", ) env.Append( BUILDERS={ "ObjDump": Builder( action=Action( - "${OBJDUMPCOM}", + [["$OBJDUMP", "$OBJDUMPFLAGS", "-S", "$SOURCES", ">", "$TARGET"]], "${OBJDUMPCOMSTR}", ), suffix=".lst", diff --git a/scripts/fbt_tools/openocd.py b/scripts/fbt_tools/openocd.py index 157d798f40..596f5f8a64 100644 --- a/scripts/fbt_tools/openocd.py +++ b/scripts/fbt_tools/openocd.py @@ -5,6 +5,7 @@ from SCons.Defaults import Touch __OPENOCD_BIN = "openocd" +# TODO: FL-3663: rework argument passing to lists _oocd_action = Action( "${OPENOCD} ${OPENOCD_OPTS} ${OPENOCD_COMMAND}", "${OPENOCDCOMSTR}", diff --git a/scripts/fbt_tools/pvsstudio.py b/scripts/fbt_tools/pvsstudio.py index f43db126e3..ecf9d4b068 100644 --- a/scripts/fbt_tools/pvsstudio.py +++ b/scripts/fbt_tools/pvsstudio.py @@ -79,7 +79,17 @@ def generate(env): BUILDERS={ "PVSCheck": Builder( action=Action( - '${PVSCHECKBIN} analyze ${PVSOPTIONS} -f "${SOURCE}" -o "${TARGET}"', + [ + [ + "${PVSCHECKBIN}", + "analyze", + "${PVSOPTIONS}", + "-f", + "${SOURCE}", + "-o", + "${TARGET}", + ] + ], "${PVSCHECKCOMSTR}", ), suffix=".log", @@ -92,7 +102,17 @@ def generate(env): # PlogConverter.exe and plog-converter have different behavior Mkdir("${TARGET.dir}") if env["PLATFORM"] == "win32" else None, Action(_set_browser_action, None), - '${PVSCONVBIN} ${PVSCONVOPTIONS} "${SOURCE}" -o "${REPORT_DIR}"', + Action( + [ + [ + "${PVSCONVBIN}", + "${PVSCONVOPTIONS}", + "${SOURCE}", + "-o", + "${REPORT_DIR}", + ] + ] + ), ], "${PVSCONVCOMSTR}", ), diff --git a/scripts/fbt_tools/strip.py b/scripts/fbt_tools/strip.py index ee14fc185a..39f3a620cf 100644 --- a/scripts/fbt_tools/strip.py +++ b/scripts/fbt_tools/strip.py @@ -6,13 +6,12 @@ def generate(env): env.SetDefault( STRIP="strip", STRIPFLAGS=[], - STRIPCOM="$STRIP $STRIPFLAGS $SOURCES -o $TARGET", ) env.Append( BUILDERS={ "ELFStripper": Builder( action=Action( - "${STRIPCOM}", + [["$STRIP", "$STRIPFLAGS", "$SOURCES", "-o", "$TARGET"]], "${STRIPCOMSTR}", ), suffix=".elf", diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 98e6b638f3..46d6635788 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -325,24 +325,26 @@ else: appenv.PhonyTarget( "cli", - '${PYTHON3} "${FBT_SCRIPT_DIR}/serial_cli.py" -p ${FLIP_PORT}', + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/serial_cli.py", "-p", "${FLIP_PORT}"]], ) # Update WiFi devboard firmware -dist_env.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py") +dist_env.PhonyTarget( + "devboard_flash", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/wifi_board.py"]] +) # Linter dist_env.PhonyTarget( "lint", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "check", "${LINT_SOURCES}"]], source=original_app_dir.File(".clang-format"), LINT_SOURCES=[original_app_dir], ) dist_env.PhonyTarget( "format", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py format ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "format", "${LINT_SOURCES}"]], source=original_app_dir.File(".clang-format"), LINT_SOURCES=[original_app_dir], ) @@ -455,7 +457,17 @@ if dolphin_src_dir.exists(): ) dist_env.PhonyTarget( "dolphin_ext", - '${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py -p ${FLIP_PORT} send "${SOURCE}" /ext/dolphin', + [ + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/storage.py", + "-p", + "${FLIP_PORT}", + "send", + "${SOURCE}", + "/ext/dolphin", + ] + ], source=ufbt_build_dir.Dir("dolphin"), ) else: @@ -467,7 +479,7 @@ else: dist_env.PhonyTarget( "env", - "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", + "@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", ) dist_env.PostConfigureUfbtEnvionment() diff --git a/scripts/version.py b/scripts/version.py index 4b1c739bc5..98b1b7e855 100755 --- a/scripts/version.py +++ b/scripts/version.py @@ -101,7 +101,7 @@ class Main(App): required=True, ) self.parser_generate.add_argument( - "-fw-origin", + "--fw-origin", dest="firmware_origin", type=str, help="firmware origin", diff --git a/site_scons/environ.scons b/site_scons/environ.scons index b638b10185..74762cb15b 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -27,6 +27,8 @@ variables_to_forward = [ "PYTHONNOUSERSITE", "TMP", "TEMP", + # ccache + "CCACHE_DISABLE", # Colors for tools "TERM", ] @@ -62,7 +64,7 @@ coreenv = VAR_ENV.Clone( # Setting up temp file parameters - to overcome command line length limits TEMPFILEARGESCFUNC=tempfile_arg_esc_func, ROOT_DIR=Dir("#"), - FBT_SCRIPT_DIR="${ROOT_DIR}/scripts", + FBT_SCRIPT_DIR=Dir("#/scripts"), ) # If DIST_SUFFIX is set in environment, is has precedence (set by CI) From 4b3e8aba294bf94be4ac7a73873202e3078afb2c Mon Sep 17 00:00:00 2001 From: Sergey Gavrilov Date: Wed, 15 Nov 2023 19:39:27 +0300 Subject: [PATCH 27/40] [FL-3664] 64k does not enough (#3216) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Unit tests: add "exists" to furi_record tests * Unit tests: mu_warn, storage 64k test * Storage: read/write over 64k * Unit tests: moar tests for storage r/w for >64k cases * Apps, libs: replace uint16_t with size_t on storage r/w operations * Unit tests: better data pattern, subghz: warning if transmission is prohibited Co-authored-by: あく --- .../debug/unit_tests/furi/furi_record_test.c | 31 ++++++--- applications/debug/unit_tests/minunit.h | 5 ++ .../debug/unit_tests/storage/dirwalk_test.c | 2 +- .../debug/unit_tests/storage/storage_test.c | 65 +++++++++++++++++++ .../debug/unit_tests/subghz/subghz_test.c | 1 + applications/debug/unit_tests/test_index.c | 10 +++ .../main/archive/helpers/archive_favorites.c | 4 +- applications/main/subghz/subghz_cli.c | 2 +- .../services/notification/notification_app.c | 4 +- applications/services/rpc/rpc_storage.c | 2 +- applications/services/storage/storage.h | 6 +- applications/services/storage/storage_cli.c | 22 +++---- .../services/storage/storage_external_api.c | 41 +++++++++++- .../scenes/storage_settings_scene_benchmark.c | 4 +- .../updater/util/update_task_worker_flasher.c | 2 +- lib/flipper_application/elf/elf_file.c | 2 +- lib/music_worker/music_worker.c | 2 +- lib/toolbox/crc32_calc.c | 2 +- lib/toolbox/md5_calc.c | 4 +- lib/toolbox/saved_struct.c | 6 +- lib/toolbox/stream/file_stream.c | 24 +------ lib/update_util/dfu_file.c | 6 +- lib/update_util/update_operation.c | 2 +- targets/f18/api_symbols.csv | 10 +-- targets/f7/api_symbols.csv | 10 +-- 25 files changed, 188 insertions(+), 81 deletions(-) diff --git a/applications/debug/unit_tests/furi/furi_record_test.c b/applications/debug/unit_tests/furi/furi_record_test.c index 512ddfdc4a..236e1efc56 100644 --- a/applications/debug/unit_tests/furi/furi_record_test.c +++ b/applications/debug/unit_tests/furi/furi_record_test.c @@ -3,18 +3,29 @@ #include #include "../minunit.h" -void test_furi_create_open() { - // 1. Create record - uint8_t test_data = 0; - furi_record_create("test/holding", (void*)&test_data); +#define TEST_RECORD_NAME "test/holding" - // 2. Open it - void* record = furi_record_open("test/holding"); +void test_furi_create_open() { + // Test that record does not exist + mu_check(furi_record_exists(TEST_RECORD_NAME) == false); + + // Create record + uint8_t test_data = 0; + furi_record_create(TEST_RECORD_NAME, (void*)&test_data); + + // Test that record exists + mu_check(furi_record_exists(TEST_RECORD_NAME) == true); + + // Open it + void* record = furi_record_open(TEST_RECORD_NAME); mu_assert_pointers_eq(record, &test_data); - // 3. Close it - furi_record_close("test/holding"); + // Close it + furi_record_close(TEST_RECORD_NAME); - // 4. Clean up - furi_record_destroy("test/holding"); + // Clean up + furi_record_destroy(TEST_RECORD_NAME); + + // Test that record does not exist + mu_check(furi_record_exists(TEST_RECORD_NAME) == false); } diff --git a/applications/debug/unit_tests/minunit.h b/applications/debug/unit_tests/minunit.h index 69bfba6d92..083db5a9a9 100644 --- a/applications/debug/unit_tests/minunit.h +++ b/applications/debug/unit_tests/minunit.h @@ -81,6 +81,7 @@ __attribute__((unused)) static void (*minunit_teardown)(void) = NULL; void minunit_print_progress(void); void minunit_print_fail(const char* error); +void minunit_printf_warning(const char* format, ...); /* Definitions */ #define MU_TEST(method_name) static void method_name(void) @@ -150,6 +151,10 @@ void minunit_print_fail(const char* error); minunit_end_proc_timer - minunit_proc_timer);) #define MU_EXIT_CODE minunit_fail +/* Warnings */ +#define mu_warn(message) \ + MU__SAFE_BLOCK(minunit_printf_warning("%s:%d: %s", __FILE__, __LINE__, message);) + /* Assertions */ #define mu_check(test) \ MU__SAFE_BLOCK( \ diff --git a/applications/debug/unit_tests/storage/dirwalk_test.c b/applications/debug/unit_tests/storage/dirwalk_test.c index e0842a7a43..19ac336fff 100644 --- a/applications/debug/unit_tests/storage/dirwalk_test.c +++ b/applications/debug/unit_tests/storage/dirwalk_test.c @@ -139,7 +139,7 @@ static bool write_file_13DA(Storage* storage, const char* path) { File* file = storage_file_alloc(storage); bool result = false; if(storage_file_open(file, path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { - result = storage_file_write(file, "13DA", 4) == 4; + result = (storage_file_write(file, "13DA", 4) == 4); } storage_file_close(file); storage_file_free(file); diff --git a/applications/debug/unit_tests/storage/storage_test.c b/applications/debug/unit_tests/storage/storage_test.c index 13188e5e0f..5ea36935b1 100644 --- a/applications/debug/unit_tests/storage/storage_test.c +++ b/applications/debug/unit_tests/storage/storage_test.c @@ -115,6 +115,66 @@ MU_TEST(storage_file_open_close) { furi_record_close(RECORD_STORAGE); } +static bool storage_file_read_write_test(File* file, uint8_t* data, size_t test_size) { + const char* filename = UNIT_TESTS_PATH("storage_chunk.test"); + + // fill with pattern + for(size_t i = 0; i < test_size; i++) { + data[i] = (i % 113); + } + + bool result = false; + do { + if(!storage_file_open(file, filename, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break; + if(test_size != storage_file_write(file, data, test_size)) break; + storage_file_close(file); + + // reset data + memset(data, 0, test_size); + + if(!storage_file_open(file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) break; + if(test_size != storage_file_read(file, data, test_size)) break; + storage_file_close(file); + + // check that data is correct + for(size_t i = 0; i < test_size; i++) { + if(data[i] != (i % 113)) { + break; + } + } + + result = true; + } while(false); + + return result; +} + +MU_TEST(storage_file_read_write_64k) { + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); + + size_t size_1k = 1024; + size_t size_64k = size_1k + size_1k * 63; + size_t size_65k = size_64k + size_1k; + size_t size_max = size_65k + 8; + + size_t max_ram_block = memmgr_heap_get_max_free_block(); + + if(max_ram_block < size_max) { + mu_warn("Not enough RAM for >64k block test"); + } else { + uint8_t* data = malloc(size_max); + mu_check(storage_file_read_write_test(file, data, size_1k)); + mu_check(storage_file_read_write_test(file, data, size_64k)); + mu_check(storage_file_read_write_test(file, data, size_65k)); + mu_check(storage_file_read_write_test(file, data, size_max)); + free(data); + } + + storage_file_free(file); + furi_record_close(RECORD_STORAGE); +} + MU_TEST_SUITE(storage_file) { storage_file_open_lock_setup(); MU_RUN_TEST(storage_file_open_close); @@ -122,6 +182,10 @@ MU_TEST_SUITE(storage_file) { storage_file_open_lock_teardown(); } +MU_TEST_SUITE(storage_file_64k) { + MU_RUN_TEST(storage_file_read_write_64k); +} + MU_TEST(storage_dir_open_close) { Storage* storage = furi_record_open(RECORD_STORAGE); File* file; @@ -640,6 +704,7 @@ MU_TEST_SUITE(test_md5_calc_suite) { int run_minunit_test_storage() { MU_RUN_SUITE(storage_file); + MU_RUN_SUITE(storage_file_64k); MU_RUN_SUITE(storage_dir); MU_RUN_SUITE(storage_rename); MU_RUN_SUITE(test_data_path); diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index 2f2b9e9811..60c7abd032 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -326,6 +326,7 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) { furi_hal_subghz_set_frequency_and_path(433920000); if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) { + mu_warn("SubGHZ transmission is prohibited"); return false; } diff --git a/applications/debug/unit_tests/test_index.c b/applications/debug/unit_tests/test_index.c index 7c1b6b4447..d7afaa3c4f 100644 --- a/applications/debug/unit_tests/test_index.c +++ b/applications/debug/unit_tests/test_index.c @@ -78,6 +78,16 @@ 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); diff --git a/applications/main/archive/helpers/archive_favorites.c b/applications/main/archive/helpers/archive_favorites.c index f395ee5a11..682aa6b383 100644 --- a/applications/main/archive/helpers/archive_favorites.c +++ b/applications/main/archive/helpers/archive_favorites.c @@ -12,12 +12,12 @@ static bool archive_favorites_read_line(File* file, FuriString* str_result) { bool result = false; do { - uint16_t read_count = storage_file_read(file, buffer, ARCHIVE_FAV_FILE_BUF_LEN); + size_t read_count = storage_file_read(file, buffer, ARCHIVE_FAV_FILE_BUF_LEN); if(storage_file_get_error(file) != FSE_OK) { return false; } - for(uint16_t i = 0; i < read_count; i++) { + for(size_t i = 0; i < read_count; i++) { if(buffer[i] == '\n') { uint32_t position = storage_file_tell(file); if(storage_file_get_error(file) != FSE_OK) { diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index 0a7b521273..e1b5e86841 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -946,7 +946,7 @@ static void subghz_cli_command(Cli* cli, FuriString* args, void* context) { static bool subghz_on_system_start_istream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { File* file = istream->state; - uint16_t ret = storage_file_read(file, buf, count); + size_t ret = storage_file_read(file, buf, count); return (count == ret); } diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c index 5769ced926..9baa738b79 100644 --- a/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c @@ -444,7 +444,7 @@ static bool notification_load_settings(NotificationApp* app) { storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING); if(fs_result) { - uint16_t bytes_count = storage_file_read(file, &settings, settings_size); + size_t bytes_count = storage_file_read(file, &settings, settings_size); if(bytes_count != settings_size) { fs_result = false; @@ -488,7 +488,7 @@ static bool notification_save_settings(NotificationApp* app) { storage_file_open(file, NOTIFICATION_SETTINGS_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS); if(fs_result) { - uint16_t bytes_count = storage_file_write(file, &settings, settings_size); + size_t bytes_count = storage_file_write(file, &settings, settings_size); if(bytes_count != settings_size) { fs_result = false; diff --git a/applications/services/rpc/rpc_storage.c b/applications/services/rpc/rpc_storage.c index ee024b823a..913d89f1af 100644 --- a/applications/services/rpc/rpc_storage.c +++ b/applications/services/rpc/rpc_storage.c @@ -466,7 +466,7 @@ static void rpc_system_storage_write_process(const PB_Main* request, void* conte request->content.storage_write_request.file.data->size) { uint8_t* buffer = request->content.storage_write_request.file.data->bytes; size_t buffer_size = request->content.storage_write_request.file.data->size; - uint16_t written_size = storage_file_write(file, buffer, buffer_size); + size_t written_size = storage_file_write(file, buffer, buffer_size); fs_operation_success = (written_size == buffer_size); } diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index 3caa155c7d..20a371fc08 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -123,7 +123,7 @@ bool storage_file_is_dir(File* file); * @param bytes_to_read number of bytes to read. Must be less than or equal to the size of the buffer. * @return actual number of bytes read (may be fewer than requested). */ -uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read); +size_t storage_file_read(File* file, void* buff, size_t bytes_to_read); /** * @brief Write bytes from a buffer to a file. @@ -133,7 +133,7 @@ uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read); * @param bytes_to_write number of bytes to write. Must be less than or equal to the size of the buffer. * @return actual number of bytes written (may be fewer than requested). */ -uint16_t storage_file_write(File* file, const void* buff, uint16_t bytes_to_write); +size_t storage_file_write(File* file, const void* buff, size_t bytes_to_write); /** * @brief Change the current access position in a file. @@ -207,7 +207,7 @@ bool storage_file_exists(Storage* storage, const char* path); * @param size data size to be copied, in bytes. * @return true if the data was successfully copied, false otherwise. */ -bool storage_file_copy_to_file(File* source, File* destination, uint32_t size); +bool storage_file_copy_to_file(File* source, File* destination, size_t size); /******************* Directory Functions *******************/ diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index 59489d459c..2927022a3f 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -198,15 +198,15 @@ static void storage_cli_read(Cli* cli, FuriString* path) { File* file = storage_file_alloc(api); if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { - const uint16_t buffer_size = 128; - uint16_t read_size = 0; + const size_t buffer_size = 128; + size_t read_size = 0; uint8_t* data = malloc(buffer_size); printf("Size: %lu\r\n", (uint32_t)storage_file_size(file)); do { read_size = storage_file_read(file, data, buffer_size); - for(uint16_t i = 0; i < read_size; i++) { + for(size_t i = 0; i < read_size; i++) { printf("%c", data[i]); } } while(read_size > 0); @@ -227,7 +227,7 @@ static void storage_cli_write(Cli* cli, FuriString* path) { Storage* api = furi_record_open(RECORD_STORAGE); File* file = storage_file_alloc(api); - const uint16_t buffer_size = 512; + const size_t buffer_size = 512; uint8_t* buffer = malloc(buffer_size); if(storage_file_open(file, furi_string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) { @@ -239,10 +239,10 @@ static void storage_cli_write(Cli* cli, FuriString* path) { uint8_t symbol = cli_getc(cli); if(symbol == CliSymbolAsciiETX) { - uint16_t write_size = read_index % buffer_size; + size_t write_size = read_index % buffer_size; if(write_size > 0) { - uint16_t written_size = storage_file_write(file, buffer, write_size); + size_t written_size = storage_file_write(file, buffer, write_size); if(written_size != write_size) { storage_cli_print_error(storage_file_get_error(file)); @@ -257,7 +257,7 @@ static void storage_cli_write(Cli* cli, FuriString* path) { read_index++; if(((read_index % buffer_size) == 0)) { - uint16_t written_size = storage_file_write(file, buffer, buffer_size); + size_t written_size = storage_file_write(file, buffer, buffer_size); if(written_size != buffer_size) { storage_cli_print_error(storage_file_get_error(file)); @@ -289,7 +289,7 @@ static void storage_cli_read_chunks(Cli* cli, FuriString* path, FuriString* args } else if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { uint64_t file_size = storage_file_size(file); - printf("Size: %lu\r\n", (uint32_t)file_size); + printf("Size: %llu\r\n", file_size); if(buffer_size) { uint8_t* data = malloc(buffer_size); @@ -297,8 +297,8 @@ static void storage_cli_read_chunks(Cli* cli, FuriString* path, FuriString* args printf("\r\nReady?\r\n"); cli_getc(cli); - uint16_t read_size = storage_file_read(file, data, buffer_size); - for(uint16_t i = 0; i < read_size; i++) { + size_t read_size = storage_file_read(file, data, buffer_size); + for(size_t i = 0; i < read_size; i++) { putchar(data[i]); } file_size -= read_size; @@ -335,7 +335,7 @@ static void storage_cli_write_chunk(Cli* cli, FuriString* path, FuriString* args size_t read_bytes = cli_read(cli, buffer, buffer_size); - uint16_t written_size = storage_file_write(file, buffer, read_bytes); + size_t written_size = storage_file_write(file, buffer, read_bytes); if(written_size != buffer_size) { storage_cli_print_error(storage_file_get_error(file)); diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index 1027d43101..666090346a 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -139,7 +139,7 @@ bool storage_file_close(File* file) { return S_RETURN_BOOL; } -uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read) { +static uint16_t storage_file_read_underlying(File* file, void* buff, uint16_t bytes_to_read) { if(bytes_to_read == 0) { return 0; } @@ -159,7 +159,8 @@ uint16_t storage_file_read(File* file, void* buff, uint16_t bytes_to_read) { return S_RETURN_UINT16; } -uint16_t storage_file_write(File* file, const void* buff, uint16_t bytes_to_write) { +static uint16_t + storage_file_write_underlying(File* file, const void* buff, uint16_t bytes_to_write) { if(bytes_to_write == 0) { return 0; } @@ -179,6 +180,40 @@ uint16_t storage_file_write(File* file, const void* buff, uint16_t bytes_to_writ return S_RETURN_UINT16; } +size_t storage_file_read(File* file, void* buff, size_t to_read) { + size_t total = 0; + + const size_t max_chunk = UINT16_MAX; + do { + const size_t chunk = MIN((to_read - total), max_chunk); + size_t read = storage_file_read_underlying(file, buff + total, chunk); + total += read; + + if(storage_file_get_error(file) != FSE_OK || read != chunk) { + break; + } + } while(total != to_read); + + return total; +} + +size_t storage_file_write(File* file, const void* buff, size_t to_write) { + size_t total = 0; + + const size_t max_chunk = UINT16_MAX; + do { + const size_t chunk = MIN((to_write - total), max_chunk); + size_t written = storage_file_write_underlying(file, buff + total, chunk); + total += written; + + if(storage_file_get_error(file) != FSE_OK || written != chunk) { + break; + } + } while(total != to_write); + + return total; +} + bool storage_file_seek(File* file, uint32_t offset, bool from_start) { S_FILE_API_PROLOGUE; S_API_PROLOGUE; @@ -252,7 +287,7 @@ bool storage_file_exists(Storage* storage, const char* path) { return exist; } -bool storage_file_copy_to_file(File* source, File* destination, uint32_t size) { +bool storage_file_copy_to_file(File* source, File* destination, size_t size) { uint8_t* buffer = malloc(FILE_BUFFER_SIZE); while(size) { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c index 8359c00be3..a5bf1b9d37 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c @@ -44,7 +44,7 @@ static bool storage_settings_scene_bench_write( } static bool - storage_settings_scene_bench_read(Storage* api, uint16_t size, uint8_t* data, uint32_t* speed) { + storage_settings_scene_bench_read(Storage* api, size_t size, uint8_t* data, uint32_t* speed) { File* file = storage_file_alloc(api); bool result = true; *speed = -1; @@ -82,7 +82,7 @@ static void storage_settings_scene_benchmark(StorageSettings* app) { bench_data[i] = (uint8_t)i; } - uint16_t bench_size[BENCH_COUNT] = {1, 8, 32, 256, 512, 1024}; + size_t bench_size[BENCH_COUNT] = {1, 8, 32, 256, 512, 1024}; uint32_t bench_w_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0}; uint32_t bench_r_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0}; diff --git a/applications/system/updater/util/update_task_worker_flasher.c b/applications/system/updater/util/update_task_worker_flasher.c index c560319928..1b4b079003 100644 --- a/applications/system/updater/util/update_task_worker_flasher.c +++ b/applications/system/updater/util/update_task_worker_flasher.c @@ -104,7 +104,7 @@ static bool update_task_write_stack_data(UpdateTask* update_task) { update_task_set_progress(update_task, UpdateTaskStageRadioWrite, 0); uint8_t* fw_block = malloc(FLASH_PAGE_SIZE); - uint16_t bytes_read = 0; + size_t bytes_read = 0; uint32_t element_offs = 0; while(element_offs < stack_size) { diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index b2c9445ffe..8a78cca413 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -101,7 +101,7 @@ static bool elf_read_string_from_offset(ELFFile* elf, off_t offset, FuriString* buffer[ELF_NAME_BUFFER_LEN] = 0; while(true) { - uint16_t read = storage_file_read(elf->fd, buffer, ELF_NAME_BUFFER_LEN); + size_t read = storage_file_read(elf->fd, buffer, ELF_NAME_BUFFER_LEN); furi_string_cat(name, buffer); if(strlen(buffer) < ELF_NAME_BUFFER_LEN) { result = true; diff --git a/lib/music_worker/music_worker.c b/lib/music_worker/music_worker.c index 61fc838f2e..279d126737 100644 --- a/lib/music_worker/music_worker.c +++ b/lib/music_worker/music_worker.c @@ -396,7 +396,7 @@ bool music_worker_load_rtttl_from_file(MusicWorker* instance, const char* file_p break; }; - uint16_t ret = 0; + size_t ret = 0; do { uint8_t buffer[65] = {0}; ret = storage_file_read(file, buffer, sizeof(buffer) - 1); diff --git a/lib/toolbox/crc32_calc.c b/lib/toolbox/crc32_calc.c index c0cd169b18..78295167f3 100644 --- a/lib/toolbox/crc32_calc.c +++ b/lib/toolbox/crc32_calc.c @@ -14,7 +14,7 @@ uint32_t crc32_calc_file(File* file, const FileCrcProgressCb progress_cb, void* uint32_t file_crc = 0; uint8_t* data_buffer = malloc(CRC_DATA_BUFFER_MAX_LEN); - uint16_t data_buffer_valid_len; + size_t data_buffer_valid_len; uint32_t file_size = storage_file_size(file); diff --git a/lib/toolbox/md5_calc.c b/lib/toolbox/md5_calc.c index b050295a14..7f335a33f2 100644 --- a/lib/toolbox/md5_calc.c +++ b/lib/toolbox/md5_calc.c @@ -5,13 +5,13 @@ bool md5_calc_file(File* file, const char* path, unsigned char output[16], FS_Er bool result = storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING); if(result) { - const uint16_t size_to_read = 512; + const size_t size_to_read = 512; uint8_t* data = malloc(size_to_read); md5_context* md5_ctx = malloc(sizeof(md5_context)); md5_starts(md5_ctx); while(true) { - uint16_t read_size = storage_file_read(file, data, size_to_read); + size_t read_size = storage_file_read(file, data, size_to_read); if(read_size == 0) break; md5_update(md5_ctx, data, read_size); } diff --git a/lib/toolbox/saved_struct.c b/lib/toolbox/saved_struct.c index 02b73f2104..2f1c09c8eb 100644 --- a/lib/toolbox/saved_struct.c +++ b/lib/toolbox/saved_struct.c @@ -46,7 +46,7 @@ bool saved_struct_save(const char* path, void* data, size_t size, uint8_t magic, header.flags = 0; header.timestamp = 0; - uint16_t bytes_count = storage_file_write(file, &header, sizeof(header)); + size_t bytes_count = storage_file_write(file, &header, sizeof(header)); bytes_count += storage_file_write(file, data, size); if(bytes_count != (size + sizeof(header))) { @@ -79,7 +79,7 @@ bool saved_struct_load(const char* path, void* data, size_t size, uint8_t magic, } if(result) { - uint16_t bytes_count = storage_file_read(file, &header, sizeof(SavedStructHeader)); + size_t bytes_count = storage_file_read(file, &header, sizeof(SavedStructHeader)); bytes_count += storage_file_read(file, data_read, size); if(bytes_count != (sizeof(SavedStructHeader) + size)) { @@ -146,7 +146,7 @@ bool saved_struct_get_payload_size( break; } - uint16_t bytes_count = storage_file_read(file, &header, sizeof(SavedStructHeader)); + size_t bytes_count = storage_file_read(file, &header, sizeof(SavedStructHeader)); if(bytes_count != sizeof(SavedStructHeader)) { FURI_LOG_E(TAG, "Failed to read header"); break; diff --git a/lib/toolbox/stream/file_stream.c b/lib/toolbox/stream/file_stream.c index 095dce472c..2b5348b3e8 100644 --- a/lib/toolbox/stream/file_stream.c +++ b/lib/toolbox/stream/file_stream.c @@ -134,31 +134,11 @@ static size_t file_stream_size(FileStream* stream) { } static size_t file_stream_write(FileStream* stream, const uint8_t* data, size_t size) { - // TODO FL-3545: cache - size_t need_to_write = size; - while(need_to_write > 0) { - uint16_t was_written = - storage_file_write(stream->file, data + (size - need_to_write), need_to_write); - need_to_write -= was_written; - - if(was_written == 0) break; - } - - return size - need_to_write; + return storage_file_write(stream->file, data, size); } static size_t file_stream_read(FileStream* stream, uint8_t* data, size_t size) { - // TODO FL-3545: cache - size_t need_to_read = size; - while(need_to_read > 0) { - uint16_t was_read = - storage_file_read(stream->file, data + (size - need_to_read), need_to_read); - need_to_read -= was_read; - - if(was_read == 0) break; - } - - return size - need_to_read; + return storage_file_read(stream->file, data, size); } static bool file_stream_delete_and_insert( diff --git a/lib/update_util/dfu_file.c b/lib/update_util/dfu_file.c index eef9f06459..85b661e8e0 100644 --- a/lib/update_util/dfu_file.c +++ b/lib/update_util/dfu_file.c @@ -22,7 +22,7 @@ uint8_t dfu_file_validate_headers(File* dfuf, const DfuValidationParams* referen DfuPrefix dfu_prefix = {0}; DfuSuffix dfu_suffix = {0}; - uint16_t bytes_read = 0; + size_t bytes_read = 0; if(!storage_file_is_open(dfuf) || !storage_file_seek(dfuf, 0, true)) { return 0; @@ -90,7 +90,7 @@ static DfuUpdateBlockResult dfu_file_perform_task_for_update_pages( } uint8_t* fw_block = malloc(FLASH_PAGE_SIZE); - uint16_t bytes_read = 0; + size_t bytes_read = 0; uint32_t element_offs = 0; while(element_offs < header->dwElementSize) { @@ -125,7 +125,7 @@ static DfuUpdateBlockResult dfu_file_perform_task_for_update_pages( bool dfu_file_process_targets(const DfuUpdateTask* task, File* dfuf, const uint8_t n_targets) { TargetPrefix target_prefix = {0}; ImageElementHeader image_element = {0}; - uint16_t bytes_read = 0; + size_t bytes_read = 0; if(!storage_file_seek(dfuf, sizeof(DfuPrefix), true)) { return UpdateBlockResult_Failed; diff --git a/lib/update_util/update_operation.c b/lib/update_util/update_operation.c index 0cecfc016a..39a7ea0752 100644 --- a/lib/update_util/update_operation.c +++ b/lib/update_util/update_operation.c @@ -85,7 +85,7 @@ bool update_operation_get_current_package_manifest_path(Storage* storage, FuriSt upd_file, UPDATE_FILE_POINTER_FN, FSAM_READ, FSOM_OPEN_EXISTING)) { break; } - uint16_t bytes_read = + size_t bytes_read = storage_file_read(upd_file, manifest_name_buffer, UPDATE_MANIFEST_MAX_PATH_LEN); if((bytes_read == 0) || (bytes_read == UPDATE_MANIFEST_MAX_PATH_LEN)) { break; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 8ed8f403c7..d861d85117 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,45.1,, +Version,+,46.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1376,7 +1376,7 @@ Function,+,furi_pubsub_subscribe,FuriPubSubSubscription*,"FuriPubSub*, FuriPubSu Function,+,furi_pubsub_unsubscribe,void,"FuriPubSub*, FuriPubSubSubscription*" Function,+,furi_record_close,void,const char* Function,+,furi_record_create,void,"const char*, void*" -Function,-,furi_record_destroy,_Bool,const char* +Function,+,furi_record_destroy,_Bool,const char* Function,+,furi_record_exists,_Bool,const char* Function,-,furi_record_init,void, Function,+,furi_record_open,void*,const char* @@ -2090,7 +2090,7 @@ Function,-,storage_dir_rewind,_Bool,File* Function,+,storage_error_get_desc,const char*,FS_Error Function,+,storage_file_alloc,File*,Storage* Function,+,storage_file_close,_Bool,File* -Function,+,storage_file_copy_to_file,_Bool,"File*, File*, uint32_t" +Function,+,storage_file_copy_to_file,_Bool,"File*, File*, size_t" Function,+,storage_file_eof,_Bool,File* Function,+,storage_file_exists,_Bool,"Storage*, const char*" Function,+,storage_file_free,void,File* @@ -2100,13 +2100,13 @@ Function,-,storage_file_get_internal_error,int32_t,File* Function,+,storage_file_is_dir,_Bool,File* Function,+,storage_file_is_open,_Bool,File* Function,+,storage_file_open,_Bool,"File*, const char*, FS_AccessMode, FS_OpenMode" -Function,+,storage_file_read,uint16_t,"File*, void*, uint16_t" +Function,+,storage_file_read,size_t,"File*, void*, size_t" Function,+,storage_file_seek,_Bool,"File*, uint32_t, _Bool" Function,+,storage_file_size,uint64_t,File* Function,+,storage_file_sync,_Bool,File* Function,+,storage_file_tell,uint64_t,File* Function,+,storage_file_truncate,_Bool,File* -Function,+,storage_file_write,uint16_t,"File*, const void*, uint16_t" +Function,+,storage_file_write,size_t,"File*, const void*, size_t" Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, FuriString*, uint8_t" Function,+,storage_get_pubsub,FuriPubSub*,Storage* Function,+,storage_int_backup,FS_Error,"Storage*, const char*" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 64695c2dbc..c50db0c77c 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,45.1,, +Version,+,46.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -1571,7 +1571,7 @@ Function,+,furi_pubsub_subscribe,FuriPubSubSubscription*,"FuriPubSub*, FuriPubSu Function,+,furi_pubsub_unsubscribe,void,"FuriPubSub*, FuriPubSubSubscription*" Function,+,furi_record_close,void,const char* Function,+,furi_record_create,void,"const char*, void*" -Function,-,furi_record_destroy,_Bool,const char* +Function,+,furi_record_destroy,_Bool,const char* Function,+,furi_record_exists,_Bool,const char* Function,-,furi_record_init,void, Function,+,furi_record_open,void*,const char* @@ -2717,7 +2717,7 @@ Function,-,storage_dir_rewind,_Bool,File* Function,+,storage_error_get_desc,const char*,FS_Error Function,+,storage_file_alloc,File*,Storage* Function,+,storage_file_close,_Bool,File* -Function,+,storage_file_copy_to_file,_Bool,"File*, File*, uint32_t" +Function,+,storage_file_copy_to_file,_Bool,"File*, File*, size_t" Function,+,storage_file_eof,_Bool,File* Function,+,storage_file_exists,_Bool,"Storage*, const char*" Function,+,storage_file_free,void,File* @@ -2727,13 +2727,13 @@ Function,-,storage_file_get_internal_error,int32_t,File* Function,+,storage_file_is_dir,_Bool,File* Function,+,storage_file_is_open,_Bool,File* Function,+,storage_file_open,_Bool,"File*, const char*, FS_AccessMode, FS_OpenMode" -Function,+,storage_file_read,uint16_t,"File*, void*, uint16_t" +Function,+,storage_file_read,size_t,"File*, void*, size_t" Function,+,storage_file_seek,_Bool,"File*, uint32_t, _Bool" Function,+,storage_file_size,uint64_t,File* Function,+,storage_file_sync,_Bool,File* Function,+,storage_file_tell,uint64_t,File* Function,+,storage_file_truncate,_Bool,File* -Function,+,storage_file_write,uint16_t,"File*, const void*, uint16_t" +Function,+,storage_file_write,size_t,"File*, const void*, size_t" Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, const char*, FuriString*, uint8_t" Function,+,storage_get_pubsub,FuriPubSub*,Storage* Function,+,storage_int_backup,FS_Error,"Storage*, const char*" From 1c3cbec661b735b08f8401f93a50a772aff48a62 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Sun, 26 Nov 2023 11:10:33 +0300 Subject: [PATCH 28/40] [FL-3640] NFC: Felica UID emulation (#3190) * Added basic template of Felica listener * Raw nfc felica listener functions * Added functions to setup chip for felica listener * Cleanup function templates from unnecessary parts * Removed todo comment * Updated api versions * Adjusted chip config for felica * Set proper chip passive target mode for felica * Added felica function to unit tests * Update furi_hal_nfc_felica.c * Removed duplication Co-authored-by: gornekich --- .../debug/unit_tests/nfc/nfc_transport.c | 15 ++ .../helpers/protocol_support/felica/felica.c | 10 +- lib/nfc/nfc.c | 18 ++- lib/nfc/nfc.h | 19 +++ lib/nfc/protocols/felica/felica.h | 2 + lib/nfc/protocols/felica/felica_listener.c | 79 ++++++++++ lib/nfc/protocols/felica/felica_listener.h | 14 ++ .../protocols/felica/felica_listener_defs.h | 13 ++ lib/nfc/protocols/felica/felica_listener_i.h | 21 +++ lib/nfc/protocols/nfc_listener_defs.c | 2 + targets/f7/api_symbols.csv | 2 + targets/f7/furi_hal/furi_hal_nfc_felica.c | 138 +++++++++++++++++- targets/furi_hal_include/furi_hal_nfc.h | 17 +++ 13 files changed, 346 insertions(+), 4 deletions(-) create mode 100644 lib/nfc/protocols/felica/felica_listener.c create mode 100644 lib/nfc/protocols/felica/felica_listener.h create mode 100644 lib/nfc/protocols/felica/felica_listener_defs.h create mode 100644 lib/nfc/protocols/felica/felica_listener_i.h diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index e2e313fdef..e9f4e21341 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -455,4 +455,19 @@ NfcError nfc_iso15693_listener_tx_sof(Nfc* instance) { return NfcErrorNone; } +NfcError nfc_felica_listener_set_sensf_res_data( + Nfc* instance, + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len) { + furi_assert(instance); + furi_assert(idm); + furi_assert(pmm); + furi_assert(idm_len == 8); + furi_assert(pmm_len == 8); + + return NfcErrorNone; +} + #endif diff --git a/applications/main/nfc/helpers/protocol_support/felica/felica.c b/applications/main/nfc/helpers/protocol_support/felica/felica.c index b3e629f4a5..f9c8491216 100644 --- a/applications/main/nfc/helpers/protocol_support/felica/felica.c +++ b/applications/main/nfc/helpers/protocol_support/felica/felica.c @@ -67,8 +67,14 @@ static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, uint32_t even return false; } +static void nfc_scene_emulate_on_enter_felica(NfcApp* instance) { + const FelicaData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolFelica); + instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolFelica, data); + nfc_listener_start(instance->listener, NULL, NULL); +} + const NfcProtocolSupportBase nfc_protocol_support_felica = { - .features = NfcProtocolFeatureNone, + .features = NfcProtocolFeatureEmulateUid, .scene_info = { @@ -102,7 +108,7 @@ const NfcProtocolSupportBase nfc_protocol_support_felica = { }, .scene_emulate = { - .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_enter = nfc_scene_emulate_on_enter_felica, .on_event = nfc_protocol_support_common_on_event_empty, }, }; diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index a7c4fe1a6d..6475cce435 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -76,7 +76,7 @@ static const FuriHalNfcTech nfc_tech_table[NfcModeNum][NfcTechNum] = { [NfcTechIso14443a] = FuriHalNfcTechIso14443a, [NfcTechIso14443b] = FuriHalNfcTechInvalid, [NfcTechIso15693] = FuriHalNfcTechIso15693, - [NfcTechFelica] = FuriHalNfcTechInvalid, + [NfcTechFelica] = FuriHalNfcTechFelica, }, }; @@ -646,4 +646,20 @@ NfcError nfc_iso15693_listener_tx_sof(Nfc* instance) { return ret; } +NfcError nfc_felica_listener_set_sensf_res_data( + Nfc* instance, + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len) { + furi_assert(instance); + furi_assert(idm); + furi_assert(pmm); + + FuriHalNfcError error = + furi_hal_nfc_felica_listener_set_sensf_res_data(idm, idm_len, pmm, pmm_len); + instance->comm_state = NfcCommStateIdle; + return nfc_process_hal_error(error); +} + #endif // APP_UNIT_TESTS diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 1e8f315a50..4f7980b026 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -351,6 +351,25 @@ NfcError nfc_iso14443a_listener_set_col_res_data( uint8_t* atqa, uint8_t sak); +/** + * @brief Set FeliCa collision resolution parameters in listener mode. + * + * Configures the NFC hardware for automatic collision resolution. + * + * @param[in,out] instance pointer to the instance to be configured. + * @param[in] idm pointer to a byte array containing the IDm. + * @param[in] idm_len IDm length in bytes. + * @param[in] pmm pointer to a byte array containing the PMm. + * @param[in] pmm_len PMm length in bytes. + * @returns NfcErrorNone on success, any other error code on failure. +*/ +NfcError nfc_felica_listener_set_sensf_res_data( + Nfc* instance, + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len); + /** * @brief Send ISO15693 Start of Frame pattern in listener mode * diff --git a/lib/nfc/protocols/felica/felica.h b/lib/nfc/protocols/felica/felica.h index da9d2294ee..31e040b8a1 100644 --- a/lib/nfc/protocols/felica/felica.h +++ b/lib/nfc/protocols/felica/felica.h @@ -14,6 +14,8 @@ extern "C" { #define FELICA_FDT_POLL_FC (10000U) #define FELICA_POLL_POLL_MIN_US (1280U) +#define FELICA_FDT_LISTEN_FC (1172) + #define FELICA_SYSTEM_CODE_CODE (0xFFFFU) #define FELICA_TIME_SLOT_1 (0x00U) #define FELICA_TIME_SLOT_2 (0x01U) diff --git a/lib/nfc/protocols/felica/felica_listener.c b/lib/nfc/protocols/felica/felica_listener.c new file mode 100644 index 0000000000..4e6c057854 --- /dev/null +++ b/lib/nfc/protocols/felica/felica_listener.c @@ -0,0 +1,79 @@ +#include "felica_listener_i.h" + +#include "nfc/protocols/nfc_listener_base.h" + +#define FELICA_LISTENER_MAX_BUFFER_SIZE (64) +#define TAG "Felica" + +FelicaListener* felica_listener_alloc(Nfc* nfc, FelicaData* data) { + furi_assert(nfc); + furi_assert(data); + + FelicaListener* instance = malloc(sizeof(FelicaListener)); + instance->nfc = nfc; + instance->data = data; + instance->tx_buffer = bit_buffer_alloc(FELICA_LISTENER_MAX_BUFFER_SIZE); + instance->rx_buffer = bit_buffer_alloc(FELICA_LISTENER_MAX_BUFFER_SIZE); + + nfc_set_fdt_listen_fc(instance->nfc, FELICA_FDT_LISTEN_FC); + + nfc_config(instance->nfc, NfcModeListener, NfcTechFelica); + nfc_felica_listener_set_sensf_res_data( + nfc, data->idm.data, sizeof(data->idm), data->pmm.data, sizeof(data->pmm)); + + return instance; +} + +void felica_listener_free(FelicaListener* instance) { + furi_assert(instance); + furi_assert(instance->tx_buffer); + + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + free(instance); +} + +void felica_listener_set_callback( + FelicaListener* listener, + NfcGenericCallback callback, + void* context) { + UNUSED(listener); + UNUSED(callback); + UNUSED(context); +} + +const FelicaData* felica_listener_get_data(const FelicaListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +NfcCommand felica_listener_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolInvalid); + furi_assert(event.event_data); + + FelicaListener* instance = context; + NfcEvent* nfc_event = event.event_data; + NfcCommand command = NfcCommandContinue; + + if(nfc_event->type == NfcEventTypeListenerActivated) { + instance->state = Felica_ListenerStateActivated; + FURI_LOG_D(TAG, "Activated"); + } else if(nfc_event->type == NfcEventTypeFieldOff) { + instance->state = Felica_ListenerStateIdle; + FURI_LOG_D(TAG, "Field Off"); + } else if(nfc_event->type == NfcEventTypeRxEnd) { + FURI_LOG_D(TAG, "Rx Done"); + } + return command; +} + +const NfcListenerBase nfc_listener_felica = { + .alloc = (NfcListenerAlloc)felica_listener_alloc, + .free = (NfcListenerFree)felica_listener_free, + .set_callback = (NfcListenerSetCallback)felica_listener_set_callback, + .get_data = (NfcListenerGetData)felica_listener_get_data, + .run = (NfcListenerRun)felica_listener_run, +}; \ No newline at end of file diff --git a/lib/nfc/protocols/felica/felica_listener.h b/lib/nfc/protocols/felica/felica_listener.h new file mode 100644 index 0000000000..d210befa57 --- /dev/null +++ b/lib/nfc/protocols/felica/felica_listener.h @@ -0,0 +1,14 @@ +#pragma once + +#include "felica.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct FelicaListener FelicaListener; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/nfc/protocols/felica/felica_listener_defs.h b/lib/nfc/protocols/felica/felica_listener_defs.h new file mode 100644 index 0000000000..19b252be59 --- /dev/null +++ b/lib/nfc/protocols/felica/felica_listener_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcListenerBase nfc_listener_felica; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/felica/felica_listener_i.h b/lib/nfc/protocols/felica/felica_listener_i.h new file mode 100644 index 0000000000..4fa25a1620 --- /dev/null +++ b/lib/nfc/protocols/felica/felica_listener_i.h @@ -0,0 +1,21 @@ +#include "felica_listener.h" + +#include + +typedef enum { + Felica_ListenerStateIdle, + Felica_ListenerStateActivated, +} FelicaListenerState; + +struct FelicaListener { + Nfc* nfc; + FelicaData* data; + FelicaListenerState state; + + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + + NfcGenericEvent generic_event; + NfcGenericCallback callback; + void* context; +}; \ No newline at end of file diff --git a/lib/nfc/protocols/nfc_listener_defs.c b/lib/nfc/protocols/nfc_listener_defs.c index 31f9bc16c6..2a6167e9cb 100644 --- a/lib/nfc/protocols/nfc_listener_defs.c +++ b/lib/nfc/protocols/nfc_listener_defs.c @@ -6,6 +6,7 @@ #include #include #include +#include const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_listener_iso14443_3a, @@ -18,4 +19,5 @@ const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolMfDesfire] = NULL, [NfcProtocolSlix] = &nfc_listener_slix, [NfcProtocolSt25tb] = NULL, + [NfcProtocolFelica] = &nfc_listener_felica, }; diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index c50db0c77c..9431028abe 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1287,6 +1287,7 @@ Function,+,furi_hal_nfc_abort,FuriHalNfcError, Function,+,furi_hal_nfc_acquire,FuriHalNfcError, Function,+,furi_hal_nfc_event_start,FuriHalNfcError, Function,+,furi_hal_nfc_event_stop,FuriHalNfcError, +Function,+,furi_hal_nfc_felica_listener_set_sensf_res_data,FuriHalNfcError,"const uint8_t*, const uint8_t, const uint8_t*, const uint8_t" Function,+,furi_hal_nfc_field_detect_start,FuriHalNfcError, Function,+,furi_hal_nfc_field_detect_stop,FuriHalNfcError, Function,+,furi_hal_nfc_field_is_present,_Bool, @@ -2316,6 +2317,7 @@ Function,+,nfc_dict_get_next_key,_Bool,"NfcDict*, uint8_t*, size_t" Function,+,nfc_dict_get_total_keys,uint32_t,NfcDict* Function,+,nfc_dict_is_key_present,_Bool,"NfcDict*, const uint8_t*, size_t" Function,+,nfc_dict_rewind,_Bool,NfcDict* +Function,+,nfc_felica_listener_set_sensf_res_data,NfcError,"Nfc*, const uint8_t*, const uint8_t, const uint8_t*, const uint8_t" Function,+,nfc_free,void,Nfc* Function,+,nfc_iso14443a_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,+,nfc_iso14443a_listener_tx_custom_parity,NfcError,"Nfc*, const BitBuffer*" diff --git a/targets/f7/furi_hal/furi_hal_nfc_felica.c b/targets/f7/furi_hal/furi_hal_nfc_felica.c index e4b8ac0ee6..f762a0ed32 100644 --- a/targets/f7/furi_hal/furi_hal_nfc_felica.c +++ b/targets/f7/furi_hal/furi_hal_nfc_felica.c @@ -1,6 +1,9 @@ #include "furi_hal_nfc_i.h" #include "furi_hal_nfc_tech_i.h" +// Prevent FDT timer from starting +#define FURI_HAL_NFC_FELICA_LISTENER_FDT_COMP_FC (INT32_MAX) + static FuriHalNfcError furi_hal_nfc_felica_poller_init(FuriHalSpiBusHandle* handle) { // Enable Felica mode, AM modulation st25r3916_change_reg_bits( @@ -50,6 +53,126 @@ static FuriHalNfcError furi_hal_nfc_felica_poller_deinit(FuriHalSpiBusHandle* ha return FuriHalNfcErrorNone; } +static FuriHalNfcError furi_hal_nfc_felica_listener_init(FuriHalSpiBusHandle* handle) { + furi_assert(handle); + st25r3916_write_reg( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | + ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); + + // Enable Target Felica mode, AM modulation + st25r3916_write_reg( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om2 | ST25R3916_REG_MODE_tr_am); + + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_BIT_RATE, + ST25R3916_REG_BIT_RATE_txrate_mask | ST25R3916_REG_BIT_RATE_rxrate_mask, + ST25R3916_REG_BIT_RATE_txrate_212 | ST25R3916_REG_BIT_RATE_rxrate_212); + + // Receive configuration + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF1, + ST25R3916_REG_RX_CONF1_lp0 | ST25R3916_REG_RX_CONF1_hz_12_80khz); + + // AGC enabled, ratio 3:1, squelch after TX + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF2, + ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_m | + ST25R3916_REG_RX_CONF2_agc_en | ST25R3916_REG_RX_CONF2_sqm_dyn); + // HF operation, full gain on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); + // No gain reduction on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); + // 10% ASK modulation + st25r3916_write_reg(handle, ST25R3916_REG_TX_DRIVER, ST25R3916_REG_TX_DRIVER_am_mod_10percent); + + // Correlator setup + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s6 | ST25R3916_REG_CORR_CONF1_corr_s4 | + ST25R3916_REG_CORR_CONF1_corr_s2); + + // Sleep mode disable, 424kHz mode off + st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); + + st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, 0x02); + + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + uint32_t interrupts = + (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | + ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | + ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE | + ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X | + ST25R3916_IRQ_MASK_WU_A); + // Clear interrupts + st25r3916_get_irq(handle); + + st25r3916_write_reg( + handle, + ST25R3916_REG_PASSIVE_TARGET, + ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a | ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p | + ST25R3916_REG_PASSIVE_TARGET_fdel_1); + // Enable interrupts + st25r3916_mask_irq(handle, ~interrupts); + st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SENSE); + + return FuriHalNfcErrorNone; +} + +static FuriHalNfcError furi_hal_nfc_felica_listener_deinit(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + return FuriHalNfcErrorNone; +} + +static FuriHalNfcEvent furi_hal_nfc_felica_listener_wait_event(uint32_t timeout_ms) { + UNUSED(timeout_ms); + FuriHalNfcEvent event = furi_hal_nfc_wait_event_common(timeout_ms); + + return event; +} + +FuriHalNfcError furi_hal_nfc_felica_listener_tx( + FuriHalSpiBusHandle* handle, + const uint8_t* tx_data, + size_t tx_bits) { + UNUSED(handle); + UNUSED(tx_data); + UNUSED(tx_bits); + return FuriHalNfcErrorNone; +} + +FuriHalNfcError furi_hal_nfc_felica_listener_sleep(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + return FuriHalNfcErrorNone; +} + +FuriHalNfcError furi_hal_nfc_felica_listener_idle(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + return FuriHalNfcErrorNone; +} + +FuriHalNfcError furi_hal_nfc_felica_listener_set_sensf_res_data( + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len) { + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + // Write PT Memory + uint8_t pt_memory[19] = {}; + pt_memory[2] = 0x01; + memcpy(pt_memory + 3, idm, idm_len); + memcpy(pt_memory + 3 + idm_len, pmm, pmm_len); + st25r3916_write_ptf_mem(handle, pt_memory, sizeof(pt_memory)); + return FuriHalNfcErrorNone; +} + const FuriHalNfcTechBase furi_hal_nfc_felica = { .poller = { @@ -65,5 +188,18 @@ const FuriHalNfcTechBase furi_hal_nfc_felica = { .rx = furi_hal_nfc_common_fifo_rx, }, - .listener = {}, + .listener = + { + .compensation = + { + .fdt = FURI_HAL_NFC_FELICA_LISTENER_FDT_COMP_FC, + }, + .init = furi_hal_nfc_felica_listener_init, + .deinit = furi_hal_nfc_felica_listener_deinit, + .wait_event = furi_hal_nfc_felica_listener_wait_event, + .tx = furi_hal_nfc_felica_listener_tx, + .rx = furi_hal_nfc_common_fifo_rx, + .sleep = furi_hal_nfc_felica_listener_sleep, + .idle = furi_hal_nfc_felica_listener_idle, + }, }; diff --git a/targets/furi_hal_include/furi_hal_nfc.h b/targets/furi_hal_include/furi_hal_nfc.h index ad4080e264..3d145d1002 100644 --- a/targets/furi_hal_include/furi_hal_nfc.h +++ b/targets/furi_hal_include/furi_hal_nfc.h @@ -452,6 +452,23 @@ FuriHalNfcError furi_hal_nfc_iso14443a_listener_tx_custom_parity( */ FuriHalNfcError furi_hal_nfc_iso15693_listener_tx_sof(); +/** + * @brief Set FeliCa collision resolution parameters in listener mode. + * + * Configures the NFC hardware for automatic collision resolution. + * + * @param[in] idm pointer to a byte array containing the IDm. + * @param[in] idm_len IDm length in bytes. + * @param[in] pmm pointer to a byte array containing the PMm. + * @param[in] pmm_len PMm length in bytes. + * @returns NfcErrorNone on success, any other error code on failure. +*/ +FuriHalNfcError furi_hal_nfc_felica_listener_set_sensf_res_data( + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len); + #ifdef __cplusplus } #endif From f9101d80840b4b7ef7146e41bba99aac881bbfca Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Sun, 26 Nov 2023 12:20:49 +0400 Subject: [PATCH 29/40] [FL-3686] Mifare Classic fixes (#3221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update Mifare Classic generators to create more accuate data * Check the transfer buffer validity for NACK * Fix the AC issues * CRC errors don't really affect emulation, checking for them isn't worth it * Make ATQA logic a bit easier to understand * mf classic: change log level * mf classic: fix log level Co-authored-by: gornekich Co-authored-by: あく --- lib/nfc/helpers/nfc_data_generator.c | 41 ++++++++++++------- lib/nfc/protocols/mf_classic/mf_classic.c | 13 +++--- lib/nfc/protocols/mf_classic/mf_classic.h | 2 + .../mf_classic/mf_classic_listener.c | 25 ++++++++++- .../mf_classic/mf_classic_listener_i.h | 1 + 5 files changed, 60 insertions(+), 22 deletions(-) diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 011f9f6db7..21f062605b 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -329,9 +329,23 @@ static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { static void nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) { data->iso14443_3a_data->uid_len = uid_len; - data->iso14443_3a_data->atqa[0] = 0x44; + data->iso14443_3a_data->atqa[0] = 0x00; data->iso14443_3a_data->atqa[1] = 0x00; - data->iso14443_3a_data->sak = 0x08; + data->iso14443_3a_data->sak = 0x00; + // Calculate the proper ATQA and SAK + if(uid_len == 7) { + data->iso14443_3a_data->atqa[0] |= 0x40; + } + if(type == MfClassicType1k) { + data->iso14443_3a_data->atqa[0] |= 0x04; + data->iso14443_3a_data->sak = 0x08; + } else if(type == MfClassicType4k) { + data->iso14443_3a_data->atqa[0] |= 0x02; + data->iso14443_3a_data->sak = 0x18; + } else if(type == MfClassicTypeMini) { + data->iso14443_3a_data->atqa[0] |= 0x08; + data->iso14443_3a_data->sak = 0x09; + } data->type = type; } @@ -343,6 +357,11 @@ static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t sec_tr->access_bits.data[2] = 0x80; sec_tr->access_bits.data[3] = 0x69; // Nice + for(int i = 0; i < 6; i++) { + sec_tr->key_a.data[i] = 0xFF; + sec_tr->key_b.data[i] = 0xFF; + } + mf_classic_set_block_read(data, block, &data->block[block]); mf_classic_set_key_found( data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF); @@ -396,41 +415,35 @@ static void nfc_generate_mf_classic(NfcDevice* nfc_device, uint8_t uid_len, MfCl uint16_t block_num = mf_classic_get_total_block_num(type); if(type == MfClassicType4k) { - // Set every block to 0xFF + // Set every block to 0x00 for(uint16_t i = 1; i < block_num; i++) { if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { - memset(&mfc_data->block[i].data, 0xFF, 16); + memset(&mfc_data->block[i].data, 0x00, 16); } mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } - // Set SAK to 18 - mfc_data->iso14443_3a_data->sak = 0x18; } else if(type == MfClassicType1k) { - // Set every block to 0xFF + // Set every block to 0x00 for(uint16_t i = 1; i < block_num; i++) { if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { - memset(&mfc_data->block[i].data, 0xFF, 16); + memset(&mfc_data->block[i].data, 0x00, 16); } mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } - // Set SAK to 08 - mfc_data->iso14443_3a_data->sak = 0x08; } else if(type == MfClassicTypeMini) { - // Set every block to 0xFF + // Set every block to 0x00 for(uint16_t i = 1; i < block_num; i++) { if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { - memset(&mfc_data->block[i].data, 0xFF, 16); + memset(&mfc_data->block[i].data, 0x00, 16); } mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } - // Set SAK to 09 - mfc_data->iso14443_3a_data->sak = 0x09; } nfc_generate_mf_classic_block_0( diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 400cf0d7fb..e68e8c7187 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -606,6 +606,7 @@ static bool mf_classic_is_allowed_access_sector_trailer( uint8_t* access_bits_arr = sec_tr->access_bits.data; uint8_t AC = ((access_bits_arr[1] >> 5) & 0x04) | ((access_bits_arr[2] >> 2) & 0x02) | ((access_bits_arr[2] >> 7) & 0x01); + FURI_LOG_T("NFC", "AC: %02X", AC); switch(action) { case MfClassicActionKeyARead: { @@ -615,20 +616,20 @@ static bool mf_classic_is_allowed_access_sector_trailer( case MfClassicActionKeyBWrite: { return ( (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x01)) || - (key_type == MfClassicKeyTypeB && (AC == 0x04 || AC == 0x03))); + (key_type == MfClassicKeyTypeB && + (AC == 0x00 || AC == 0x04 || AC == 0x03 || AC == 0x01))); } case MfClassicActionKeyBRead: { - return (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x02 || AC == 0x01)); + return (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x02 || AC == 0x01)) || + (key_type == MfClassicKeyTypeB && (AC == 0x00 || AC == 0x02 || AC == 0x01)); } case MfClassicActionACRead: { - return ( - (key_type == MfClassicKeyTypeA) || - (key_type == MfClassicKeyTypeB && !(AC == 0x00 || AC == 0x02 || AC == 0x01))); + return ((key_type == MfClassicKeyTypeA) || (key_type == MfClassicKeyTypeB)); } case MfClassicActionACWrite: { return ( (key_type == MfClassicKeyTypeA && (AC == 0x01)) || - (key_type == MfClassicKeyTypeB && (AC == 0x03 || AC == 0x05))); + (key_type == MfClassicKeyTypeB && (AC == 0x01 || AC == 0x03 || AC == 0x05))); } default: return false; diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index f180411df5..146e6a6f15 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -19,6 +19,8 @@ extern "C" { #define MF_CLASSIC_CMD_HALT_LSB (0x00) #define MF_CLASSIC_CMD_ACK (0x0A) #define MF_CLASSIC_CMD_NACK (0x00) +#define MF_CLASSIC_CMD_NACK_TRANSFER_INVALID (0x04) +#define MF_CLASSIC_CMD_NACK_TRANSFER_CRC_ERROR (0x01) #define MF_CLASSIC_TOTAL_SECTORS_MAX (40) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index f7bd5b3f45..fb12ba8a95 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -34,6 +34,7 @@ static void mf_classic_listener_reset_state(MfClassicListener* instance) { instance->cmd_in_progress = false; instance->current_cmd_handler_idx = 0; instance->transfer_value = 0; + instance->transfer_valid = false; instance->value_cmd = MfClassicValueCommandInvalid; } @@ -154,7 +155,7 @@ static MfClassicListenerCommand uint32_t nt_num = nfc_util_bytes2num(instance->auth_context.nt.data, sizeof(MfClassicNt)); uint32_t secret_poller = ar_num ^ crypto1_word(instance->crypto, 0, 0); if(secret_poller != prng_successor(nt_num, 64)) { - FURI_LOG_D( + FURI_LOG_T( TAG, "Wrong reader key: %08lX != %08lX", secret_poller, prng_successor(nt_num, 64)); mf_classic_listener_reset_state(instance); break; @@ -272,6 +273,17 @@ static MfClassicListenerCommand mf_classic_listener_write_block_second_part_hand if(mf_classic_is_sector_trailer(block_num)) { MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)█ + + // Check if any writing is allowed + if(!mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionKeyAWrite) && + !mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionKeyBWrite) && + !mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionACWrite)) { + break; + } + if(mf_classic_is_allowed_access( instance->data, block_num, key_type, MfClassicActionKeyAWrite)) { bit_buffer_write_bytes_mid(buff, sec_tr->key_a.data, 0, sizeof(MfClassicKey)); @@ -338,6 +350,7 @@ static MfClassicListenerCommand break; } + instance->transfer_valid = true; instance->cmd_in_progress = true; instance->current_cmd_handler_idx++; command = MfClassicListenerCommandAck; @@ -382,6 +395,7 @@ static MfClassicListenerCommand } instance->transfer_value += data; + instance->transfer_valid = true; instance->cmd_in_progress = true; instance->current_cmd_handler_idx++; @@ -411,6 +425,7 @@ static MfClassicListenerCommand mf_classic_value_to_block( instance->transfer_value, block_num, &instance->data->block[block_num]); instance->transfer_value = 0; + instance->transfer_valid = false; command = MfClassicListenerCommandAck; } while(false); @@ -581,7 +596,13 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { if(mfc_command == MfClassicListenerCommandAck) { mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_ACK); } else if(mfc_command == MfClassicListenerCommandNack) { - mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_NACK); + // Calculate nack based on the transfer buffer validity + uint8_t nack = MF_CLASSIC_CMD_NACK; + if(!instance->transfer_valid) { + nack += MF_CLASSIC_CMD_NACK_TRANSFER_INVALID; + } + + mf_classic_listener_send_short_frame(instance, nack); } else if(mfc_command == MfClassicListenerCommandSilent) { command = NfcCommandReset; } else if(mfc_command == MfClassicListenerCommandSleep) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h index 4b040bec12..52273be9c2 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h @@ -42,6 +42,7 @@ struct MfClassicListener { // Value operation data int32_t transfer_value; + bool transfer_valid; MfClassicValueCommand value_cmd; NfcGenericEvent generic_event; From ff129e524a89fddaed7b84a4a5af5928daa97c42 Mon Sep 17 00:00:00 2001 From: Evgeny Stepanischev Date: Thu, 30 Nov 2023 12:38:48 +0300 Subject: [PATCH 30/40] Allows you to use UCS-2 in canvas_glyph_width (#3226) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * allows you to use UCS-2 in canvas_glyph_width * Sync API Symbols Co-authored-by: あく --- applications/services/gui/canvas.c | 2 +- applications/services/gui/canvas.h | 2 +- targets/f18/api_symbols.csv | 4 ++-- targets/f7/api_symbols.csv | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 85c0528530..44adcd9395 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -202,7 +202,7 @@ uint16_t canvas_string_width(Canvas* canvas, const char* str) { return u8g2_GetStrWidth(&canvas->fb, str); } -uint8_t canvas_glyph_width(Canvas* canvas, char symbol) { +uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol) { furi_assert(canvas); return u8g2_GetGlyphWidth(&canvas->fb, symbol); } diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index f34d02bfba..a369e213bd 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -214,7 +214,7 @@ uint16_t canvas_string_width(Canvas* canvas, const char* str); * * @return width in pixels */ -uint8_t canvas_glyph_width(Canvas* canvas, char symbol); +uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol); /** Draw bitmap picture at position defined by x,y. * diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index d861d85117..7835718def 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,46.0,, +Version,+,47.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -633,7 +633,7 @@ Function,+,canvas_draw_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align Function,+,canvas_draw_triangle,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, CanvasDirection" Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font" -Function,+,canvas_glyph_width,uint8_t,"Canvas*, char" +Function,+,canvas_glyph_width,uint8_t,"Canvas*, uint16_t" Function,+,canvas_height,uint8_t,const Canvas* Function,+,canvas_invert_color,void,Canvas* Function,+,canvas_reset,void,Canvas* diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 9431028abe..f31349f9c9 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,46.0,, +Version,+,47.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -722,7 +722,7 @@ Function,+,canvas_draw_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align Function,+,canvas_draw_triangle,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, CanvasDirection" Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font" -Function,+,canvas_glyph_width,uint8_t,"Canvas*, char" +Function,+,canvas_glyph_width,uint8_t,"Canvas*, uint16_t" Function,+,canvas_height,uint8_t,const Canvas* Function,+,canvas_invert_color,void,Canvas* Function,+,canvas_reset,void,Canvas* From a849d49c92ff6d015d558717c9bb5c72ad074d86 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:51:38 +0400 Subject: [PATCH 31/40] [FL-3682] Add the secret door animation (#3233) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../external/L2_Secret_door_128x64/frame_0.png | Bin 0 -> 1648 bytes .../external/L2_Secret_door_128x64/frame_1.png | Bin 0 -> 1655 bytes .../external/L2_Secret_door_128x64/frame_10.png | Bin 0 -> 1552 bytes .../external/L2_Secret_door_128x64/frame_11.png | Bin 0 -> 1548 bytes .../external/L2_Secret_door_128x64/frame_12.png | Bin 0 -> 1577 bytes .../external/L2_Secret_door_128x64/frame_13.png | Bin 0 -> 1541 bytes .../external/L2_Secret_door_128x64/frame_14.png | Bin 0 -> 1578 bytes .../external/L2_Secret_door_128x64/frame_15.png | Bin 0 -> 1897 bytes .../external/L2_Secret_door_128x64/frame_16.png | Bin 0 -> 1918 bytes .../external/L2_Secret_door_128x64/frame_17.png | Bin 0 -> 1882 bytes .../external/L2_Secret_door_128x64/frame_18.png | Bin 0 -> 1907 bytes .../external/L2_Secret_door_128x64/frame_19.png | Bin 0 -> 1974 bytes .../external/L2_Secret_door_128x64/frame_2.png | Bin 0 -> 1636 bytes .../external/L2_Secret_door_128x64/frame_20.png | Bin 0 -> 1937 bytes .../external/L2_Secret_door_128x64/frame_21.png | Bin 0 -> 1894 bytes .../external/L2_Secret_door_128x64/frame_22.png | Bin 0 -> 1923 bytes .../external/L2_Secret_door_128x64/frame_23.png | Bin 0 -> 1966 bytes .../external/L2_Secret_door_128x64/frame_24.png | Bin 0 -> 1958 bytes .../external/L2_Secret_door_128x64/frame_25.png | Bin 0 -> 1946 bytes .../external/L2_Secret_door_128x64/frame_26.png | Bin 0 -> 1881 bytes .../external/L2_Secret_door_128x64/frame_27.png | Bin 0 -> 1902 bytes .../external/L2_Secret_door_128x64/frame_28.png | Bin 0 -> 1969 bytes .../external/L2_Secret_door_128x64/frame_29.png | Bin 0 -> 2094 bytes .../external/L2_Secret_door_128x64/frame_3.png | Bin 0 -> 1599 bytes .../external/L2_Secret_door_128x64/frame_30.png | Bin 0 -> 2028 bytes .../external/L2_Secret_door_128x64/frame_31.png | Bin 0 -> 1922 bytes .../external/L2_Secret_door_128x64/frame_32.png | Bin 0 -> 1900 bytes .../external/L2_Secret_door_128x64/frame_33.png | Bin 0 -> 1938 bytes .../external/L2_Secret_door_128x64/frame_34.png | Bin 0 -> 1923 bytes .../external/L2_Secret_door_128x64/frame_35.png | Bin 0 -> 1913 bytes .../external/L2_Secret_door_128x64/frame_36.png | Bin 0 -> 1937 bytes .../external/L2_Secret_door_128x64/frame_37.png | Bin 0 -> 1944 bytes .../external/L2_Secret_door_128x64/frame_38.png | Bin 0 -> 1683 bytes .../external/L2_Secret_door_128x64/frame_39.png | Bin 0 -> 1662 bytes .../external/L2_Secret_door_128x64/frame_4.png | Bin 0 -> 1618 bytes .../external/L2_Secret_door_128x64/frame_40.png | Bin 0 -> 1725 bytes .../external/L2_Secret_door_128x64/frame_41.png | Bin 0 -> 1654 bytes .../external/L2_Secret_door_128x64/frame_42.png | Bin 0 -> 1495 bytes .../external/L2_Secret_door_128x64/frame_43.png | Bin 0 -> 1440 bytes .../external/L2_Secret_door_128x64/frame_44.png | Bin 0 -> 1445 bytes .../external/L2_Secret_door_128x64/frame_45.png | Bin 0 -> 1464 bytes .../external/L2_Secret_door_128x64/frame_46.png | Bin 0 -> 1446 bytes .../external/L2_Secret_door_128x64/frame_47.png | Bin 0 -> 1369 bytes .../external/L2_Secret_door_128x64/frame_48.png | Bin 0 -> 1529 bytes .../external/L2_Secret_door_128x64/frame_49.png | Bin 0 -> 1851 bytes .../external/L2_Secret_door_128x64/frame_5.png | Bin 0 -> 1625 bytes .../external/L2_Secret_door_128x64/frame_50.png | Bin 0 -> 2132 bytes .../external/L2_Secret_door_128x64/frame_51.png | Bin 0 -> 2258 bytes .../external/L2_Secret_door_128x64/frame_52.png | Bin 0 -> 1615 bytes .../external/L2_Secret_door_128x64/frame_6.png | Bin 0 -> 1591 bytes .../external/L2_Secret_door_128x64/frame_7.png | Bin 0 -> 1671 bytes .../external/L2_Secret_door_128x64/frame_8.png | Bin 0 -> 1612 bytes .../external/L2_Secret_door_128x64/frame_9.png | Bin 0 -> 1575 bytes .../external/L2_Secret_door_128x64/meta.txt | 14 ++++++++++++++ assets/dolphin/external/manifest.txt | 7 +++++++ 55 files changed, 21 insertions(+) create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_0.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_1.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_10.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_11.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_12.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_13.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_14.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_15.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_16.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_17.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_18.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_19.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_2.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_20.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_21.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_22.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_23.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_24.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_25.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_26.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_27.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_28.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_29.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_3.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_30.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_31.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_32.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_33.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_34.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_35.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_36.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_37.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_38.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_39.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_4.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_40.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_41.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_42.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_43.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_44.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_45.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_46.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_47.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_48.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_49.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_5.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_50.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_51.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_52.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_6.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_7.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_8.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_9.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/meta.txt diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_0.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_0.png new file mode 100644 index 0000000000000000000000000000000000000000..8f29d5e2c7065c50e1ff361f437e85f24cfd1113 GIT binary patch literal 1648 zcmV-$29NoPP)*aVU(87^MRcYcl-tDPo zmNCXY9(*14eILuRjD4@EZ*Ah|!IxsITF`^<#g~!VNC?eH+ zq&SYqm#*u;p8-S*w`djniE6)12!YO}L;02`Yx3=CA;m5LsVY4tJ*GWIv~|cOP(<=& zWWPl#qNs>`D>8U7z#)7ez)}vvq_j?=rJbcQ?(x~3Vxl~C6lj`!rDu^kK+^|Q185h} zl>1EuACkg89ho>UmO?!z)0|6-9%c$aTRP;qb+Idf3oxU6FEV8L;q;?jkc%;Ck>po3FFZK+}qLCf7~s8$q9_=&y7hl3!6!-o0okg>1gBQd_-w|FVoN zcAax@q>*yZNBZ~5d0Mpej8G~NIbH2Minp(XRR=F;fm?s3yEwAo)A;ZzdNkCdP*cE_ zmCeCDA(L}G@>>4KR8tUi@86E%Wt?$VT|MJ0^}O$(fEh98X{a=*?r zn4x1DK!i}lGAlhZJugekGnQ-$pvE;LLNx+-XV3j;6n~o+4Cl9j$P~&8sYf7Epic1c z%4s3{r9E9$x;1Lgg7dU#ilkON-+NQ5qbukRWcc=`Y&;TN3GO6tF5*^)=2rB=Qv20a z6J%*1knX4{-Wt|iWzeS906ZE@(A=g8FO&PC^#ABnCXs*A$BsYKUil zGADb6dt|K?jsToFq>!;LN#9G#^l~J>L}g7kG~PST?;iAc*yy2_5zO}ptnfn(!V6PZ zQu;iLcSn;SkB_SqeH@#le8~vL$Q4i7;>22eW@{Ch8(0P4Ckw&|Hck252*!}7PEloC ztuM|1QMk2ku0`7GPh*ojTr&nKWSHo?pWi!hEHreECY4*9CB+&|tNYzhVfU;w$ryEH4?T zlR&FBh%&`P;(Yc^u*TOBhd}ong%uqFc{KosG)bh-uTUdIjhW9wtUFj!!1;{-oPo7F z{7*>x_zYpLJJS#%XIFW)qQ;Rjpw21&v1rdI&_lF+(lBWX^~kCjT_<@c5)rNFaP;p6 zwC-+0y*g6^M21UVj;w}Ajc=5$=CRpGK<~{{EQ&@6e=^}}67MaPSlqNC}g0Ibb z6;cZ!^AQQs&@93yH^9g|=OqGEbG^l2)Ci>RV_u@GibktnMv!?$YaQzOnR7V5G=+7+ zI;SlHbVmk6XlO*J@GaeADyYNrHGa7qDyTZse1(1&AbDaps+OEJ-g&O3Aj`A8&%O5? z5&3q>W6cmlP)QpZV?ftWo~XyukgxIYrA5#4qx(Hn)99ZJ#(4doL6Ha`S*#@Ju1NCf zNYE7tH92|vyXA|V_c95rDxcCo=uJB4YiC55pQHDV@UMBkx4&Dyp0U0~02GJ^XTAKv uvGP^_V~Dv4JUBu6!8lgFsR;1kckmCdW1|lcRm-RV0000^@RCt{2UD=kKFbuVG`2Sy~4^w9pMcb8SAQSEj4cM}*-Ga8g zwYIk#OR(>I>%F&qpBM3<(|a%A>=%zxYBxR(TZMJrI1bhN+Nwj!jbE&At~&+XD8+36 zUyf}R;cu%gv?{&gBp}VNl5cMdj)8-@Z>cZnez_4;$b!?Tl&@+4+`^)ZeVg(JB1S-A z$;TSc*O`TA09lKxX6{pGq0Qe@nF4VUwe*pDR={ctnoi~HN z@B1FHK+mFAF!yQD6zIv#8@p1b{fE9?xL7IRR{krb(5}fPqHM30n8h;!@US1T;v)(^ zFC5OyM-h?BDual|iRk?dty#Kg=-0x&Mq6?iP3dP8(r?E=t2rUvNAL-!1Vq8w96B#k>1&1% z?a4&3@B91r0Nnef(CZOB14#WaQ)@&OiYOj2GAS~nplN-x!kdIM6g+$6$#_mgSzcK8 zj*S|xnoeeq#M1a>uY)TQ^$<-NX!??rCh;H@$I^3ceT|CKc@A(xY=G|))!e+>WAam3O<{eD&s?Hnb~&_T5X~AQL;@}dNyeD4THq4Bxe z^AThtXju(_RM1%gMVcaLG^6i9tZ`X>vWOZx`d)^QD>Hy2tv=FAM`&rSTWvk*zIEiw zVD<>Ajpw|80}X_01Vb41b&7c4zxTnTRxV3t8zQD;0)`_0D=AbA^YAzQpk^Q7mz z-*81EpqNep*)CS3FTPUo(i#Xn-lTrRN}yfL0oVYz$7@$_zV(|TqWG1?SOi*^@kk@c zHlotUKzgN{LyH%$88rI>=SWCRsG}pnKy;nwUk{H8kv2KTm2R3}HTqmg)QhAp-MCMm zd7Zp7z?F=q$fNi3Yz3n)Ds-C4eS5q{FCOhgF(HiDxJR-ew3d{46NWi_G zhDgcNuL><9Nix0SX<$Q-a1qbxvGa)&^%m{$5oGm56)P`gFVl;B7r8bt9!Zy z$&d#!ia$~oVg%p@!Sk|ou!$$NdHv_c>;5nJ!i+DP(=4o#KOW-FO>$!Dr zfYw2D{0h1C)?WXC2+d2i9PKrI=(xY8_}27d&kOxhDn#osi(Yij+g}go%y3vCU5X5! zSlpq=G^V(WW(@$vSVuhtSgC<;LL2i}y`CepNA&m|Ss!UOjj`q@VIGq_YJ8K|TR3|E zaM&l~)lMKkzgkAXnfO-44`lN3QQ$mnk=(;QT^sXBI3hiH^ds_Kjpqj;RzG_%HGY4Z zvN_K7OwXAj1^5i8)4Q*OrK2E{<5mbeYk-+FRb}wn+FI(hdM(mC4-(DZ`)dl|6D-Cx zL>QYDsJBK{2hEzBQ2?K>HHb7Lkc=Y2k457p0!Tyz5wu#XPCECp4;+aGf6KRn9qTWJH)Vn#wX5+LaT$(xd3B^jX5 z_|^F5_blG3uMdqGnpe0-^E`}(OzBz~5fG)1^||uV5G?U0{YEewLE#865MdheSQM3; zq`YbZjz%(XU!Lb{`{QF*DO-#HmVm~yS&v1Lv3za3wI?f*MLgSko{__9rE@vGeGfpH z(C$?-gJ357bI+vrtNHgL!BO({_}Oc;|ZW^MM-d)eShTubdWYNWUwbXzm)RJ;q7N@ z{U_S@BMIcJ-Z{BDz)OPD>?>9QyJhKah>!s7x3!;T-wy)NflxVnvhy2I5}an=dR^B= z6Br~(nURf-?wCv?S>t)_L+v`-zK9KYpY`v3zbAS>F-Gj` znWv}#+N3pE^6Z#i``*0>EJsK0kCbmcB|z;v6ZQHx(u~PbBds=mua6OU#z#mXwOfUE z2+#&c%9cAMfqd?slRHW6JcRbxceO3wCxM!iBQfcYgwTM7I^LF#m1$outTnvo2dyFB z9f&Ni!liM46JyVGAoQ(8)jGjfwWJ596W+Z9jo2v zjrm%_nn6mW50o_78xbZzB%_}JE6&n3(aK@h+IEfm6JhwuLm&h#*3pD2qg2dV=gCR2 zI|O9Q<0!O5jgo+q1L-GoZIKYL3N8ZhdKE2UW|KxbXGe%&?aYybt2@E10M>&I>z;-T zGVneSM@mG{?)BsgndIK_oF!ZZPy>2u>s47b2PcB1U{PX^l3|CM43&XBC5STGYe=WPs@1j6tORe=3EaV2GRWtbJ+{=p7as)R zEVm>)atNbMwwH(@i5jxAXG(Fev_wnQ=$H|xA%K@OS{v;?`dV@(k~ku@dPY6(g*Nw7 zTB3DJ|Ulbqhh;-`phKD~MDtOzWq-w2Xoc_eunNm{J3a~C}42D1;e zGVrn{#Mv%o_FiY)Q6@PMhg-}vU}Q2a&opJj`Sz_I!ys2643WgCxYfY&wI1O;7I>k`5MXrdRHl7 zl#YW>fhNy=^$JxAnd#zOrJB%Y8ZjFK`z-=7Qz1j0=SIuAWmqMdEUxH+OGy~6o z7RyI7Z2Gg8U|c1mbMpGf^~<57VSp}3%MrANj}oFM_ZlfY{cEH``t5~I+Fzs(?dtk- z@mV>5)E{3Ql|-61AR&XdMcR)NOjA6s0`xWxw<99+DGER*+M94x8LW1mop483j-}W3 zbC&(#DnLR{)@NP0LA=o9^)zUqAk&_qzYpM<^bAF4pKDht`%-u*MVIVM8$|D=eR!49 zodci~_3S*$Ii4Lpst`y#owWhzINp0#UR@`FmQg*6+_hMVyisRK;4&5#XzzLCS2L;x)VUePYJH$PwpP8AY@d0YKVo0+ zChUFwJ_oQSOJy=DyPoR`MWBw5<|#oULL(AN+8OrkDUC_)zjN!$R7B$M0_uPneVlCH z_n(VL;F0vZL5u4d_n&OvTFSHkcQBXg5qOfmQ}73IJklVFLs=dGN1=UW1F6vOd3VxUy|KI zM3ug{Egn}h@Wr)w*7^+qcSfOa3b-}CDd6V#8oT%`8$lDDgR{o79y&rTWJ=W;`!erUoIg zBCrZWi@wIw)zv;C1BSf59>*dEw z1BnFEC}uqWlr%AA04C9ZB6^{9G!B`E@_-ltUjya)R7}+X@37Gs@3d-wcP;odq!xki zAdJY7ZuI+1lv@eTm$mkDhUiXsL;tL>xp&KAPTmg>~t?=v>qE-B@4CTAk@sa|(Z^m}QlV`2)d_}|NbpLvK zgz=75uT(n!CO{j<$7Zd4BHA9^Md0f27tQ&eSG$@Ktk~B{AA(r2b-xU1!b9JSd&bUm z3Q=#=Gde$1{YV<8(bj=w$ zyMf5|d8I|mwGri_&k-KcRM6{F%<_!FO9#~}oB|@R8b|cd*Ryi{UK`e%-)HK9nSKLm zIFZ)1$Eh#*AY?Y|j~YMG{En4Dd9+{eIK%qXAV&%FCb*5N?X4cc#5iHK~6 z5kPB)Mwp3Iy1n8QQ5fpEnc-ifyTb^gjQ;G(!JBr#$45^?zNY-cM%crJ#u+W(rEuDu%sjUmRzw>0D`t?Td?F(P%tiv_xy8`Q%9hZ) zS{i^B1$NX^d_3n*q8kCYSE7*sdCnO+IiI7@a(;t#I*9BwTlqvkUj%8EYB9@;8qSb* zuhHUT?+&ZpvBqXApGb)SoB+?s{5Q@J;`v&I|4HEcu}(P}dX6UNN74o|=cNYV%t}R# zx?Nh0Am@LY;)(j_{%9Q}$9Yc>sKL})|9=+VD_A6YA-$JQb}1ii5@j}%BD4^tMm*o8 z{9<$h(Of<9^4(tF^Tx<;tI>-TR#fi6tNdE4-U;LjBgZ|B(G!%#zq zvYIxLexk|%qR-ze{iJ}N(k%wjYBw7m9=&uWt?bAm*U8$4OX=+TlteTJHO4KVd2a<~ z73P^AQINIXDC&;Ziz>g?I{w$eGXg;h#|YCsS~KtnKeCqAXF;zsN*>k#z0D(=>ItT| zIG+<8rwMlknv!~Bt$nXTwh_F16X>Z(OZoebK%N*7Pewi7y59x9-_?rO)@k?I5#Z4_ z!IjxIs|i?Bykt7c3_8DIr4gXs{}N6oc6BgouD7EhcvNmGlE@^9^a<-RknM8+3ETKJJy?g3szEZ-W> z>G8N=5ZaMD)n?#E4O##()S>(v$0GO6?i99OLENv%f6m zbN+hI8-@`e+bFU;MBAiBS5uq}+dV$C`7*Mg``@K}&MUvFW2o~s@SVWJ_bd&BPEYXf ygd_f^&@5=-d)55ewNAlDL;x9fXD|w@pN4-f&@TRJSL!1G0000Dl!S!2Cu-V z2N5;;;$!i1wg6w8i&tyk0Px8;=$isQ8s8M~;rJTBhvP9dz;PVZTBGAQw(xt*y3qq_ zfUb;PM!@;q9Y=eBDR;&5&yjNEv{7YBK6l3>Y5=bA{@GIwS0W#W@af~8pnRf-7ywb; z2xQbi=*w|Wz+()6Xv_#uy1oCCluz_910ceUfPaUki>E1{=mNWdQ4fujVHJj!QE0sG zQtcy#X%)wR48S6`V-ci)vmO^2K_p8bm&I9Y=oz&&=c#RA)x#!4l0#@73CtBssZjWQOy{w8URuL9p;=tX%Tq!#qpH9BIj%T zcL6==e9aQxjoC%yMj#6#%P3HpqW-(r4q2;9+y3R7vwjp629)LFA#)klTFXa( z6+ri~S$fXeaDe)go1kK;yA>G8W!;aJNffVM?K zXhbK2vnO@Z2+qXF8N`g?zU^H8r#0qH9`!>vKC!o zfEJC+eL_?hjC!iZD~pQr5cM{Yz@uO^KUZ1j$hrK;g;JJB)E`Bp7;XOE+FJcR9z+Z7 z0#3|^ z=Z*-d^<7!DN5#MwPQ_3fK>vbijQc_q=8ILF;gg7u$%^w4dwqQ0!WXyT105= zSqi8f(^`GB$wkV|6oImDWN`dBA0$75NdOuppj^zEF@C-Ct z#Y@Fs&$m%(Ar+roBc%po`x9DlbB+_p;tms!MQ+3Xl`h;%-(Yc z){ZLwIF7&nC{hbi884Each)vdE?`CuIcG$f5~v|~isfzpJfm!_Ro@D>!g!STWd!j; z+6r(!BYZRI&FiQ28A**+y-?Y{x{$MtmXG=OXr$;s`0Q>|?*nKPmPQi6^Rf}3iz<^K@F)ilGY@Kv>hT#v`4m7A;B7#GcgQd~gPEG+ b3!?u3+$H50?G|~m00000NkvXXu0mjf9Le=- literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_13.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_13.png new file mode 100644 index 0000000000000000000000000000000000000000..38171c273ca522acbac21d3154c54aca99cd5db0 GIT binary patch literal 1541 zcmV+g2KxDlP)|T}FV6v(CIEwG9Yq(9LZN z5mox)v3Ttk;ETODYW+HZC!^3e1Uwqw5b$t(3Gi@i%K=I$RBNSD$|dVPE!RQyyCnx` z#<+?Ee7z?iqTfVTgKs=;p32X+PJ3}pD3o^ zZAoC11U;*f`TKEC0;=DwRlo=d(0SYQPc(i5qTlUhAW8y$4GkAhHhzPr-{~p<&EmBr zPBIuzTr^ThYt9<~ZdJmlZY5~?eItN2nWpd=<6F;4BtX_c$&!hP4y`$6jgK6XsWK2T zWMoV~R`UcsDZJzm-Qtx*+1-F^-&6Vkky5Q6(}0kme@?>8_C^VD_uS(T2`HEYNXpNE z6tg1t`Ex6AcjKZs4-y3k;KilY%CTzy(S$F<&94YCk(T(MEFQFn_8d$Aq)yL(<@&FB zhv4A~j~GGZ9ZTqKVAckAmS3}b;<9UAY6afvckeA9sMBLgszq4Q{ToH*{7C7FlBU1D zid=sPAPK{--NnUm?2i8)Jo$F(^svgO{@y3HS9yH4;$pUCG*-~u4R^v@yBqR(W*B0&myX10 zE7L|2)~uFtbl%n84<SCwyi2x6f-66|pHAhOlm9LXCPkvTkKy3tRn?V{y+R674pV4G=77^vogp8Rk zWLBwYdVq|wY&51@0Wsj|cFK-!K~EcC=qt$980#cdB|o>BjaNQFkK1%R2c)@0*c+mOekl_(bu%L~9}U)j}yn zG<@ykNNZ9+GF^b36gkUeRm){T(Nzn9SRTk2r*_9uhji9!$ z_DM8f&qrIqcP1BF^RGJj83d`d{=N=IPQ2H))i!G-OY?fdMSD{&H( zfKK4dCZevezkfFZSj{bo1k(Pa#$0{+xr{F_n{VHvhTs{nH}-BuM!=0Bg|3yIPpz65 zLGR(uzYE}>t2cmc9h5?XP zDHpnb=1yerl0XgK9BJp=Lit!i!5_@$J6 z{~y3Jz7|v4^+;&QOt>_{qaMmD!~1f4#@J#NFtz(2_{m0vMCNJNq@S-qG=?L|pyUZx z8~^kGT-p8iRX{dlUDxJpa(afpI%m+<^GJR5=SxyHS7!7iNrpz5+}1{n-ykK7cTEr_ zJ@D&0J`e5YED0K<4M&AUlxoS35@NOI>t)Y&=OcO*JAqP+?FEl0u2)2a`5utXde8`q zA{utGjf&iFP(1)wo~B4?;}PTWIS>+f>qU%i%@>8WUQe!UbJ8;!i6z6&?C;Z2YqkGdc*LD%jYoibtJNp| r(@~1@8$r=n>Mb(srbaLl!k&nK#X!8+KN{(N00000NkvXXu0mjf#LVgb literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_14.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_14.png new file mode 100644 index 0000000000000000000000000000000000000000..3eb9a1f6327dffcc27476326c75d9b48c1f75cf8 GIT binary patch literal 1578 zcmV+_2G#kAP)74%zv8YW9hk9RX$=SXVtYs|Lb-cW?65(P5P$ zFp5ZPb|vg9E5C}2^1BPKPf;Eu;9%Q$5L8GG}W0bmN%uSYw za6|B-fd;9T@YY*0%tWMUy;YU{TPLvMAuGVTg5hUgG{~HjnU9F3vJ6I_p6)B=B?%UT zk-N7R4JZa%b;To|5kL#oJcrF@Dq9~&>!Wmz zDqr(+}{b*KG&{7T0!}35usWTkJeRPc!>ZRaHU0V z4|JW>GX7*kpvd$}uCD%3KM$#srFpmH!IFmqyx$_UG=O8#qG)9xADO6m6`l<%fY;v$ zvhJ@GQYC9OK&)};%vA){0gtCH!}roJorCWm)M~X37azAg-Xba@1R4!KJtAmPlfDA@ zk;8%%aiiDEZQK4*02Q{CyCVf2B}!YbK}!ptWC&EA+Evk$anv9@J$Q5;$MO0*fmNkv zj3G)KWwP54W?iee0{MAS+3_{ntG9=R@GYRr7&64sbCFoBc+4WJe9LH~w9wBig-WmZ zzFW>XFLe#4lG5v{(4m#<~ktEsW2U?}IW@^{8rk$nJ~dlnI_9IP=n2mQN|K z(}*;ZQY>fE#=GPT0Drdt%hNKOWg>)!OrFH~o-t&=l`W+q$y1|y)Aci6qcFb@FuJ+N zthcUe`Bu)(L?2EELi13{FU2e+cj!rs03$;71gi;26B^FXFfE-EQ9cdx(z%o_>u>&g zma;2O`WQW2Vmb?nU`@ys`aI=R#YV!Z literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_15.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_15.png new file mode 100644 index 0000000000000000000000000000000000000000..6244074889e65942a79e6f658f1ad82e989cb88a GIT binary patch literal 1897 zcmV-v2bTDWP)ewA(h)M%0 z3)Z2kVA_eDJ6@^#tDx9^p&gnTtz-oD%-ggMf0N*|_SAa+$&B~1%-lf)MIYF)uO`8c z9e)LhGju;+{lhLIDEh#s$17|9-FEzlZph|m@wSVONT3d!)#^wejM!U+-8Fv3FK;i) zh9e|-XKeKjWUy_JO++k(47-TX?Oqjpw8N2|Z0$$0=1&Pwu(CWSb?UK?G$CbV^tSySSsl-+^rN_`jL(WOjbm^dvJ-6u#P)_4NxF zrBa_FS1xUrgV4a4bLvEt{!vY3Bp40GY}#K9w0=lDD5={zeuAWinYnQCsxc`;}!K+onR+D}s-NtzutI|8{-|y^r*RkVuWPprG_s0qZkT z7Dji{CwD&6KGiait^cn+r<++;KO!r3|5f`}!pV1+NO z{aK5Y0BS&1Axr-e89Wi9vT)a(@8=TPok8!P{w#cFuvKI!-nZ)u#E4<HQ_*T)+b1d^)s#D$_OlZ}#def2zJ>s;>0ea!9ffv!f8L3J#3Nd8^m&zr zP}`#C%$I)sDgrRrU2XsF$W9WT2(}HgQ`w!UeOA|5Nn&F#+w!a6JAy5+UmTXAds~J` zEUF5*v70N*v52XXRXSBUF!6tUueS(ITp-oDS3!@9jsKLJ^RUCBQ6DeeCzMg{zD) zLjvZrMJ5z8-~LGguz*LqNIf~Ae$nZm5_})*(F|a1K2ijZzzV@C=dG4NgixN_c53iZ zKjat70NF9|v8R9vY|xP){A2>G?)*w-P{!-+ExwWfez#`}H+$5o_+`hAb~bBQ)dtb& z;-3_OUiGu1R>ukr;M=1ykv-*oK&D?Z5oWa*ZTiEP==ibk+wC>blW z`{UEUkOA14+AnUjuruWX^=0?6;9LKh-)h_QEc`6|iHOquh%KfkD!xR%DZ!79m8=c& zq4)Vp0N!&#XTqX%tvy!;jC>{?}@NXot@zeN_l%zS;IDxPB~uQc(gL zwMFyz3Ib%QJv&B4$V6Xelcj4$$n2Cdk^$^J-|n^qP=ck@bemFDyKF~gN52fHBr#iv z2r7xy;J5bB44|B?`!nT5N@PDG&WZyRIvPg4WTz2(Wc73Kejmrfz6-E*5v5j?`q-7h z5=Zq%X%`7lYbPpW=UW4WiISFs{gY@ z%E)tT0o|5DC=Y55 zDiB$tGIAA3wh~~)#Ly1Tc6xS={I!0wqa^a=AAUto`aWvbn-eYdLwcNsTqRosUw*u;w{MUcQm}%#BPm?f1S4av jBvaPT`!kA&bRGWzWq*skP+kMC00000NkvXXu0mjfeO{Yi literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_16.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_16.png new file mode 100644 index 0000000000000000000000000000000000000000..f1306c2eb4a149aad4d800fe64d0ef950c8ec0d5 GIT binary patch literal 1918 zcmV-^2Z8vBP)Wg zUzxEx8*~-S27jG!y4}BXZGL{mpKGo4SpQ}KrYs!@%!-)C^x`IV=IGd{;uR5}%^Tg@ zGec*u*m#ETOkp&s!Ymt$ve9Pl>g(bi={~X}S|6@6OXqAXK2Pmy&)n`KqI(k75OIjUI|5i-KyJB-v*yt~#{cC8g>0}Q@ynTmjVzYM!o9C-Ns7P!&Hiz(jL~EIvt9ojEIe%$6$} zzthOi*3gam2$_!Wok-}^8jmX?U)`Xp;X0jv()m|q1E%-;q{f=k>^&M#=~Kpd`OKNv zWKKo?M8j7_{i`r?3P5zDALY@(OukFp$=ZJs@u$%}J$~dAfas8d$*af1Zl=NK-Oaor z-B&iUjNtWE1YqKbDRVsAG<>f*>uTqB*1wZw*qDzZfJfCOvv*NOVe(mnnDrf3I=|BZW+Z5h`BVZJ zxn!bRRJRu$DBA{X&|e4B3m-N?3Y1TB8qY~ z`dOWi<}rDu>ni7aJC*rx9T^dB+XF<4Vw+=#G6Q!0ooHl@;#HB)`VrPRGNNKnVz?~< z49NQGI9BO8C4zsx>wNXJk-g8z=W%-iAa)u%rel`~Hpai}I$w2ObqcADm}~t)0!#vl z;Gsk$%Lvtc>S=+=qkW3L+Y_KVmic>puL4O>rDgv!lVOpl_72f}oec2fdiP`CE-+22 z^4MUV%-?Mo*}UpHBE7dIK&O^6Iee~e9+Opd;M`2V(lb;9$kzJ5Uf_-d$h!S(%v$kp z(7X%+9g&rmOb^OuM>@64CcX*GsDKhr_&k?`_vw_Es^HH~r^*SRPs$(U)$GMp8 zQREwb#qR?-Cq^d@^<+>rl3w=L5ukE5laD^4RL?r^alWka#KshV zRx^N-#eN+Dx*vF0w0T`s$M1EaT-C)#{YaOvkxbMV{J9cY2t zkI23Spd5R~y7+FNVLwNwoyTL~pNFgI?$wBDo|0Z|%uW_Sy}NerWRnQ~0~oIB*L(-? zO!v_qHF+5M_>~Z^QzXxtOtz+pxw9kU*nbq+HS#2Ls7Jl18%CR1(-b|MfYQiKAtIU0 z@zG6ScY~sIj$`qCmH||~s*TK+tAM8r|J?9a0#u7v&co5Q8mH>naejtM&vdr&dToCH zY>NP=tnDr^bBeb|%>Z~mMFM4ASXy4yKr`FuDL`>#8I`Zt87uk0O z{QTdz`BzWQny=~_>8W%uoH#$ydn%9iy@~{D1^-iMHw)}y#{rS8-C8~6{7PR}?rP`b zoL|=Y`addmYq|eGGMBme*a literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_17.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_17.png new file mode 100644 index 0000000000000000000000000000000000000000..ed8d96bab11cdcdde1efdc162669fa9ac5911ee8 GIT binary patch literal 1882 zcmV-g2c`IlP)>mitID=)!YQzt=};hXoLG?^ zw)bvhjD3tT_I)2?jInLon3&Hd<~w|j?=ALyAKSKlyPgdkFS=SkKjBwrEZcAO9JcX~ z0Eoy~hX}L%StO_g-7efG0*`)LsB5SaIkSsnY=7JK7U61&aP{CbKNWO{E&DQ~e?&^6 z1wEStciQ=tKw(O*&P^f0zVCktfI;Yzp-KdtSQl3fzUmk2gU_blRh!ZMwr%6h9A{)u z7LBpid*>}u6?YH5I`5ABE4E+Cz|(joXGO({$NJe`9p`GnxBhqYwfEdxqw1O=-geMv zf$R=uzk7YW#m9+OcgEF%Z|8JY(WdO^%H|nEPyhs5)M(I1K~N3Y4r2DN7W~f6uabZ% z=TYqYUMIlpXalOGhzb$Lh^yw6xpf7)L9Zx4SK`qIu1SjkWBknXRt+LDtWtz4kzhse z8Nu!SS$N?tt^!Gb0qhb1(Ou-T&{ZUso<5~i*7rGPTLCOsO27dXBCzMo@!t;q^sl2x zw*99A&+uC1gqIR5G9svHVO3S#!I6TG&4=0c?iJsv@qA^)TNO(6?Tx9Xg(wKoxGT^J zy0YW(-Re1bd;LL_}ci7*-UDM}v>;)wB{7a?v;ye=nr~2%Nk}gh)2eP=wAr zGJ8kT$`M>z0W7@T8|`L>ND)~7vkSk-o_)`hDjJ8)gN|_*0!(;8&uRk(Cbi5)Ca0{> zM1Q-d2(O6sQVR1UOdEG2z!>Y)V8RPXb}I13QAohrF+}sq>IXK*AHLm@027%S*k=kn zsZ|Tb?0t3TM>U7y1KMHNOMD0Df=$|crT__*Romzb^R2t{I~BjR&5o1odTRoVQQNhu zxUhYA-Cy!Qu2#f?( zBFuhhuad(R5@f;3`a}qcbLS!u;T_SU${5>5U`yp4$uhs9zES${j(VB@p4~?gV2nBm zCe-|1Jym!

NgTqtDDYR>z?IOMePpg^C1wCyCjnvR}NKp_9*#AgT!-qX24E?zLt8 zj-(HdG?g8n%~SQkv+iQ7`zY1Xe-3;6`--yGQ>$^@&ae?1U59L9*Oh z0X(R?DGR=}=M|QfaiX!50x>FVncb}afAbw6LKb}6&fERfanR=cT_FSW6YtgFZ=3Uf z3VkY+4>B3lqZclAmKLIqH7N6$pPsVN_xq>M9gC3#B&zsl|EQg+5cWN*?9~8zZO~5U zS7hfAH9&TBvXYAJY~QK^cu@K)wM6zjssqp$c2apn4WLx|o@}BVvw%ba@`zM9#v$>n zEpNQ&B;bt^`S)e_?kS)Oc4SiJQdxNHm)T}@2}74KS$cTHcYq3%Jg$N*EbH$Dz`j>f znrF{zr_=`j9RU#R2-WR-6i5Q^qmN=IQZM`bFaeG%!0N?gKMb}Y@^*--1WG$rjCsh^ zqJzlBEsH<~MLJn~Rui!2_I)QPM+kL9X|i!2p8{rH#-A~G0a#Ul&c`FqwsOSlAhPjN zB=Zb(chah{G5GAb#lXI@RmQy<-s&-AjL-kE!b(I15&PtteUQQS5s){t6URD)enfQSUDAIjWTC}mXFyfcRwx=uxs*-;W31T5%Q zU88YT5@dFx_eT}LJLOEg7%LQXDqyepvJR?OZw$PitpJw5RnmCxal9^~LUz9U10`a# UP{|Ze;s5{u07*qoM6N<$f?@!a9smFU literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_18.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_18.png new file mode 100644 index 0000000000000000000000000000000000000000..e1df3ea495e94ea5d0336d3aba41f02af8dcca5c GIT binary patch literal 1907 zcmV-(2aNcMP)v^AdP zHO4r`7~?pOfq1=Mv|aVRUauc=$8r28Yu_tv5tLp#fqLzHvOTCXomrzY=NMzWePed$ z9)2UfE!qIestw)+rsEk-(1D#v_1VEkEml!dZ3v@y_HfXXufmy;KjRD?hv}ZvJL;@N zWF*53SWS=7Txa9V$dC53^ zkh68p#@WQrf6k2fN{M;12%QCPRHZqV5vmGbfioh$dd^pufj4^QPS|FYBlzz~9KVIL zBK~eLJ>T|&rKlO82m4f~%0lPnaVG8<@iV+3+n>ir5i~WR0!HXC!oO{7!x<63OD~)+ zv&W2+d|0%e36|===?u2^w~WssoXwLNw@RWBAM~(YU|9hBcdxmE)eNwLYE-k#%rb4& zS;m0(0C+_);aMYLUA!ak)^fG+BfZp_vC^uDr<&)VU5?@oX44#ctDhq}z}dc8eAD<@ zaCFL$$ye7XJ3yp(Hbqt|E1q7Fujr!mx9U@<4M~v!D28h1fbBO~eU>(B4 z+sU5KuJyZ|6?KlD(Y{vnWMj6L01r&BOqon+lkp#1L(SpaSB<~hVOKH@BY7Psy(9w| z*kRglMRdHPHV4~47vD1e?u?UVhYXix0Jfk4Dvr^c$zxxX6|S!Nvs}YF;EFRU2eaR& zJHQzHuZH_RRM^_>6UqB=%J3}X+}R1v1fInu4qyxW^dD`Mk;W|QtMi!r6~@PCt3I=} zcQ}cybD0C!qN}Nm8HbJcZ9Y4o1D+Lu-H6A1p)OH|vwmE=f=eA>4DJNgL&uG&jj}q5 zYncpV)w9t*6Y*X@HJ6uBgqf9B*8ijL*j4D7h>XelDu~9YJ{I*WWnjkm(L74$NEYSQ zxG}!y0Au74T_JyL&IruOSo)vg1iJ}lWiLv1rQ478Z#uvj{O<_(-%OTaHe;~$IvJsB z^loNhhF!TqpblSm07EAmL^#V4A|sw{e3hwGNy*y$^KufXpi*!|l)S8=I>tkh(#*)J zeMj2Qh+SvyNT=Im07FD*BBG;GV1*c}lwXnAZTv2QRBdG)@8$qw)D6zs6&S~0-*HUj z2s?~FYwW7d+4x&JfFWYGS%i8pXQ?=VAFtM{8ZX=DtP`j+sXFRyH~@pyaAqKESM?s- zkWgjDH(47S5wni*I~-yK8DF_|20&z`fsr;Qv+Gc+Wg*(nY^}%rq8?0!&i5n-FmxQj zxBEV3z!_el=26C9A&walW%@BZHUl8CL$>b-RZ`TPnKN|j^(=9$?gjV6@CXi&p~{4@ zk9{BG|GI1+lgkcMt&fheVtlrjtjs9b*hf2nK}CRy^6uOnN3eb`JDc{E6XAN<{-X@> zcn44h!AOrvLIqVv@N!;uCh})9gBs8F|9A&bX&d|T`^tKi^1>V;Dg$aytK1;EUHobi zh=|g$^>-X3BXyZPuF3dFHYe_j^<_@**bIP7Uqz-*!PqwocIcIQj3uN}^HKMz{?&~0 zNC!aU+reb)e@6*m##e1BJFyIqMQY{tg8hn!dbvkBfFX(?l-mIn`H@`a2-$7H&&Sqd zWw3H9`c>D!F=95n1FF_Ww*mjGIs#?{l#NKE*D0FkS8xD^U6GFH8lNE>%Q6D49bFf3 zu82cCo&$8Tk{Po144Koh+d?#sm6z(Z(XXj)Iamfx{l}qqKz4mneT?B(Yi%^I`W@X; zD(?bNFLlMmv5#~BtZ}MerCF0vh*&zVvkFE8RevReu-j0SF&Sc!nq5-Psr``>8 z=1~E_WZri%Y!#KrjOu8$4IQb=C05QAGujRki+eJ>JKp(pWP6QLZk6>%b61HcM(_%v zTg4cEOF(uoD=%4|>Rd>?loNDP^3}-7qc(gxt zWvrH`U0_#QkB{FNs~1-oaRre9l^n{mt5)>%WA1!D(G}Bl|FDhh@W^i*Om#gKjTPfp zGXT>odS|h^rwHnu$QX_Uq9QvO=-ptXDvOHB)6c2aLUhmajM9KQyjQ)O;ZAAM--VUo zz3hw=Fep~v)qTe~vX?;rZUH+Ky$igt(ddIg)ezONMQE`M|H7^ t;=8Yw(My>Xqs=%$RX!^(yE6c;^9M>+T{RO3Ci(yX002ovPDHLkV1g1DuGjzo literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_19.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_19.png new file mode 100644 index 0000000000000000000000000000000000000000..d231a656181d21d77dfc168ace0e42aaffd02137 GIT binary patch literal 1974 zcmV;n2TAyeP) zcK2Vx*@Bo{$ALSO;10T1elUHs?`5*Rn%T>D0(j+UaVq#8olLwk304OGh`(&F5m714 zY%6^x`x8yBjIrQnV`{-yGQrAPztX1+m7ub6Qo&~YA1y4RtH`m6O~aXG;cmK*e2SiX zRG7&7Sx$ffJwP|hj!@E*lHd$fgJkIXtC~tL_v$!eikNAU{=V;0&YpSa(8-Q}2xjjS zg3lT}gzb$z?=V#a-0v3#p<;m1;>tuYd)>vcIX@-%Q8JpZQ7l&YOBr`GN`P`Injmwg zQX1aQPWpFu@GJh<8d28&HkqoOsAQY$iy5zil>}U{vX?OeqQeB$&AR*KcjsH>x8I)^ z4tAkR0!~;-1U8O#D!l=ofIEWUO~R_p6?VK|?;haj!m}i>1w=us^as^N&jf!Zx=CoV zxCXS@DI*a~@0E+z(V=Kn=PPA_(W)Bn1b_AEKf*kfGMF(T)AjbZZ5uzU7mpKUPO-W1 zMA&b3Qf6s>b?{gDQJqIUtLXpocmHe6E3ev&s#Dp#DoE(_-6!AswZb0^cGjcdzDK3g z#@>Gyz$n(E^W0C=&2F^ie=8be3w+wiKdTpsug2O=lef=RwSPsepT&yg^;n(& z29*TpfFE0(2#PJdjSg1OeYQT;OJTo-C03PO=7X1gUjxsADhW8|okh6{lr2X4M|y#k zbYJxs*O>Ja*}nbKJv#vmY$F(DGuhchz^rE*+X>bc!Ds8p)>AEQOy{x$@D8YFW8}5D zOWSI5x{Pq=$&c36(WN?9CcqfAw^<5V@-SIe`yzIkZSYnFzspvKf`2sw7&5A>=qY`* z5m^tCF~Us4r`9lIM>TU@TemX+qDuXlKH8W`1eIW`g3o-P4%|Um`&{-SXclbqJISB| zs%VkTV;jPJsnYz)liw)==&ypbe>Vd#RO(r#Uo8!0Z>B6LyDO8x+sl}y(ieOj129wq z9Lcd08Z}BtpY|P3nM#7p_R*e#CG=62G@GZr2|N=K#e3N1RckXQf+`K2fMAkzPClEb z3Z-l7v3VYu00ti@47NSTWT|W@O9XGz%b-7KBV&+=_Rp@)`!4=Hz*C^IoHcQNlcOLi zJ6)_i@f}&V_6Uz<0Bpn*)kmemGeiX)COPB8M~y1GEmZJG2EgFshTw^>pvnqedz~)7 z>tocIR+-?D31DEsXXB{jfr+FNAxaP&!@wR1z6vU{i!xF286KSg9=H)6SQ40?qT`5d zsy>;`YVb40h~)e_v*3^M;2wY>qHljf*hZl&21)6o4(h78W`d78-Q-|Q@l^@HU;*(B zpQ22rYoFLKs+)#-p3UX$%rbySwE_Lg1i&j_cD1_8zcKpn2@oo|s`eh)14O4{j9RU} zEBJoy&L`>_SQCuDBfF1GfHCrVnw^+V@L8f^V;MciG2bUtgWvVn!R!3Uyn_I+3Q#&qvpXR=z`HSYeuWVM?X3x@1I-Aepey9 z0M#p(m-U#X;K&y?M>anuP;|XSyGrN%>>CrH60~mc*?0CEZJ<9H)2Q*R@$KmN-(PzT zJQ94gHADMd-=fYwD-EizVT~lN=PMIH!FR(3`##gvcbDUFDN!P1tb%fttEjBa;14E21ePc&N&XiMz#1tW_ra)apa-7jYRSMLt7Jhx{W$(H znWzu)V_%&BjPfzKi~(lv;HKN@8>*$InvB)k!B;ndW9T}H!S$aiDZI@pvPRU)RduV0 zrFsR{_HgL`# zKiGZwaW$ga7`-WDa!N1zT(O48&dRx1PvgID+u#2yST#Iq!)G1r=tcEg$y9=c>iaz|5hhKl$4YKm;t;u&pNk-*{jI0 z=c|BwjK9m*z*(mhovUCUX~HV>+nFm1mPb`STT?bq2bBZ;2XF0HlYkc%w*UYD07*qo IM6N<$g8wtl{r~^~ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_2.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_2.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a864c76259bfec69678932d7d9321cf8279f41 GIT binary patch literal 1636 zcmV-q2AlbbP)g@s|R= z96tm2ay+sV?wac~Mw|pjog^ey%l9aWW8lf$UGts9h`o%K#})FW4d9cMf5P%MZ-2~q zJ%*K+l<&$Y@L-x4S21@LB4bDQ^}Jdu)g-!7zF`sgZOWH86^QPmh>(evSIgHe0e3?DI831A~v%%Te?d&esZ7KLx8-k?wutHWwNHdO7nYj$I;hqI55T!97`6AjY z(t)J$=utjHKtdK$ats^pks_^V#VB@0Cy-J8PBqn0N~yCtT0253NZv1nGe$knYb)ze zzng3xmhyYQaAE6*UBD=bRV3PbwosgjmlR+z(8ADFN|s*97GT~w46O*7m&o&1$<8WN zpM8KGy|h)}=RIpJMmbh`@WwEqT}Rka$U3VYpMD*@60D%SuzUX2MW^oUwbTI29EM*8 zh(@n5Q3lWxT33MW$y+Cn>y`F!LV`_{Hu57Vu466Ywj~Ox6n%km$JzpDvhV0hq8bXh`Glm&J zMi{6fW(+54pEBvlG6IkGRf=Bmu7LU;Kw>mAJx4un4X-;VpKA|~P82J#f~IKzvo_tj zu9vU%nC!ax{luzJ-;)MMu45WNW})cCOzXOGeJf?4=1kA}D3Xkzqrn)mm+m~Cz402| zHNea;#dy5eVaui$#{0EFtWJrooj+s<+jatx=a(|4t%{7mGb)racEs=qAO)698PS_Z zd5>+#j6!5wks(Gc+ntV%wbph6U~>?fhkje0*xHGUP6B9-x3<+zj(Cjt>_KnZqYXfN zJi12nncq?CHj@GvT&3|yvp_UZ)}u9yG5tMbpN6`g|gcx%jP8AMLm6ak_|J&X5_Eq8>~XYjl} zN)gujtzaVZ%U8h}<+G6jZRGBXF9m;hXr(l!A!Qj%Yk|n7jQW>pS^xcZXbc!N4wr0#M1zJJ^v&wnfeyR>to(Zx|(*@;9lMZ zwB&X@|77GFAZ215{br-L8CR=%8|Zod`P?FIJ>MB46=Vq>8OBVsrW)!LU=bO;v1kJ$ z=*?`jSog9{(&ELfIBCH?fW(N<-mBoA`8ymzkqoVd7@FG))5)a)$blZy9=tTi&qk2Z>!jhMIQA@q8Gwq9VOrI%uR8*CEHS}%P7 zPx<=18ExLG9lZX6rW*-BkJEJYzFNG#CG?)O7dZT=4-D2zvWUt4sK5sbWMgsAsyJ-1|opk>0&L-c!62NeMr2E6-T zZl4_ykn$r#Kwhf%faY2IMRc;tpY0rUAAn&V2?XWn9X#I}i;Pg;XCuXlEKe)0>F)s| z0iw+_SZNH}>pi}8B=W{Zm=Pg+uGBYy-e#;^#0momCz~EJd>@DXC*hiJd5xZ)CIPwMp$&Cj`p z_V`xiBhN?jLXNa50wDdJ*Q1pG|6M$5os#($Z~jCuk*ziQ&BoIJN{P?E==ryURqT%P idochDsL1)@Gw=^8Tzpq-BiuUx00006ui^S0SMv@ZIY+1iQh{FHgS z_i(lU3E&YKn<2s&Um-z-0F|KIgS#W}7Jg6a8LC9i?D{pP2;iMOr3n6gc6d(@KJrt+ z46#-GiJVk!;8;{;;flk|9<%$T;3GdHjI;G~cJ8hB&J_R+&JZ~;lNO@qcAcjNU-b*k z@y~|eRh!Z0>$>YB{%A|@X1%Eaj zq5UA+=!|C0%;GC^AaZEDXNV5p+f@rg$)B+SKPbxM*&-1cb`zmm zWuL%~;74iq-*mnpd41z9b^kCiZFxU zy7|5$uLRwy>~G^o5y%`vH+DA>W?^sQs;vww1>f+E`RC7OCjD0T{>7xoe)jLsW>(vo z83i~&rVKMdR|13b{?4?(e4yV0FgDtNGgfEa02-&>iflacbq7{+{8QkGaCP&EwI-EY z9uXlb{7ztZEpSKhz2d4J0g4Uk?tWb44lJU;RpkgR?*D!oC)PS0d<1j>l{GUZzAo_l z09A&ay5%b2GW$D7aF^^eU)hC3Yx{BOUc3UZfU@_|V%bI*DhHSacvow9NAMLWK2+?$ z6u=x)Zdd-=P4i{71^f zZo_q5vJ#vMel@K`Hqi5IZSO-$fNDNoMYges3^phzxRwNCJR`$ukfQyq+MPXrdrnjV z&~5r{WOaxiH#WzJVV_lQWVMDss04p?4Tf(-=)Lz7h1_YVIS|c>>XsA1_v6*H!g4=b zd&b`{e;{uG+n6u*?D$=Zu;MGTH+$PxG1Ub;0seLjumVj{1Xk~yEc_ySjLd9KL{hfK zw%-Z76G$3a;fD^<7C}A`h$N?S{#cVCQY^m)+AkY#@k#;=uwXMqK=W-t*g;p*09t=V zNm#1#zS*&3KZqO_uO@(nCqpG)dzJ8HuwxVwpxj;!z7L!aCM)v1x}mYw{>KoYHT@r| zA}RGGV(Xy8R0_$+uJ^H8@mt%TK+Kgy)p$>q-2f&V3WM2t>W+$5y z;o}rwKsnS*;_W!KXhekW+I zgg4g!6|meHwP~yJ>({lmvfwNGVE$${>{$6Xg5HYgQ2ovJx5IW2XpFLUrCVTrp2SC{ z0NeJl9O{Fkk7w;1dbZMrv2jYB5v`H=<>%Y+AE^Kc zND;DLUbU&_?x-tZt*QNtND>vY$d2FJKS2PL3RZ)U))@1Zaei#p3bOAN*!LNc9Xsx$ z31Dx%{k%K)cD?F&uSoW}S}UMb6wM!Vu1ol}@HZklC{+Bh+f{}C?!Z5{zA;}j5+EDM zkL>1uWE+^ZeD+;*K&w6|t)=3-wS`El_<-8jkE;RHmJcaHr2>zjkZ7h@v_#G7fXEk? z@*b-IN>J1Tjpjr}6atd-ih_70h+5ESzOn}M&(41=0V1%#qkPFKZ8V;>PYhn_t0Z8y zqV_GT1ALmvQqHSV0FrtunM%84$Jys<8^>&pxl#RL$Dw_pF^WC*&f2hl?E6;`fCV0n zV_%H;x&DCF3fp35@o3ksd=J3vpw<_Sdo%&E;?4uLVZNYZH{UCOsst6kyl)8BkEm;? zfOS5tJv;?4sb@ekk7O_UnbiTa!Kjj0EeaL*OJL9D(FAC%b`Vh^rxt!y1yCi~`1lW8D2s?ux6@e(| ziXxz1JloR=Rj})CCxFc_)g0+DJ9kI$vqCK*8}bMJRQ9|>0g#PB#2^2^00xzbJ6aZB zyjAk;uHZ+(WL*TCm)VWpuU;Z=!>{p$`c8yuwY$sd3JK6nJE;IGq)`=QrvlhwaQyv0 XJs`E4X;N8O00000NkvXXu0mjf8}P7( literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_21.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_21.png new file mode 100644 index 0000000000000000000000000000000000000000..0d407de64bfc2072706a182f61cf9c0aa101cd6a GIT binary patch literal 1894 zcmV-s2buVZP)lgDWXM^mm@PS!#j4`(H9{@y- z00QIS-GXoBC@>%!_E}Xb0QjJd+C@AAo~|7~^3aZuBQw9VpUR%AfcYm{C|hjb_n(b; z^lu%zd+@d2M+YC-?PUCnd@{oIb6x%<@wq70q|f~SYZq?fp=_KOck zX8c`5{De&)YVI@`>_Sn7MvbB#li%98CuY80hY5bR&raWv?N7_sHPAYzjn6Pb)E{`x zGJ3Oe*NjK&Wo+01NeBQD4+zMhZ7Q?1JUzSSQ9zJ&uL?fOaF1!Tbvmp`0l+$DDb6z* z9ZWPA(dp4W!7KyJ2%FWYxwiHh5a>DXi=fP5+aF{GtH?wEJEAwxd$=O_kzd|EZNRnv z^4&JpX#Fw9*!GDXpyrJc54{nfY$mKe{40Z>om-_0i9Ty%3IKZHDhNbSlj8xw13@Tu+DiKL6UX23=m}eY!IxLtn05dqAU=W0U+8yBnaK?+IIa; zaPAa*#C)hkvi>nixbM!3ppGEJ)#lJ^Sfr_mkZlicTVGy|~0Fon%(tD~90 z(jQ`k6=h+CT-kFVU&i?VEKUPJ-9Jbgs3dsHS_JhqIGBF$Ie+Lpej)f&S>5n zW6OePx9Wd2<55C*tPqvHs1$tpc~=0490>&PfV)SsveC@;fqo+}Wq`gt07NQ4$T9|H zzt!#1?5bM^3NqRY(zW{DyfGdG0Fev`Sq+Uk>+H6`__nga%o;+rl-T|Ldj2#3h`1Xf z8>umHqlo5ZL5uWf8%&SZyEh2y!?HgNI$NUVh;8I-+Kozz zwxgd}{l@}ej5Qz_BL;%j=}>N$_A@4{tQ|4NqX94m4+3;RDAV;^IVc+lbl~Xssvd&X zMdO|?^7(iGh)BSqI%sK82idNLbfP}Nu3yPcq@UGwuOxXkytOZV6SzW{0CxLayN-O< zW1e)Hvgngx2djt9;Z+P^>!i(SogpZIsJZg&$lOkY8I3c+pApLxuVa8Q;x}XHxy_J@ zuxyg)v6-)R^*$o8<2Fft+1R`Mc(K?_N7NjF0L_VNJWKs(4)UA*v~%tH5mPV?@__Al9>#(Jp-a$uXN}+9(9XeC-@ndsv>h=2Y@3) zvjQpw%(&KLgOBDRzdX?E`AA;D08#xz6z}~$L#mnIWd?7)=xcc_0Bk3ZvO|CObk77r z#00FK2Ldb1?PA+b{7a#$1$FLrJi50toxdLUZUx?4=7y2^$Gi`SZYLB7o(OIhqnO&zk?*XE@-m@(DXdf&)K~VfP0EpPk zXYSK8N5xWj7JTGu27;(OJpM({j8w8Y>jk2Kc-KSy+m1uJPMSt*-=lr~`%eHMYVN#o zq?=J~=7ZKp!L_zLmdY5Q(nGus09mk+el#B4v8(fSKs?ZS!D6nB+9nD<(t8~MX0lSR zfifz)`c-|4SO@_jdKX~lGQl6?g$%%mcerTW)?_U!`ezHS2ng(zl@0#3{jom_&~-Jd z>r8MXDz|#kEkm#4*+uH`jaR$$WbDnEA;59mU>g?B}*M|14k@t<^(gf|2R54A22VCQ$>LW&bR=G8T3J z=g>%OqcYzr4#AM{-0Ux+z_&U=u6Jpcdz07*qoM6N<$f_-9@Gynhq literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_22.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_22.png new file mode 100644 index 0000000000000000000000000000000000000000..f53ee0588351daa326d75d7f83454511592676a1 GIT binary patch literal 1923 zcmV-}2YmR6P)k3up(7@vD6^NSQZ=ScdHJ`~oBIQ=S_Y|@*Ys1fEg2`Gxg-V0BQ!XvsBLUs`G3PPE zuvuikG2^j8o5DoHXW8CCCV=IhX9mK%IDaia7{ykU)!(!Gso-|IeK&!f1#ljt^ll*R z0Ga7sGry{D%5Hr=cRkPrD+#DD69`kNWXxI4uLfau%_#;D`TG>@S|tHD;03}YI?kU& zH3&r(_ke3g_E%WoIF9wGPK=<9vJRGITE_tqtDrqohnKOdTYmH&SU~7;d}eII^?$qx zoT5Q52(U+B<7l|0!vZ?=8P4BrIICsA+jlfyuk+a5xCItWNOc+A9s4Tu+tp#|+zkTD z!JS6WlGW$)U{T{m(vCwS!_LALGXJbz#6yb#JUYj~|&wSS`4cQHLb{QCgYkW#?1SpL!DYjGCvvIN($=2SC{HEdP7 zkDP}#>9b+`vz}TOZP2o(Gk^zlF#E2@u;D^v9op>$rs*DSkM@UWVX>MQ6u;&kXLK7) zc!9uVJ%$jlL&M**&N|!qm6BM!QCRlBRR9PofgrzI&b8)y4WbutXF9*q0D3`Cne+4> zAOoR(sde~W!#Zf@d_5n_i(ZRS=(C)!%Ye0~Dd)c}10e7~Er!rznehrEbQ(TyFV%Id zX0E!{TlWASET?(3k|7&NT7Js;%+9vsHf81cmL-5emjOM7Wg((Mk;l@ab)fuI=Hs(d zMwre_-(c#w3Ik|l*dUYL0?UDwvVe0fyLT8R(wFHAF3SKK88*-|QB#KW=>^zM=68Au zy#}5^^}LWZj^j;l0a>shup&PL76`g5Sk8=W)N58UKeN8K7psKmbGmc@ti|7&vASLf z3X2hBOk_N|?bdv+ADPBwdjJL&@fM9{`T`5t+SR;?5urUGHo`IReO z^g9cNk1hd%Y!k??k&(Rq9NiXnuZ~R4`aR?PwLT~SwDYiY*T~XsHxN)q$N5?3MYj+y z_`aT>Py(V1kX3%7MQvYvYx=Ry;@SNb#P62eoO#Z$ad7$og2p{ZK|-=jxLYw?z%=yzVL`J zd7vHL-d$Ti_3zalU_xdG*1Hnz?_d9&z^FsMD!i+k^`?zIC+zUnnPwZkuISfe58Pn( zWycQA&i<&u!||ygsJx((&(BIKX4@A7WH-(hsBXZzVpZ0O0}u)^;OpNGOp@;%Q?I9xVL8o!CLE^0mLwdDd&69-enTBD|>iT&X3ls z%AM_e)Y<-@MpX^-m zQjamlImQ_0d5$s0IF4h?@5gccK1XSLeQ&O7Yt=<?*|fVVlYKvq zgEK${7}Z`4%NU`9w>y7#8Srdia04K6mTDyap2@}ysE6`2=XcAIMf5y6qw1LmMaC8I0JGsYO7NMQHCa8onmkK;(oLewZl)b+p0k&zX*ylGBYxwb8lVNAK3NtlhNuG=r~=; zcpTfkhbTCf-UL?JK@Fftu02FsqVB5sp1zfg{|4}!w!8|?0wJU34kOI*x&G=hu+rdF zbs(}n3g^rprPLhf=J1TJFV-NXY^btXz+I7fS2=&m_TcSR(aFyFH?ejHfM=+EUdd3; zG%t{%Tg0yNaCPQ;d&B1zYV*s^@AvbH06?RWs&PC6ZqSn#>Af=utZg0n3U=Lq=KO7c z4)zpSMc%l2Sj_pXQC#f}Dvh7DtqL2Qo{Vfy)uz*~yDR`u5jHYta3vT#hkMUapJzwK z{wtlYI+EGq&BegNb(fU@i|DXeub?6-0g=2)S-9HyOpld|rIWFl!W6eLfHf*=-X?4Y z?_vaeHs>p4;VS2QOjzwz<{bQ~=)SxMK-kT(1Kb%1D`i2+o(?Kyg~{mZ#zeR+0Hy)f zxy;cR2r9e)VnG!hzDl80RGeQag`SQG_FQfafT0FHygdM>V$V7AJHi{Y4$T_5RYs`LbGF}%aaJ43D!vi`WB4z3SO%;@2?RTLe(q}g zDjAP!J-Za0%G_J7fz$vvROOJPHC13kg!1h?MyFn*X~#0>Gek{n#9E#mj3vJw029%s zygAI_ouG&ulGW}=j}iplJP#~5nM@YM7GEm?h^QoZQH`HCK7UtZ+iOar1I@AxW$ws) zw8`4)1tj(pQO_~PgBW0fQEZl3b}r6W89~V=9E-}=Y7dbyUL>3Sj-QWVfQcycS$0m~ zL9uQ>0_#b#fXZ$Yp3RZ|XkC=mOm5`-^E{u&02Wzuh0n7r?=Zq#mu0t=%NU?i_oM7) zO(oik&mPYJ7BlOj4JozQqQeMt-CR@2 zFWU!>J^mJ;Alj&Xt}=mFGk0T`^LOF(0bsMsUh{A~J6LpnwQN+d;{1rAI{L?W;H%&Y zSp7#Z7GRBEB(u|jv$<-68QHJC55b^&EdyYKhA(+0W?hc5EOI_F!JKF7Jj!8xfcG8u z60r~V5UAH{G$T0}EU#n$biUVRSH>dedx6s_4eTc2=~l0ZOrLti{NKNcdlOjXM~=tu zk@F*6-F)%ndMsw2vtEJOtvdfWj&}!uMKwckjk;F7df{PbWx;DgJtt;1Oj({BZ~V1A zfQJe_vjf^`gL<``4B!O|D{GOgDClsn|5N}(VDAbl9eAcA3nJyZ=Urv(b5Bp!TUed{ zR1csaatgcmGiQ1!Cuta4@R>fPIwq`=zi z%^GDAuMqWPX~7%RBa6Eu9+w%qqYPs!`4AB%HrO0^jGa?*JoEc^oIayRuindgf~9M|MR;Io_+n zQ;qXSc}`ft%%YH)3e}1~dcS(}?{t3kG*wAM*1kH&QUdt?l|@wyj0jL2Tj5UGSN0%S z@mwK+?;Fkc-c^+=5@1!!o}-a!e1+7Q$5`>$#dLygOnJM^o*c)A=HO<(``b-hPBg*fX z4pd)dbkshIP^>>joxh5-D@ezRydIJ+RRCq6pU9qh5-6kCb3bO*KEhqjU#&QqI%L4P zUTKd(;9|VIG2nCmoArqntLC{Q=a1GJo`5rCR0P|m03K+(N)s%?@i|izL`6D(fdo6@ zeXvyl{De#myhAE=LAE*S9V300w2K z`t6aW3RO$kyJ|F9n_eQUaz0y6M((J6w4Tcq;KP843fK3?F|wKf<&_b$w_xed9jO!ZvF|WYhNV06T!rQLxQZgi!>+ zjYl=P()p@i=6v7x=M<$W?J70EPo{v@J_|i1^~w=QjBG9(ixp-{U7|5pkSIb{$NVG#(D~-bNY*_t z_xH?;Hbfg7p&I$tR@sr+Y5f&pAC&^o5vq@eN)OQ{Ga}f1MuO4WAycxb7Q){@uK)~@ z({Uq}V%Rv?E}E0gk52LJRuqmnXK$K#L=C`DiCSMPw5I1X z$oghuviB9|d%JxfHg?wbu|=T4p8(YR9{w|@MRM;8(a5&wwBW~M^RYE#Dr93m_87=E zm$jLRe0BP_~)Ps%Z2!MdLi828hse0@&gFY)i5WU#gs=T^qEcG))qRbMDIh~{Er_&@&r zV--L}eXo4_epw->=84*=zLk$S*&6Jg*<|k?rvNJI@mQvSjz&pk?Ufy)@M&R1nn5!7 z^*xFJ>cdKFHECCQxcAto#?IzuxqpU8ejI=AN&Xt0V1;3;z>arJLjCg$KJuditSZTO zAv?yt*!gfLR?Xw3omJ63;+YaeW1_9<2$mfsqp`8=j{RpJm%J^<@!!7-Sn;Ln3S`eKVq>@Et{m+VIgu_w-{Ck$s4naehz#=-U88R6k_Vzmr_Yas2zgj8O}X zK2EGQ1d&zODo06Ja~@5k{9^K|z0+x{$fVk_HLfZSG1&a?@-c9fiRf%E-S(c@ sFcLjT zda;iÎi$8n4ZkH=$7S@qe%l;L?-0ou0u93y|0ESG&}=|jvpkhNfOnGM9qHb(L(OOXC=;Dk=PW}4C?nW#tNyTYmfly9V5jp}?8W)sxp?zD z-PU|1n73z}0&gRkY;a`~oPlbzR_(Q#%3tyWN6cwBK`@cji0nl^J(X3CK*$B2(ke zY!t8J{ER(wk1UJdr%X2kaCsQx=a;~2-S2GJ(j8?4r7N2WvWNBV$gi%q%WgcM(oex% zWQm~OvmTW7bh7-bonIwkR_6{qXxFm`-~*pd^HOyc5fL)|L3Yy}=kG+7gj1IHz&a~s z#KUvmaDE7i3{)GAiUB?>B%tt-HN&qAKZWUH(!2W;<7L|opM?R8tCGw-brkdg{UC$ms4XA~@ z`n?MoBJg{h`>x36XU7iDVQ1kuj`1BeU1QkI2#!a_S2w40D#u~ubeyn?)yPL3O7{+8 zcsjl_&h8kX=2V(P?@&;e)gM$Ft}f0fKWAkFrT4EU&?5wnbsSu&U(wtQ5zdPI9SvU; z^{;|^3m7B+w|{=Wf(*H=$mf)-GQz5@D-pjM-Mi;M|9gO{k_n3pU39X9M^Y>5J7wS% zw~Z*stUd5~csAg>GyyWs-BnYodaXmN98kr+UFkm3%TT0N1k04-=iG<@9f#~jw#--u z;T>$nS+8)uw@+(7*({^x{6&BrHS$bUHtNl(W`uV}zCx$Dm2-~cIL>I~&W2YP=Q!^r zQ(wC^ewXvB*=ou8l^)=Vh@6~l6!9I-J)`04>WP}UtS%n=l2+aT=={gy&!4XOz~(=8 z@G}A&GVFFfj%725)r0NI0JkJS&5FwOvRU~u7Ro0E<&xm-d zH&JJh%^tVS0Nzz;f@}DEH|MjSOyih6*lg|Z=#0t=%AlOWZGQ<|X^?QfPE0rN1(+g66gaSOqtFmQy&YD#!KLVJDp*WekKho^k#d|0n@0r+RfXsPjyc+9`TWj!oS?4QxM79C_cmkl)RYUlW1jyGpv?Y2n zEOKS_-S!sXfzzZV(`oE>pmIfIvZykEdU>5_y^kb7bTveojPq6c#WkXFemAqy{Jit3 zsAMqk=uRqDOkB+dq?Tijym-SVg z&vs;pV%{P?`5G8SedN$?3ifPKYgpro2;Oy2>9yuO$3Bq&mgBA3>K(rK*_)5+M{8y5 zi0=HAIr#mfu7P~z!}ly_jWN1u-_sZM3lVYEou74CWas^S1Oc*+ALF+J_%q66y86mE z+hh@8%0$hg(#iI#%*C>oZ3456%^0=%Y+VDDF7M85>1Ewsw0n)EXJ@D3vq*Bw44@*O z@75MndY$hvN}>Z~oz?3l%Bd`bGHfTl=YLbi3l4mD*$kjyZ3+)4iV$`#N0xVIj?g7R zRDM{Wr<=)Qm9kqkfnLNb=Vz{V98nf2*p4i`8qadsxmiM5=b)~fmnMMK+>N2rrk6@l zCqGqpozWH9-kq22JF@UH)1?Vu)p#7QToJxR|G^iq!^;%A<^Z>k`s{gAE;fl;|@S3L*pn7Nus%!VU z`0On}=~v|e_p!ra(Ru7RGt^~$p5HHh4P@u2=af_O3aXjRtkWTvwLWIBv$H@{W?s?* ztT5WUnsp*oUF~){-?~B~ysms_ufgjnz1s=Ezf7Ig!J>XEGekP8&bRcg%CmjDN&v2h zPsH>86&yJ#Yt$-xtzt7RJo!j&cLw0*mUVx#K%^*x9h>MxHA+({XIcfW-15 zH=Q14cAA-;=V@kU$8p%ecs4M`@HviqoabrBas0TdVDeCQ^d8g8u9d8vsP<2JZ}%Dw z`AWyxP2{JD=I9V20Q# zzA__~2pmdP7Oof^$&2JZ$@$FA3}bKcotRIP7aguU8Un`btK~y7#8DKVK_!^Eu$L%6QG{y||X;Q_LoIhKR z*m{_3wnsC2=JAcny)djpY_Zv~8Mr4Y0R|!>L`pI;>?T5| zBfbhdobP|eu`Aag5nuqDyUJlJL{RZt&SwsrasCylU9o-WY!P5U%?4hfLWC7t?v8xy z$U9CS_jfyjT*|0LKmIOYMX*`yU_W-(=IrhT z?r^@hnVl9ofr7qZwrwMTH-e>iT+|)7Lf6&KXTZQ2&nlf&CO(eie*)~Pr_~1RtZSJb zuWywEccuNvR+dS#Zwh{1xfX+82~!Q7!4;8TIe6F6@DArIP;BVPSuO!8^P;)gd{urG zIkV;G?#PcE$$F>C1||KU=eg$;z!t>jsl@Q}vNYB~HNr%oeaR5NxW`t0yE5J zikZlcHqHO6kl?PPoN?D0&f7Uy7?R``RV2GkV8q4~JT^V6!4VApv zXkW$SGXSEB@TeRNWZ8nfb9LjF$@Ak;d5iS0bx<8|Bfvn_y^o(WuvE+5+mZffPZ6v! z&Poc-W%GZ?e=7mZ_K?8r&+i0Y4$e_XpwxWS)sYq1Ps+-C5 zuS9;9)r`URRv&?eBE_UN$>Uvg_*!FmN2&ucIq+ z#(cb2k8(R|e)OKdswFA4>k~@=cF$3XP?1Ggmjs=<&qz=a4DH2dAC&>H&W}InB$gS} zjNs*DL|AoxC8v5P!^dWTXp^ev__H5ZfU>L8g3_omyQ2)?b*c7$Tn4C8yOJ8QZ|L?3 zUQgC_N5Dq1<9r2`T_14@sG{1>tK>wDnj$kQJ=uGe(~(@W7&4gN*AoEIjgshn)@{$~ zR3jZDUL~RmmJvRV0IOhiRZYKGZe|)qW`m-yS_d2Zhzt-pr)rqk2C*ZazaP&!4#N4n zoWBdNKLyMpJ018r8Hp4dP!Gypjr{CeK=%Ha|5^f6n^tWud(JknLkKk`<2nyu!0?tAEEm$X0pylA+(#x&B!zEAOAanS0ak0S>U$=e4go4 zNub!NMEno>_H|17f^$&!`0k0U_kY&L(#K}abd6$!?i zA#L;T7@g$H1M5-j1qaR1qC9&0hK?kik3FJH3kd zC<9bodKYL*HV^fzo>IIl%qYtQSow51yD)S%I-G4{l~QLjfSQs$vYOnf_X;vyW)E)y zm7^HW_s(TqesyJO5_Pk#TwTwOZw_63NUXTuQXdxCaKmDWg0eT zH?r>yQv_HwbT)FT_jWp8Nz;+O>b>sRRX7gvmqChi)kP}?bdENazMamG^swHcL!NAH z(b#Shc>BNA24xqp6Q51RijFHYKt=-9o=ARnKZB^3F@yg%(ANq7CwjJujw3o<`3~o2 zJwVlKAS&l$K%l-=VBPokU+Cnn;Mp#CXH{ODkfpDfPvd@qE_ zzjf@}gRlMG9egzJ%!yyYOXO1~v=bGEB1N!mdcKv-+KJskuO6~a^8c0pkK6 zZ_d>u*m2^oAaR7@=TDVwNX|SPo`P6XArky1zVXD*)D6-4G+s08L=2B|wO1c7XEXg) zu{+1F_+{-yYB)oZ*Q~_a(~3?xvWrwBLxx>M7~O6y_Ad6YE-c61NDQ9%q##oiWX6^X&1bsHqbuL27d>l!()GE z2a(x%@9C+mbu38Rh!$Yy^Q6>DWcTJ@8T^RQl{7T^XXki-8PvI`3<(B2xkpN($E^lq zRrb4q_6ilx84~ER-h6)%U_AUS5=0elh6tnmw@J{AsOqm2qFEvw$1!&e%%HManN*?Q zd$mDjJ>L|3T}PogDrvxyz}w%CKMxRLW`jK^Dsy-$F~;pCLl-jhcr}t2d}|-!O}MkT zDpqW;4Voo^wQuLIqy@B*-*)m@?Ndzyh&-MR_-&vEwhi71Ug{KG| zX`ySKSJfQI7m+`EaVY@?b`il#3*UP3qjhS#D;VRyf&c^EM97Tabpop=-UhWo2-{vE z$fY$v1dj-|4+H9p@+2Em^|!0g^n9`bX89eh`D31MCcpq%un7KsoFOU-ZQog$?Yd>K zHKQ@eSF|UPXm=ohNc?4q?&HC$tfSjP#>dVAGoxbhRF6s?aY_) zdTRoR_*MJ>I?*=B8W9n6A3LvZ&z?@yKg#PYC9ydksQ?2J31;iu3=t|mdHtfAfwk!$ z-4FTyNCoh~h#?|>ZD8gES$h!)qJEi^pCyq8s}zq^0Fm5@LwT~g!C5tllp=HT8HuXv zL<;eKJ!kdtOTluw_l#Bj8eT=tP`Mps3P6_T82K{=7*sRpelx+3$W+CnY5-Ibv(4|YZ*67Tb-!%z z(KzH6TUT^Ve1rm6Nk=Deri$Nz>dBu~1~z{5*SI|a2J9)cf!439SF05twXfdEX8jlm zEHbx?+ZTb+h9F5@$(Qz7w%tA(s>Bp23L3Mikx4fq4^aS{20G;(DG3X%R|i;I*_>}l zl3kl64O5(3D*!{c#Ow4jV;cq8+KW!Ar#MU%JjEI9k0ihjXcEkhNAFpXSnyd|L$?yo zhcV`VMSzvmz+@dgM<*?l7W8{Bu+jC_QxfantqI^2M_zlC2vP7eu&0vAI8p>XJ_@MU z7p>#A1c>hQ`u=bGu{@06-LZ!)j|fbz*_k9N5!%A4niu@zc*u7F z6=Wqp6I@TqZ9i{bZO2P#=y$JQ6nv3~d=Rt(uYk&KCbMgmrs`LeniyE2sM`mYQ$Qvs z?HG$}At3wSMxrZJ)&A(;v9@UbiVcKY)&K|@=|uf)O@PK(RhS8EwP@8obbNln@E8Ix zcpKma)4PA8`?-fsrJI2_|7+#LjTKzEDc%(e^+3jWon+k;JQ_VqZ9KmTC_`>;c!i>13a4f%wunj-1{r3C*#xbD;qq7YVbW0WastTI~2gCA8V`p-^LAevUyys?A@EaMnv_h o_ihEKk}2w!-Lnk5eHv~50EUc~c&+1cLjV8(07*qoM6N<$f+m2AUjP6A literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_28.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_28.png new file mode 100644 index 0000000000000000000000000000000000000000..b16dda91d5811ca36993ea8783a19934068ea27c GIT binary patch literal 1969 zcmV;i2Tu5jP)sb@S&}{dtVP6@W3TL|;}VBEA`aTvt)PiaRnsI#>O+ zcZQCw*nYZi1OX5+t{koes0P7`K{8qIEcZ$dwjcR>nr_0BhQh3Iwm?1MVuJ-y}=nQx(?NZ^jb8x}ZsLFp< z_GX+LVaLFyWS>DLfNh9l_GEUNZA)*QUUwQl5(Sg*MfcLu_@IDd>d7)@5B^}nn7bZ{KUc+X6Z6=a4)#Xa4s@%>!$Y3Fx)cZ6Mh zyv<*J!IvTLpxMCi0x2HeQM=H|n5&%6hOyPm-B|&Q{*@6$CA))+$L^9l?OBz^IQ$ z^j;{n#%Lm5Y)>@^Dzax-9XPvfAksVA@A+)`6r2TuDs>g3&p4)2erL~6XRZc;a&UJ> ziDfq>0^c}c5^YJ;8`8x;DDz;SsWXhDfYT&BQA6E^2tC=6^(9L>%HUm`&ZmaMt-5s%-+Z7@t|N(LLwQQ%5BTviG>IvKcE5?(uY))9!G7ry@nI zrnBdk7Qlq?e|O5Tay~o9*4bG;Q&>e%@2_^gFY!vJUC#eV1u#U8%rZ7Yl;!xoQxQ5( zTBbsQ~awMZZ0&qDH|I1p?c*)A>x!X~!+n+Vi#{kO2i}zY)qwYAxE2 z*~R#LBJ-ot&ep1We_aLe=vD)S3W7>-C){z_MS-aZ5>puj&vN>UNn zUdAJG4wg?946~V^?T?(5>-`&Z(tW&j2@u;H4j1X<6|XrjH9 z-a0$zRfb4KJJTw@ss$ie@4_`UH`w2v&eJgdRe3rCSU2M<6%Ef;H-V~7UtIwZk@2JV z29^2Dpb?@W?W%I$InUE%v&y3az)%eYX6Q<5@Vp{ajK1o8R{Gib-L_=->K33-Z42Gl zX19%u-v5n(Fzfv4Z6jK*IDd?X27n=p{8_97g6;8ZUFTPw7gc~P`0V-U05B+LuLObZ zR}QOWB&!J7dDYtjqeuBF{2m_wDwEXYKLd8Nh|046o6)dLtPYOqyiNu9=lR4T&_lHV zzt$b@7}TIQi<#R3JGZKv;``_TsAQpmU7@N_(|(6{FVg~3!8O$4+89d^VouN>j6V%_G3c#uu z(th1PgzSdOUe$M_K*)MJ;~ix?%gD+(S+Heu!9R1;Q@;aLKYFM=Yy$T*kz*xJ+cBsQ?@U2QD0>@2%N~f{a*z`rVGekHRqcV>55ZwG#swVP?2Zn+3F^7o`1gtRs^{_6Yd5YTiwHVAj|BXtv2faW4IQe z?uje7V{R~+Gr2LleW@KoUkmN;m4R@DW(BH(c>Ui#y498B8-_oH>f{~W$L((%w%BtO z8K2$N#`CrF{ku0)aK~KmiNL9zhnZ1zex_4JXZ$X3myOgd=!FV;LH+YL04HpFx6}Eo zg&?A;bw}cO{x7EJsvzIgHn88Tdw=z*&RC)Mxa(GCws^CseahsHU~;QKoN<1&0z~u~ z-POs1XTEn|MLI#W`)V0E+po_$KXOi$zO#N6{26}$ulVm6++ypIt?_kYi&yRj1Q|tu@TMj?%DAymLrC(H9F?qdxTy) z&Q`9f>;io^_`f1}kcXUC6lJ0$!LAek2`1PnV-GmSUPogn;NRH@dh5R-2_o>{`mh!xfCs#N zU8UKbCE*j`TiLOvSy2=5WE)|E^?oL(EO}PS9Sp$0_nKq1FRGNvl?>B+e|{Jg1;FbC zX1i-PfAywTKMGnu74W^M9DFijPfBb*>ReUqQ`Cb6BnysulA^Jl4Oyi@^^(v7-JV`N znciMz!BZKcD%PKK29OyBsP+!4HhQHjT&4RJz^y0`Q6ilxfSzL!Ju*jjHD;czRp6_@ zSNo|9H054qGrCV1Ad{@Qi5$73OSgW`CV|}#18fF(>y!81>h^T5ED0xW_$mO_dECgI z;G<7h>HaG4RoSK2O7H#20OQSW`4#ZhW_E|%frGVkt}>`LD|eTHVS5JrXslw_3hsyL z+kN`2ed*(11R??@+ptn{b}>R!>sJAfetJoutlc4ROx7K%7zEb1V1S~4F*A4f2Fxd~ zSMk<(;;m6)!hB$UUKJKM$^h1w+9N0pl(%L#_}RMEz>pfKkC$bykzX+e_5lSAnm9 zHUs8r2C!oFJ;neA6dN~tjZW7Xs|42CnFXIUmR7IzX9jp&udKNu!_HOkJ+>P1hyolb zRZgLu%Z#hKGaoa$A9L;i-r7{{?2-)p*2rf8N;0U)GF!uE%Yoe_tH%hUmkb$z(fw}$ zAI0;<{WLIhKB8PZXSSi60e`Hs{xRU~IC~uh4DWgVM~QKVsEL>|KolfvfB`ZKex}>A zWjE^quSjK$$|x1)yDBR9y?5RNjD;&2nF?)t8>xV=*7z|uO6-bc;NK+`@Q(w&5o80Q zG!SUiu2I07?Fp=23~=@Ivi_zjSs7cQtGZSJzcum{fDSN+*vZ9mF|IQW9CMZ>Xa)GO z29uN}@2o^jwz~&Vz-MuL`%a)LNViP6HC$x^ugRAk;xClCXRS9A;kWndyukv(t2XtNUR3i!A#O8jWv zPVr*J4xG2%#_{c2!D>?x)pnFI&Q7jk&)%<`YOh=czxi6=;SjaY&@D9ZH~=TY8ulq^i-c{6upWLkD@EK@x2GWs*A;g z{vIIO1fFWIF{(JMvO}~<^{GKk0*}e=sQW4lE8sH*qzvFW;jw~pnzK5{bla1c1pzl@ z*V}Sd0pIf<{fQU?{i{gSZ&*C4;9GxRdH~#*m-&&AEU-~hpm-S@&BuA{$)?gU;@<2% zWT@3_z!H_&w8`K#%*yp)7h&UMgMh)XN>DM*$9cFh6y|IcFnh&urZ19+m6*MZ2`UMK ziOYQVnp!W}v+MC(Q2?S0_xz~%#dJpjjK=Ww70LP{r7uyW0)FqEe;)t? zn4Q21{VQb!-)Brw1wXTodaYlx*OlUxpDOsralC#b$SSQk9wiCOcy)6bXi=|_QKq7A z_R9Ra$|7D|qVZ`4umSPjBOSB)?`=8?NJQ5xD3xHaJu!Xghh3*!BRv(l3hopGpmFB7 zcbe4Gory}@EXc|=^U-61j3J_vukQU0&|et98e_r5_bgEu8+f4E#9~3Q`er~=u8~A1 zKVt-iL00Z##r5s4gT40{B<6e+RCR7e@3=p+dC$)(lT?_Xl6-ev<$oUlO9DIfk*KGk zLfhVn%V;$7ao07IPcT6Et6&R?1=%YDcpAL9Y&;7B6UJCkQe@>sNuKD$D~yrJ-AR!C z=h1ef7UariSdhJ-%mi=MNmP;tS*(&2ihK$I-yqbMbXI1HZTzXUA!JGCqC(=aXFE3S~WM|10nt0zMqS z2JqoH=bNX*!j4LytCEOdSNR?QFeYHl0N)jA$pPQ@oc<>$ zAK<}_Ag>aROcw)nz8MYPii&$AVS7}iGy2{B4cJaJFLO|A{@7j>2Tmaca+}W+$ zMfm`YKML(?f_Up`D>J7h9?m81#@(%AEW5TGAmUb~IzB2GZ(O8CV9~oWi5GFHUzA4gcN&YM!Hw-1V*xJ>iQ$KcJ#!0x^!J$ptBcXDb&+~mgsRPCxO|f zM)m1g<@Bx&1r=EPi5^bN+nv>xXB5_xHww$uXB9|=vs(gK1=l*~knRImk5Z*M+UMvK zwXQ^KwHLU$^BB=dIs{}h@cEw7q2GIHO1yb!NjznE@a8_{e@Y(D;mm085$N{f?eSWISFg^%;GL8&jR(*Z+l)uac#ewl0hlV_(@uT` z+#ab6G*k?sL-_zn53pm*zYCTT%+DGk704Xlp?m<;3XY!ePf@T1Dwhcy4!jEE@&c}k z%H#^toL4ItU#*f(BS^=+D?F$AIPwpiyeHq2bZWf1JOIa(lnH-|@+G%Vy=3*|PDt~u zgJ`XJdK0=y&|=cdoHlP~NOG|bPGygtoXb0h;`K+OFr(FM-cvVA7_&9#p9AFYzq5Md7;SD`^fW~+3K0wSHR=q_8 zuOt=V=O2iWl&@{ZQ!Qw*%%Z)M5m-r}1S@g&$~_DA@BuLZPv&pcz4$v%^Qbcsy$aDh z2hY(AK}sa0buC!(Weq^vSVj3>W8j$A)_NMOYQbBU&p8r2w7zKUotf)=S&Mi!7>W7# zdns{zS#N-^Rk5|2;bR&enc<2J)8MWiTI{m`iCN7p(eO~Ya%*a*25+3hYOf)AGi`h~ zFIjnuoxsS#^gX^-jlt_dsFGKmcn;B6omGA{ba2-%k8mx9J=R|J2p(6cg@&th1{z9n zNR7a=|B`&iuzwMR7oyBnPh7W0pn}8e+zqemU+p}l+ zeBr}_U)^%J!~<~mD#k+*QMxtWqbN)#3TdAbt;?0H$jSUg5N4QeAiJ3;vf;oofUeVS ztzqr|D&=$Qof4B;Y^^B&s?BQ3$6=xqJM7U9nV@% x#p}O@y(6e%qFePU_Q@hNJ-}08x&L4M#UE%S_4L4VKM4Q;002ovPDHLkV1lHU2L=ED literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_30.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_30.png new file mode 100644 index 0000000000000000000000000000000000000000..08074849841151bf7e31c917e604a6f103c05bca GIT binary patch literal 2028 zcmV-P)t2Cq)Mc?8rJO4lgBX zuQ}%&V~p#%#{b)I=(hDfd$s0VZDWkm+!YzR5n03P!=A}@PnS!FV+`2Fo;^&diLjY# z6sJf(P5y6zcI1WU&O{y}MsUjG-w_E;V(medqZX(%#GZyfY&F23WewK&DzfKAi$Q1tKf!z;B2M zULo3rtYIMH7fPQ4WQ@Qvh6({|{ZBg@Mo%Lr!BU8|_G1mSI!T421?0W^i9J;jHN+>{2!hV{6{RBM>BJoo0Flp%<7i!!NtK-uX3qKbWss!+Rtr?CYt+Ac zQ{6{FDQARycFNHwBXm+i`-%3ALY|@?NFknbqMl^6oh-;Q1u8Q_M!NJ~?U`&ZRq~<{ zA`29s7 zk!RkT)^ivEJVYV{6ZDQMUCLQC0=ADG;-yUNy_}oP*_jfadc(T}$T28i-bKDdN4Vc5 zK8sWHO3XRGBEWicVu3MUKR*6+@}tG<37p`;TIZpw*(xlBu&|d2!#k*wFVlx^i>|A& z=36f`*JZ5y3JtFWgs2Mo%66;p>r96l*95H*A(&Ts-n!$>)v@e^6Dj&UL<&VDi(aEc zmZ+R^UYY{f0QuZ2p4hxB}1WkWR7dPP*! zQ!|F+DOLAHd$FQemiP>56*9XcfP|dyu^KdSQUH{vn0IA`h~~RtxmIfNBKr5UIE$8$zcNM!sIBLSlx9lir(wNB$V#yMPF}UF1t4vjv`9 z-wO8@@hl2>1X|BOg?tSrODO`#2`wWTBTjInc0g%L8$s0LQQe~D_4Y3NTYap4rw}#7 z2P2;;a^1_9Tu}E}ZJ857cB6>wOpe#cj6u2DGByicMiM1|&dI+Gtb}*H_&X5I@yy6~ z)|GQQWWx@7W-Aff&^2Y!*fYn(}p2_W9 z$Ql!qBU_(jQXs9s}8D0%PXC@N zu9JL}wyYy7bBf4O`1{YpBSz3kTBpKT7(~^+hj)`7ktcGZiKY+ub+A5Hzq@)xSBXgI z-}!98n(OX@kLgSrLgX`mb)`QGM~iiaey@0ncw*#8XubF3^x8j#{D>p1e%jHW$m35z zp1;vC5Z$wW8F@3t+jX+A_P2|OaUyw8l>hOA5Hx^2uR?}V`I67|=>UyqXL__w#=ub> zvHST!hyJ`{XJlW<2p+nFR@@0xk2SKNme;EID@AP7&={;J7F}Dv_tK^}7t+T|4WK7J zbquVKU0I`Q1XfBqo%bU$M#*PI{f`KM^3^Ht?}DcQS!-m-M`>i;qi5E96+^M=4J$RG zzG&aD2Jkk5gzQEnk7dC&?a3j>=txj0LbEcn(~b6G`C@Z;*N2=~TQw?((0$j&rP8AY zA(f>qUH6Gb0G5O0J-Z_LqR>1b*;!G`jNQ9lUt{buH8TkPTngNU=+TC)?J3Y|)Au{@ z3b`(wWyqg%zW$FODWvoU-KP6@g>a-G_Npqwg6x;^{A^^{0ZTtw@~`Xq`L}^61hK^} zi|*Q>H6N103!QRK6amoM6{BYBq4}bQSs^!710btso6`!E&pN=Oi;grX+{-zT=X=JD za;Y2_xmxpNpo_i}*9TLkhwl)Q93M>=5kr)7N}05bmIosFWIsfLZfDO?e-C$%{t^Kq zAs-=|=OUpU&ClAA0WuOQH2|8o>iLoV-bK2+nm-BCf-!+38>^0u$Y+hs7(rHfQjSO@ z$Qa*U*O&hfpcN~Mx0r{h~Qi zdY6_F^~)GRBz;&O{~L|qi4?ENVR_Bkgq}w$nHfU_(x{>#{d5G7`>v9&WxnJ3(2Gmu zYUOAFkpeZTXdVT{2++0000< KMNUMnLSTZsm)8OS literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_31.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_31.png new file mode 100644 index 0000000000000000000000000000000000000000..d4dfbce33f3b5c7aa34e16d5b3b7c855a3741c71 GIT binary patch literal 1922 zcmV-|2YvX7P)4V~^Od12cB9Hb(8_J~C};t>w-vQVzggS?nVH z1o^Y}&w?QyA?*N}Nf;;C74c6f!A^Uuz044g=1V)k43H5gNPn{uWX3HePrQdq=Y&-l z_3#}|Ajdz2oeI!e3;WhusWo5T!_`iq(KkWj z^8U=YD^iGC1E7hc=Q5|yc&Nl`MPSyl!sZ?GWQq42E$skI6j>FkbcPuMRylzjYX_pW zWz;CUPgYTl+Fgt>oix2+vX3QkdQ7Y0AAxkJH>Ck9O-Y+~LzAvKusFKq0|{h2iXgN= zJ?To!D!|H<0ZK2Yh?jO`a9bXNHij+4x>45H$na6jIKeLRyIo#euZ?bxFhhLD%@|@y zIU}z~ZdXUeY&saRCt9~|EA5=c3gSE57eR>lY>w3iuasVG+iCLq=Wc^;r|)Oxjq0)$ zxLL16i^y!Mj)ZS?f{ff}@9TLyWXAB?-ce<2J)5bnS4LuXd{nDM7?Jxd*nVugUgJb6 zb)${(NMYsQ8e=EJ`X=&A z;S0_yOMZtYjagWRgjr}Mo4NM!tYVg3d#2q<+#>`;vVyR?K(p-ZM2#weUN2Kvd24?g zZoS}H0<0P$lK(dqhN!?BCH@WYY`;$~EJON}-&<+tNl4r8RSSsZALV5EOe+R6 z9)nTxy?ft+$X@CzVVW>cp7n&fEjn`P`63{xj{102zaINE@jK^$d^PYyZ-U-%Ytyo% z&dO-kajf>JRzZC<*m@;ugPzaSLTJ76v#9{G5la$NK?%qqbJeK`8gx;UW!81y>&9t^Lq2W9abu~+T8Mkbq2N&Rqzb?45^tu z(gy2iWXmY=Pn-fWX;rrI`dz(~cMP+tbff@sT*t@n0xTs!N4v;byrb4AvQ8lHbvxue z%ch8U8HL{hWUKkR0A`alv0kPBB#=sZ>7o>0AuNzjydip5!AoP_Dd8lt3OtKGhxvT~%fr}|ASdYecWmqm6|nOA z6Vb2LR#*2cfa z#xN@{dl4!NIM4QuQI+%HDGs`>oZI?`;LU#_IgB<9Mb1n_Nn%ljj%@OrW!A2Y?cR}k zH?qgX*2I4gw;aJ+fJc7jyd4p1r5MJR%yT^-+a_|l-AXWvTGd|)wO;;skuKX>KR;br zkAOK^>UJ4*Iq3w^{{JX|^d#DZs{86-VWJY*Ajd=fBcRhsr~s#AP8x+aPu`QZL{2G&&sQ}v8XfOtu4cEk@qD3zPjS*ZzUKrVUkXJ7 z?SyyYV3lW;6EKCZ9?vTnvwP>gK+4o$DCd7DfaM)eAUd|NW6U~%B;U*NyI$^~n!q9u z*~XIJns^iV7RY1ePP;rO@gh&>^(fD09K=!{k3g$WhWuJ@q@T1T#^>YjmjltcHIDu5(glP=|Lwa54IGmbF2;W`+s;9#!aI9Yq7T|2HHe=FEB zlv%*;yuZ`QBv6s%-AB)@&zbp8T*Fge(!q|24O1%i` z&-F$z{dPdkC+*7Gq}ydTPtMOML1fcu@_%Xo27069qIbiaN7o=;TUooH=b6px^Xuzq z4e*!(czFsfxc4~`{W7A^oLUtuN3bH-d(K9F)@eMPc7mbr1DuL{J-0<(p3IYm+kr(-uR=WGvhGpJFNhJ02l+#Rk^2=ZvX%Q07*qo IM6N<$g7b8%pa1{> literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_32.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_32.png new file mode 100644 index 0000000000000000000000000000000000000000..c9c169f2eb4b33cc403c054bc170d3880343f82c GIT binary patch literal 1900 zcmV-y2b1`TP)2S8*IBnWn$_&b>3v_28XYwLvrUTw*e-KRW@U5s#2e{Fq)!cjy|JjYuKs4@}~Ca!tYa)vgU&Y=}Or6=nYWQ|o-8&m_8d!isk4ryzDY5>U*+=)`|vYac)sm7}F zEA@Jk^IOB~x!zh6wULyh0xJrxYD3(`08ewiw4PLiwnkEbCx`-dx)uZxBV=;kiF6R1 zciQ8eDvh=VkFW6p+@85Bf${GsV<@lmMt$dSMYqFF)CF=8>dl~wgLW38ebU% zXnK1xsEuEq0W>FNa{iPjtx1`I2b7%MPP`qv!IQ^J(# z0nv@?N5@B)K-*U|HAS#9urz(I3?*h5Kr&o5ha!5e1c6uB?tqmNvujF+k^AU{I#3hN z>Cr-k^Qo*zhcMTqb0f~@sR>C(D0VoXLknb)0T5vlyt&oYvnR`XjyPRoEq?Eb;J%Q2 z(|dpK0xH@hDNjGiXj!^{!XCI2tuBg=(dLaYelvh3YzNSwLN+_^dorcy_vqf!`3ZKD z4w*EMg3Gw7Hh{KgsH}>@$CK|l-@5l?ctJq{eH|QW5vAONwr_O3D9{tB<-&i#@fNiD zP7DBTuvA6!d30=~L(tZebklS~Fmu$$;#dmeR(Yx_q!@LU9YaO+*h*DY(qj_7>5h;`;)Dk?r+yb;EsBiK_Q_gBZjG_v6-wyb6E%UxcvUjREl(FAbMhHI-x&%^R;d#Ys)C2fnlxhG61gw zBn7P6VFlXh^tui{-U8J%(g{d%A}qQC(G)Vq(7z3=P&{+;rOv{V=>?nj9C=TGLh7XW z^^UYCVcPkF0p>#vG$rr_q6%3RzSkyda*^>XsVcJ96HG8+1^rJ@{{GqCyjBQlEa9D6 z3sxRpJ+0n6v19&F^eMgYRE<HewKX9cwAtkAc5&r~<<`HDVckiQb<^|2g?^PfV85+waleIq$Gs~dd> zGv!nLq*j>gh;(l5mqA{k$0<;fcN)kG5N#fEs`wf^+0HAndFviw-!aDD-v_98Aw-op z;rv~NqSxM@a=rxZ^Tlhq9mg0riyeH`& z35W_CXzdzTy-~LXZM~&8It@Lmby!zHE zajiPn#`4eFl_O#c$q$wTr8yDj_ufB$A3&nDNZ#WV`lN!eHU0Z>NpJpn1zsUnWuu7m z#~AN_Aw*I*3u`{ow(JB=SMz83Y}zAo@}tbK0xkVSo!@)^`yxnk$g1*I8%67jldw*= zM6H>tR&}pHtKzNuOAK%V{3PBDY6otY$kmb))rab}iNvGTy1bl6+$g=Kh&!zDm zPB{II0qA1fFsE@c2(*-EoqUfG5C-vdI^py;2G9(0M{d3g*<3ou^J}&SIPLr&2GEpQ zF=!Td*8>sb&GG!2tpRRj07;n@+*Md2n0i@zjGX)kV|aKB1Ka_`F+10$>qbsK8Wa&d mZfAi18JQXYnP0VT<@Fcvuj8iFlFrfq0000A_}~RbOL0QFiEg$$3MXYJM8g%xDxn@bONlvTJ#-3e=`$gkqLY> z_M_`>7qW|!rK39ur2M$<49%$i*W*iD^QL--r%Uqb5A48$_hYQoCo_jKJ> z0@xtP4pq+kElE%f96OI4H(5e6p!UJ}#13H~6XCZcL8h_W?eD3>(lZm{BX4%~0ZiS^ zFoMqHj-H?!Zwmexd@MiV2!%+f%)Dtthtp*?zpXKRTktbTCjgUK@;OR|l>l@lfs}Oz z-WdEbz7ik`s;tBMzJ9H1w}ecF6=%qVdQ%yAE4iQdZM+1qGn@9_OCL)TX*Gd z$e4W4F4lD%J@>9txK^tFI-I}40RKYpBepxo$bTro(yK+c-Hw0aXt;wtc9tf~R`-J- zEAZJGt65}+^PUKP=Q=D|D>^j0qu8A2CW5Z_6{kw-{jEu`qmkSZd=13TV|;xX-n_Fy zi4_Jw^lv3dv`9;~9N*CxT8-@!@HW$YZOxO=FM7Kx=<78dBbbu;BM?rpb;5}HeJ@tZDI^?NH%9^jG5y+vQt_%fx zz03;TKOOj}mLt0uU!8X@tV;XYIWnNA>#xxL9VH;zc%8bYtg}mKME{7QtMy*W@y2D7 zK+2bELif5+DaBRD^-y02YlEV0UyqHbsshGIp53VQ$>g%`?SL+otgkb$HVphI*mAB{ z%jbPL)~fH--EY~+GJy;%Vxl{Dyk#dshYgmGU;>~FWScLf@Gd82@D$avHg(zH#qBtp ze;S4+A_|SzLd)vf{m71J46?yufk@{as2;Z&Oc|%VfzH5|VGNaei^v$d%i$}5w^$=O zT6SPHG32<{(+f^X9my8H_$(xC7HpX)m%fJGsM|B#Vv=YL zP<{7K8CG&Jc1Dbmg|*|f?N+}LG2f~kXxx1MLA%2es)c*IRL<=z1G~_%bG=4$H#0Ck zL+n@n=iwbC;%!*j{Z?}sF>43d;G<{ZuYx_LXzm-5!dg#v0KDMOKIKkdWP?A(7@z3K zWu702&j?mgO-%h>p8`4%1%FjGYiD$9jqLgHWsr9qWCf%78R&WF$ca!nw|AqP{UU0Q z))Luc9s`*q=ng(QrdgjiAUoKGQ+MT-9g(d_R#)(mjany@9L$O6`=5trf{zT6uhEf? zfp=C%I=vpm>jON;JRN+-9u$0ZgpP1s7ydd}3djnab5@&6DNovn?prddNnnk+JNTAe z6KL}>v@c_7{w!Q8(}J~wy|GzDM=MqalLS!{?A?D$@R?)a9H%$>se{foS>6di8&$>5 zhRxEW*APSC4R= zr2*{~dOhE<%^tGP zx}JIhGQ`>qT46R(s$dx-112F619r0k@*%UayvEhLe&l2%l+C&)YPd|$s{Sa6yhagS zk^GD;T9y|;G$#}M<2d5q1R^JRh-jLr^VMCA0>$cM%T+beqDHQp$!G>(>P;1$&Dw+) z09mgiR?wx*gWLcS1F+1n0;~LFgMS>y&tC*-R2nB~2r_)tAq?%$M9|3~|Ef*lgbo7g zveEl0kUUFI=Gy)rMyv!sQ)bXEu)6gXU6%eSBjfBWszGgGfUJXdP+g=C^%s%da?A<~ zWOqL6&($5B?g6ASz1S=|sJ~ivv_9+4nwO<%RO{tB(fbH@1^ovDNafm?tTUbhVuNTr z!xr9L{ko$ExI6gY3}6|PLC5Z2MU)8g*&JI*1f2x>>M?<{9 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_34.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_34.png new file mode 100644 index 0000000000000000000000000000000000000000..d0f3a5383d809824126230e478a9e2ad74da83ff GIT binary patch literal 1923 zcmV-}2YmR6P)r#ZSK9l3REi~$e0 z?P|~Kx~}6mj`KW^pO=4tedB$#jbx6#<2a^d&*-oND|%%*4*LunW#hat`20N2<6Yb4 zUm?PtH>N5p&S5}MU)`eb>hFl1UvMJY`Eh1fpP$>z}xg4PJc2JR8et! zHui=2w+q$H+0@Y;1XliC=y1NL^L1U)TxHK81MH?wuOR%5^lxF;LIzS9X*FPN@JDOi zmI72K*b3Fo`z=8*>o|3uI&QE8G9cRE{f!f%zy`u^34%&tx7*%h4R4(h5HH)=RR<_} zx55Y*$sIL8H=gADUm9;?oeipfkbJHEsDo^Ia? zhzOOSpbVfc5DE64E6!grZbsKL>7h%vZ^HBK8#la~pKbJEB&yCI{Y+s+AJhSzHbeK{ zc06;S)g{aIp3L{18&gky6nK?AL_3OrV!9|e0x zWw{*Z*|8p_cc&YrUdhtI=wti115qG%=-}Cg1^|mdHQ%xYGsfr$h-wfpM)-!~Q9p~F zjvw;fFN4@bba0ffD#hB&_ztktvvLjYhEfR6V#s*g4wj!i#iEK{b!K)ItfImKOb122 zoyYpJt7QjP1H+DcjSf~J~{@*!mye1t`Iw21_MXM043j)SzK&L^72^j0MUJ{qBZR z+qmBbR-!$k><&7NWM^}-Vs@YsoUF##k?U6=-@>lzx|AUBu1jNq=!&&cBzj};8CyF; zip}v{BHw0D%cJN@N^jcEZ8!ARM|7QtKd_hq*(fU0F^eQ=hi`Yq8E;pI6bqWRI!1hf9tlg|uUb&}ezB6I$#>{SL*_4()b0PF^kh9JNb4W%4Yzhb$=F)i?PCv<N9$U228!w<)Q7SBM-7loz{R?0pULQuy8J)`@#XNl4lO?Ec8&( zyRqw*iS^BrY?$hkNH73<3T6@!jItw1rDYS8i8wlng)Inm9>rXfXF41x~^ zuoIXf>~%-RGif87mf)&fQ zMO2v$Wkn8Tb1Ke1&-35k1K_4mffZnVf$Kzl8SV}Oi|qQGJ+p}Hk+tJ>#rfBD`M(F~ zF3OOqcF2!XLc~@p!BcTi7rdaWI^Sgg++4TvUAG5zEvnWA9n6L;Qgj!CqC9V%N_+c% z7}2#3I-0QyJ0YH&RXvopidm;t+K;b;aq%Z3Du(d22e0-~p`Luzo_9E%-U4Q7fNvIG zRtJm03YlJ&G=cM2kl`U>?^W4%wjW;yd+#$td=p+E?hHus=6Ofq#{^(q;ofPxKX zX7A3{T04&8IM4I=x%~rd>z}jNNM>(4j$=ypj14=mV%NyVzCL}8M*X}#`20N2?Os~9;xLOK94N|Yejwd0>)f*tlmYq;Y0j&uO5z?<|PPJc5KWRY?F zsP6~!ZxynWv#Fyx2(0|OP~m*f=GK}tR+)3i0K2KvD+s@l{w=I7WFVE1Rs+@sf28ZS z6rei6R;YH|w*dw9bO0!kWuLQPSaCpA5Lj7v z;Em2dj-LP+Io0N2Y{z@d-4-?&Ru;ns)SJ@4TM?ZGF57_(!hzln8WkHmqJNbE-nuJy z!}{dIb}{C0_B^_F;iwex%Q);?LT+ z8=0V>44^8A1bfdF=l3=yPg!s#tG8#I&Yb*a$4Bsdd*OsvD&(%n%If#lh|$iE^k(ST z3$7Wuf7eN)>S2RME{JI8Cztaj#q=g z%CvKe3ezggq~clF`AA;}qd}u;ANwLzRZmWl8O^~4ME~ry?Ep)G%+3{fn}og!_7;@o zavW#-dO02YRj`m!v%G1?d$uuD*x;=T4FDE_YQe=6Dig>QcU6ee&|QwV@al|8nJC}= zGKdXCCq?;6ai~}HtkeW53!pBf;gOy@pqzwe(Pdn=ft`Up!<33XnnVQ8k=5w}p%${X zFALn=1>I_3*nXehfQ!y@wpYo|?5LS{4Ku}_)o1IH%yCjF1|#R+$r$#J0d4=xM6EJG zEEt(`MTatp5o}N@1+KLra|*zDde^7G^wVzxN5P;5OVv(@cHC%8mR)f7Fx~9*Gef_- zp%k_5w}F{xk9O5a_Q*jI!>}qo>-b2o^30~kr+2u8dZHOJ0HboRIAcy&WdLtsJ^L~` zDx7BZza}7~p#|BbG(RNqCr$DK(=W}(m3sJ^eiX95P9mfLCTPJnb&e*~F_2>Vb0$72Ah^ksU8LyyvYL_ULe8-H9Q8B!G z&WiI{n)=MrUN%L{I{)sRnoWDQ2xaY9tL%X4d}hb+SHY1|Hr6{fqM;cu!&i55CG|(? z@6G@oIiKO1z=`8d*(TR1(}rL*`eC=>&u|bJAtU( z%EPu9%q*(Xe>AtO-POmy5w$A;Jar6If=Flp7*gW3y)^mGkhLFWdZg18=bEl1A9N*=odOY zs`@=){rRrlSRr=>UOE_!v8W6b)kkO#WBFe{2w?-f=N=o(ppwoRs*Yx}yT4*{jE~Y<_&FB?;ZVlk&Vb72mV0vNtytWbU4g%C|uZV1FLs^jn z*_e#;&-48KdjOmi8n6P4)as&dloBGgS`F-xj7)0t+D6xYpK*R`&Hp{XuByE1eF1a! zOl?pR*vhpMUeINo?=k>Rt`b!;SxsV}*+8%hhJRJXEaqqLbA=u+70fWeYyXE43Zh(y z_a3~|m$gB;W-;s35(ZEr_Q~SQ+F*gZ-a{r$;5e^Bk9K}GCEelt*4po{gDpl8`zF@# z0`ZREtYm<@oc@aeta3Cavj9&6PZ=}gN3f1$x!?AgsR8bGerwJDPsC*N=PIgXtpB&i7PAcSL=EsC!+!nF)3T#y00000NkvXXu0mjfEmyX| literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_36.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_36.png new file mode 100644 index 0000000000000000000000000000000000000000..4b34fe377c1b7ed112f6b453fbfd5ad4d004e4d5 GIT binary patch literal 1937 zcmV;C2X6R@P)JAWDFmT z{pkGLh3w{J>gaX?DgQ2X7~j(Qx-M!ivuBq9c2lQS5dKE`myl~|24Wd$)nTRcdu!d6 z0$3x+3RTYgElyB196OI4H(5e6pgx21i3njJ9pSe)L8h?Vecp2oYn|y3A9=H@4q)rRPm0Iu2cW^VgK`yfrF! zL)zqnqFCo~^xV5n;d)X1>Nxxr2KYZ1KVrLcjQocZEWKKE+kNm)w1zv_V`plzbag)n zvJ9Wiv6@A89NrVg@7#waYh?}1?#MPLx{09kedSOk_3m;4R==tdcNCI4jIV*%d5kg6 zXhZ1PN_D+rgp8vy&LGD{>;ASb0@)0WIjw{7jKb1Cl2Ks{xo&3T6-My%l=7b_Aer;9 z(zZ44%os#2l4Sry|K8zS8;oEXYb8A(r@9+nFwOVYJPAGiivcnU>1!k-8+k|;V*t%! z+Mz1OM~Bbqb2lR|sW-e*A}|lreK}p7$=yr82LNSEjo|RwWh4IOK3#@ zC@*)d&B(LTf!Fy+r;+z|ppuHKko%#&4%P}q)xI99smgm^1#@V~QJ9n^b=?8I?v6FB zbA}%UTZf5qxt=G-T1B0gW3A^qz_36!TUqcNxWfr7{h!uNBN9lM1ws zT5mMwPHL7qbjsB7%`bzPDE0EyN<>?R+!2XZH{$7Y7eg_va1~R=N8gZF{gR4V?UR=l zv;tXr&E)xL3=6CE(q|&aTGuYjbJi~wQlHPf;d!~f=T)q_a*hf{Z;yy@jF;qDs0N35bOvS*Qq=p95HX()TKnbr%z4f!2rL21d@nI*a8f znfkzUFjT#>k?bKVNYUS{aqn~jrVuy34P+v0UcEwal@6nb)l3srz3lpI>XPa4=?Ir# zj6Vj!0Eo)1>KsL(XMDyO9s}s~!nCT|&BZvc~U(?n>l+PnXOYSP_RD&pIbIYCU8ke?I@} z0vMY1s#>`j)DC8i-$|*ulbAqhOU_xX8?xO*1&r|#8-A+AStdoSMm{ne>lkc=BL=iO z7bFKowv@ZGHeij9^f)WVmjW%CTZw#&HnWGwv~N?cS1VME|3onu86Uy?JwO!U*7F@X zzjC0=cvSRSwE~)po_82Oa=gsgNT0vH4D#ARRxqN^3@kQ@T2F5-vle=mZSA@vKcaTF zt#zOOd(D3u=qX$^{+!Ef!ZJFN$2dVWH%bl68CALfrhCZ*sK(E~hi8p%(R`=zJ$aoi zrB^6wCa4;}iYW4}^JfG0Ck0qWX9VtweCwHh?jcGAndf&K-_mD7x2udk+Q#P3!u4WW zFglc7(byq(1(uV%#rRAcILGNg|LBc*RX-9opRE|Flg<&kD)Wqt862p9T?K0+tq)@P zzkU#cCRoqAB7V2=8B~qS&gnR-sO^k&vFf{z9)OAot9o7C9Lizrylg}>2CG!@jI8YW zpkPG$v7Lw1>5BpM0A1-uMN$<}TjfDU;GH@6F34bvic=3(i}}R>9=+=ctA(F7+MJ)I z)#{v8==Hq)SM-WnZ+6d!?$P~^oPZQT@2eZr4%1cf-|Ykv-RoLWtFK;>X%&2C4PX^w zY=^*ZEHeHIqLkpV)#|?FbwxI^gJ(cACu98MIR5@UfZmi=paY%V11gHLwZZDXv>{g3 z@E9?=&i5JPU)N>-9$;5n)+N_VN!k&lk@TypJ!1^i1B7tPUgT%w-+BG|?_le1OW`hb$y#*;7Kj1n z)nft=cN_nQ0W4)$bg@9ELwSx+&BwCys4@Yw#v=@Xlwl7hJEyu<1=A7aYu>Nu;6;3N zW#zwu0kV+Mv0~6C>j`UZCgSCM>#!NTh5<5|8<(4`Fi3Xp4xm~{?+Y1SqRIeI)Byhg XB{?Fy!d-=500000NkvXXu0mjf&_JrU literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_37.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_37.png new file mode 100644 index 0000000000000000000000000000000000000000..4935b75a6f35f2c11093d8cee1a0e9991e2a1bf7 GIT binary patch literal 1944 zcmV;J2WR++P)NS!%o*lQ%)q(yt(Y)&5mv#78JQKt+k-1iK>sj!dw_o@ftOh#x3BzzW!+uOR)&nV^aa z@!8n7ufJWWF3y&YZYQwvuR;g;%;xhvrMb$Q!wj%Hb+U%=8`Hmq)#Wpgnvqr=);fQr z>#`D{l3+VjJMUYZV3s&_o;q%137-M|9(?YI5Czr|zQqYDjot439y*ww;Sg{8u&WPH z>TV??cu(%=3A*tl@{dF3@|})w$b?$Y8%A_&y7lI#HHJ?kzk;#@D4u2CBWGA4pvwuY ztSj(D@{i-k0Wwl;9rn-ty|3LC))`hd!#dQH%D__*od!O30Gi|{vIxqWjUC>VG;me&^x;Dy`9& zXx?XrkeLjC(!WANwqT}bj9+mE*4Q%pb|MO<$QHJT5zvaD{I_aBeKYk^s;o! zY(dU7(-_`OdREJkZOZ<9u54;L(mtxe(HyIX-LrJgoEhDBAPc-sT|?HVOK6ttcKm0T>a|YE}x*{QpxNJ@}yLi&G z(~h01;7TV@8u6(NUpIm#d+Yf1W4*G*Hb15i;@>vZ5XX*^A)U!ANDcRvT4y4ZETASn&G* zQB$WXvk}T7Mv<41sy3pC)Xa|T9g>li1-4IW)JCX8{&@dS50EuHR(RH&p@xddyaKGQ zBQkBDfieb@kDgtzUWI&Arrxu)vsxl%$-kFIni%uY3_SLmNBOlH=iG@mpM;*F1sUloel0w6 z0)_k;;!*UoF5X8Eo2%$zU{QxJsE?L3Qnw=KMU*za@Z?t_tjEd@9b=d8Eu7gdJz?n5)3-i24ja-*QU77Vedy z&KISpF7j9FpB<-U0rmY8$ybhnW1J84k0(89ikPtRepfVJd6Yt6aj?bv9tEuU{p>p42V0J0T8*&2{OYfi?oLN zXW7Ek)VB-10Y;dyEj#+EeF#eT==s}DK!%|EmFV}RS;J;h@g1G`Z04%SN1eUjcNUDS z;iEkOtHaEY8Tj&o^s#3du66>i+g?4YrOnHV2t;!#*TIlZ?Sm~?Upj@k%CAB33C?0!f^JQ(Y z@KMiDDHDDk>(Hafua=}M$Uo2X_s78&na4gUYcNN=!Z|xLz*VIG$^cfmH>R=ycf+4D zX69$GM55Yn$ISEqSCfC9C;v~xRO{y|x@4_7f&%LZ=<45pMFv2|sOZW9oemW_!b(GC zf49$-YemoP8KAN;=zdm4H-;nFpYeRf1|Q*8#%vE@<=vhEs<5?jh0r_u38vfEenh&( eYzDZa2lx*Z!7Ci0000P)2x$ZqmI z)d0uhtC*zw-2pqw_pJzwGATunD(3!2d_ulf6zGGTJ&2=BawVclMVb5Gu%moWMWD2y zYeD2ZVx4zYertQm_pJ-aGKt{M%0IB1e8n~}!X*98+VrdZAM7Mwu?Fyn^W%x2Kx3xh zoAr!JV~bSpk>YK&e4!#RT3AG@*cH`&m2x8?wnF*zyj2)h%U9y7k1>X4od}Z>(-w1* z@}jveij0RK*ITqAhCd_Uv`m`tFvwC4!ekY5(*72o)hQ;*6Uxs{@`Y*u?FO_Qr7^VH z!!tlaY;;&N%L^*s3gQc(bE`&&xmeDZaX`>!iJph6I{&;(hL2V0YiE-lTVjuGMO>H=57TLeI{%JZdt5F?oJ8m)Mx z5g`-eDW4K%c&>^PQ||<>R=x+XP30eL-GSqNv?5Sio8fIIJX_Plo`$QHj)eS7QRq$D z5CfO?`Ltt1@N5l#5Ja)dO-jm(To+ltV(q74wt+KKEd;AN2V@;RqU&3;dCt^DRkMvO z9n%1;;-x}yk%5a9lD%;44V+NAo?tTytSG_}I@&!f`NNRj`{|QmtP03PPWqj%*{z^M zWGk)b1@SWyIuNhdX5mQ1oNcwdhbY?f3Jbp}k4M0D9G(MMLX3oHYhP(?#879wb(Qj~ z@_i-Bo&`j_%QGT+Z0%etAO@K2!83}Fw4W=Lo_#g~8$gv;ctw>J!Vw->CbsZvHlXVlV>^{C=^Y1_2t1-}6gZ63ZlZ|(xg*wK5} z3>Ce02iZP6-n|s2zF3-Ci1lQuM40Acp9jN z6gKI{GCDpSqMnBss5BVjw6*WMBb!FtE?@3IVwTf3p z1Zwo+JAqd!eP#%PMggg&iF&?wl%Vk@4UDpF911A{_TGQmKxy&HHjwT`Tf$jbU4j(> zH2%DZk&Oh_APS{{rVlI4pWX+c$E!m>HH204tq6cdhG-d0t)fwcOh^VN^lN>)w5EekDF7S{bFkMF1+KtKsE8t4Pf7Yzc$% zGjp^ejdib8_Ypb1M!}vJT>;BWkci>&?Foa@myX`LOwA$jhoD0FV~n3c5W4AXZnl)m z_tCEBf;>K+(R#w5yda+KosZTW5y#6aoy*}=1JILPaFkhX9SZGQOX*pf{9KjiSWckT z0N(Xh?I8U&%kLPpkW3d!04b-uwCg3Pyx!kw literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_39.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_39.png new file mode 100644 index 0000000000000000000000000000000000000000..d276c21233c76a9226e90ffb3065d2f9bfaa23af GIT binary patch literal 1662 zcmV-^27&pBP)|~@=aLw{BfrY{SWbZd^cvNX=m41TiX&KMVVANZ=!|?!pCYlmEm0!~V zFp)|}h$tBgy#qTVzSFs>&Nv-jv`e($F$it&q&CGFE?VmDqMZB~RPo!33%6ZWn)s8^v;dL}q;PUa*$j5u7`}Oe0=x_v@dHy&6 zUAV&$GW4p@74aUqR}9WIdYl~E=P?Fcnt`Rp%_|tUAyt537ve zePUi>2H=FL%nBMUnof801f9m$j9QU7vS51vZjp4YvSHMCNX}3J+J9t?uNhu5dUPL} z&b{fMJq2KRg<5q4YDlef?s5VuOQrFpy=CS0>e)*FShm+dt23!3+9O!cW93?rv+4{L zY2PxwXD{7g4L|oX#u$+IGJb|{6(Vwdm4Gq{1Zd42w?-35 zTBnr-aq|t4ukG2AxdNW3$M^q~0I%{b=F)R3opDsD*#>XL_*OaN`UD9P$KsyzWF|2K zWW7_{c(&$8l}fMeG=5}HniEt6qQv7%Pf*+hY64NAEMy!dS{8O1-)hV_e%_Kt_sP-c z-n)MxB#W;jM9q(vytL01XmtSUaoI?Y^5i0z%HlOXl>>iX z>7Ok=yU^wUE61V=WoX8ksht$)A%)I$c;b{6tWBFHhqWIgj2M@f@`1*Pg-9y7y{X zDYVl_6x_bwTa$Sh&3G1Bil~UG>`X0 z(|_cAUtu(FHmcMuruCHpR+^HPGw~hKkNM&sNgl1~>yF?q;{z}m0B@fA{8U)SLe7A9 zoMOC=lyNw2FPC>R=6QV*xM-IKRuxCS2zK@ZVg|^JO;1n%6Wl<^a~kT9VFz7pPbC@P zL~zHasLa)S^OV#op3-cC;>t$+$paAYxt$s$+Wcj(BXBs|Nc@&Ez=`n6hU-0NWDgz9 zajfSsPwIr#&}2*X0GyyF*MFKVP+)?>RqfJ;Gg^&txsn`Y7EKj1Pc*BS<|Gi{I|69!_Y6;Vm5U6YYG<(ef>R7XaRJEbA43}o zNza^&Zl`>TE-nDxxBzQfzdM?_`2)TF^fC2LeC7b! zIsYW%TiyDKj4O^qpS7lf713Y8*Y!Jrt3p=6!~dkN{w{q*_`1FgtVXvpd1|4D27um} zX)_Zqxb+?froBp*ulu`zyQ4pftP^MhF^sM(Lr-Dax(b`98K9EU9jM3z7HugDMCe4W zTk=Hte*R!YSK7bZfjXT)mX*jcB|8(px7@cCy z2TnyK`X?$JQ2bA#e$^4G(eXXPPX6qljr%_v|BiY5DpvUa1224YscsB!od5s;07*qo IM6N<$g381tfdBvi literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_4.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_4.png new file mode 100644 index 0000000000000000000000000000000000000000..354a96b6c5b40c54cf1fd55e0d7205040cdbf583 GIT binary patch literal 1618 zcmV-Y2CeytP)AXuSu>^=+xNGJB zfB}sdW5977Fh-s1Mdvt<2FbqQ@N>5SU)+ncBT{E$2N`$8*_~cz80%XC=HXic{y4r4 z@W*kCNd>lg6UgpgeRJ5oKRKZJ8VK-TDHS7RXy837oS@^JcVmhJ0PvBaDJr_&qT_V} z%Gb-2^4S&BN&w3YDT^w)YjA{VSx!J@@kaEg7$4xqCUA_=t~}15mXS24w0P`pd;oxR zCULJqkK;P3d zX9TXN(40Uj50>$Fg2x7K2k=Cxr`~2zdBf;&0*g1MQ-P(!S>%lO$@0mVD^4ktcz$K=ieSI;Sp?A6S}n{xt6 zgYxc_;oZQNfXo<`i=HP&N*9jTaCEI_5m@PcMa`FFngvbo%WeT$D)pw==#|pb;Bl!x zIzE;#<3>~g7lcda08$fYWd$xOr5YV+;4}xQswMi~V-_FFnWw%Bs5VR1tpcy*o?8mY zW`H{|%S@*yO=VMJ<=UtH9&rjQ^_jnX%0MBq~rZOWvMTX|xX#1nk zYAwQR={|gQ3!0!+sX?3FzSf@3OxGP`Y7=N}p83LLCh!1BTVsK1GOcTG7FJ_Td3l}gDFZ|XG#s-I zh0^uWYiGnMJ(-|Fr}N6}jsB<%$L}8bb*cwc@fwY6Ht{-FmlIUyBhlMR*C;*8`xs*k z+zDr+A)?4=ACS!+9%LL+J1ci1@!roP)6@(t4rj&a9>(5isWxOC)4u3>$>7(T>$mJp zYqs$L$h!coao~t^it{K_%Mw|dt8vLp^~5!W)G@ey6f2AmKr(=4h-`}WATs^xL^k_z z`{*D^qK&hHgjL1|V4A?EhfG$uBO0U1m?CTQ0^dnZ^ypf!e^Q&>i>4w)W*4}d?Z@hwNNy!jIy z0UMBO@~nN8xd%rl>j*#8)3V0LjSY1w?D18Py&KfJY@&q7+9%FYIq_&#V0s|gowds%?3O;F<}n_OK7Q=p!B(tvAZKg zW+kaRd$aM!7{5J$H{$6K1FzS52~P%?;oYloox_tgxwR_;;L(!-c^w>?40`7Wls+d6 zrpxi$8QPgV4R=>yu=WA){}VA0qg&3v3B?_HXGicF9)Gv8anuyWc4k+3&;vVKRe3?Kwib26Oe2+oieAHS z12c!3nGvuO@H*~y?zslfUQRyldo~kv2NBx?R3b6kJ46nLmC4n?>pATgDiKKQIj-we zekvdLoyu$Rj_7B32I$TZ7rM%XrdY4TVq;t9(juSxKI7a=Ge9ImM3C`(&PZH_@H&WO zd@1u;kssMV^Hb96lnl_FA*#-38UK=rrt7HuQsi6vSL^#J16YThogqA*)r_DS{#uKj z#c~2mPD}2}`8t9P>nSt|+!35%=`-$mHe2n6rT=NvJHkropN@~u0AJ|%2c+VWi=+2( Qk^lez07*qoM6N<$g0=nl8vp`YmHw&-Vt7&7$bBf-3d%a$NpBb;Ud){j`X6^D^$J%iEtb6p?kYnlK#36PvEO#sKA?tE%vMG$1#H(>dX!-Y300zrz-Q=L!kTd~v21gmzo=3{UU z9|1sxX9NP3H?F%g$3kW1XE~qR+1kH#jjoXx095cwAXsJLsl|$*GV`f?M0Bn=R+6uk zUo!xxkjy}cEHX9v2|StcmBEc`#;xIvU7`h#L$JY7@#`ixnvmkXM)~47JYJ~ zfb2k!#&OREbL^`9!-lGim*(Ng)NBkpZ+ws)2q=$^L#CkR<6ASI&K2kD(N9qk2*^Ai z0e}Oa2!t7VS*Xf*kKHQ{=NdiE4()yKz1^CFrN+%`7&jpMJbT%~nY#*H>wJ#S*{?$9tI#qozaJC1e2m zk6Gtyj>l(Q&`aPxtIfsp{!Mpd7$Ca1vy31ugeQx#nV`b?l9MC-kd)CBk~~iUzB+k2 z({-r3#(~TogC&2ZEMz&~ z>SH2J9pZz&jU9;Obo$=?WzZ}ECWpu2UW|Et z90YkfQcY;Y07Uv!jR5a`S3OkT~k%H+M&#nXmXVtE!fqHLG3Ik9@C)5AH z>gnC;{(rX5vSd?uo7*V{@Ce=wZp(`HkETun9wecBkK?4^$q0N&2Im_|*AfGq3NJHx zn!hZj)AY;$?eUI9{2T*BoMSNn9Y-0(Y91ptdTl^^vc{${z{&Mrv)O{DRLttfF%d+! z=MtuO0mF!sm>?QZ-m%ggBfFr?+MkJwP68VwPv)OA84Xoi)`;BGoZlK@fYv_0BK2(f zPGW#v;La2%uyG-+K7c3lwG%SDe;QltE?+bHtL(joaJ*`nubr%M zd*-LIZbr}UAh7JsZXgjiH71hzX!vPaZXue5k-&nDHD=*}_y~c8;{emt8jovA85`$$%$y+s%^W^ z26o|YO>g)HkR^7(a{#r&nW)p+=V$d&t9s3oK^x-h!u4%nYx|ww znr~v+UA^~^hU#AJk39C%&#dTmeHW08>R|FTLmnC0`>OprS9Yaw8EdFAK(?|cF&hNl z;I~drBl;ruEqkJR-+mw9X(p&f1{2Kcok8SOlJm`s-nWy$3a9T5pvVc?jO^Vsb2wTeF{{G6=FT^PNOS0J481>KB}jsG3tI3(VNKs$cvoVZW07Phj^tt?2&`-_M@D TfiX(a00000NkvXXu0mjftQ1Sx literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_41.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_41.png new file mode 100644 index 0000000000000000000000000000000000000000..529f6cdd4554f19c211e1c06ee28370e31309452 GIT binary patch literal 1654 zcmV-+28sEJP)t^d=5qgAbU_ z)f@mY0071q;Ndt9u*TwZiZKQp$MJawKU?>r*KTC(id=DRBz@jJ`V8fGI;61x04EhD zIgnzE@e!aoTblqMzq|9PjU7QyX&=J#pM;a&=m-QYI(KzGwQt4FC=;yO2@qp&34a2B z3a3*1 z0H~14K$ux%YV;krbH{fEH(xVp4KH3LdWblL7kJt;E^{Xa=-%Oj!ONzafup341bL)VVi<`LPc)j&Hh{-8P#xI8+JGX+f_Z{7KHu6(``{S+O6z?tVy z0Pul#1VTn$6}onO#O@V`ONE|fhxP9<23(edwZbiGm^2|Nup+_G6$mKzF6Vpm&a#J> zM(8}LE|mc!V=7s}lEvxtj+&s;`Ib{Fm?I0Z29O46_bLlUONSN=72x$p*7=s>EvL`U z!&>tw{fnmnil|YmfxsPURnA>Oz-_5?zBae4-O+XS=%3nl3^F=HEweR(_dZ=*Z|AHA zLj~=7&X3Hc8=~WJE@OwN3P!)1H# zX>u$E_{h^zK$e=KLEurjhS_nuIp0eW5jiupmByMMSx{UAMh&uz(qNrdBI9>(eq{b3 z#|2o@s{Zk_+X<`yDqN+@=qW+dmvO!}m)Ut(&gZhIExeYguGw!1fJknW5M5x+@zV2I z=SPFio5#$Yc@T8swo?FI{0KB>db&^#l_S|=1pyz=ZOS5AS6M;G=eLSh2Jk9S4J!*R zu>q%7d``!C^j}5&QTy?;wGk=;;q0QAC!EjqOL>($kLOr!zhs~Fe0T7mxgv$nZ1iQF zUky&{Qe_=M1tVoqSqn(>z9I!shH5fKcL$7BU~$IK-nX99G2Xac@WlW;2xc6=>twmJ zwc}SL_j{0zdONNQwdu5~U_RIa&96J|egOaLTWO3nmOq!)uCijU0Jrh9jzU@vjSAld zk>-wef3?z|4T9`ZF#^d(kpUv-WbL}^?nm(59(6E(H-hZ$M>dtxRdpXgWq_IM8^CRq znnrgrSoiUp!t&9dQ$UsxehnRSn@y?G`%!qsEh5DLn&92(AK`V_C{`Lj(mQvsrX*jp ze~AHhhD7b&kuVEuO;%0^RrXrGDq(=#>HxaCt;LQOfe}c0ywd^wk)Cr|S-UKhFu+c1 zFx$APgj8roZSvToYmL*V05ov-<_~~QxgEN#UA-etx;WgKk=(!2M0c%CGKJq=b2%lN zi8%l5eSn?y-x*L^lIS0=)-mLb&VQN(&<23Hvw9~^iT?3w z<@~ofpW|u!`7!V*d&J)di0phyS5lyOJ@%&<=0qmVW^IgDQyDpnze~68Dg85gL*E7>o?cW-e?@Jg&Dk37z3;(m zqepbF=nXT#)6NHoMRv5ax2n6VmCR3J*0>6POff(ex`QcF4M$`|bZ9KFs%O^jtlqER z2l%CCPc{fD0zdoiOjAm-Go$yb6Zk96N6d7`vhurR-v#kc$5!I$0O}5cDr8#H6#?k} z$(Xn9eu|2kz>{4i>u&u^e=+1u=q@^+#ESlZ083e%Y!Y(6GXMYp07*qoM6N<$g6lCG AJOBUy literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_42.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_42.png new file mode 100644 index 0000000000000000000000000000000000000000..15168cd11124217a5092687483149426b63aebba GIT binary patch literal 1495 zcmV;|1t|K7P)xkkIPCPs3`dZ>^RC9n@{P#p%><)z0{AjGhYtt9 z#48*D)9cr(Bgewb$geU!mJ{G_U!!{@Ishg-;t1BUaMor;Ff;NoeTt~Abge{RJAO?E zz(gt?A+pI>=reF;#LskYx@X)T9<)ld;4ug-@T6yy=AAOY?1<-rq2JFqy>~6O$w3KJ zJA$;1d)70@RcC*fVOGRTdUztW8ePtVKB#sCN)NB2nF1dlt42Q7mFnx^k1@j$Xy*BF z0J`uDN665t!mNn*$US0kuF&J;(0*^N!J!#gD%`w+aSCyc<#C2tj?n3zWqeETZ1%8@ z5v(WXC1wCln98i6(W2?}jGADk@in7XWR5J@8h~3Q-K#7ZH6D^PRDjkWS>tPl*Nh(3 zL)&w2`e(ZU46jh5jzA6Rt(+?}0F|ZE_>yi}`MvvWrGG5j*3jxqYKhhematx06;4o* z_ATRkvcPPxhVQzx)|w;?cg9&vI`PrZc)JA8T8mDV@vRI;dCmfteIzH?;Q#jls^D=1 zZcSD36K$m`jW2Dwwr&>OPS7SxBSp5?@X<)m6rBBY6~@>2bH=Yc3M{!ehcLT<3ZcBw zfsr+2#1PeyACb7Iss=7_ZLDcm}!_@9pg=l z7+;ffhVdyc?e_{ya{z$zTAnB(#|PvK4fXQloK%?d}@tChHG^mlLt9tl)^YebKd*;L^V5?5{?r-T!ei;NHIq znAWaU!4bwYdepO^RsJ2-XTMZbYEDoAO6wy7NE0(lkk!&Z#@W%&8Q*dOjz$!mE*~{O z_DU671)dF`Rrzz1K4}a*3t|SyyfBI2F3xgw5mt?8$5xU7o`@N`MeC~({#J3@k;(ub z!mGgA4F9Tef;%O1>nMYLP z7%~2e=OYH!a$S)LuEfrz^+@E8w1QWH(}PRPPsfgp%1r)l z5j&Uu`;|NMxv}rlBIcX2z|N)rewEIAeEnfZ%1ZRBl=eDO_uK= zMRIm5Y&p@Lz-6dA$~hBn|1*e2K<1smN}H#>1j?r6NNZf_Y+1esH6%@cp7}tvGFO4q z$&0Eq9>pl%R}t6+(9ZS_>9|-GQn4D*iFQWTnOqe>qkMPzz}x4qQs7xwty8JS0id7t z8df)cM@5m!%}4O)oLk>9!h4kO(DwnJj0zpE+NTKL)Hi|vo)i5XxH$k9Q5Eejx873> z;?Iom4QBvJ=+ziPj#Yb)ZG#6pN{RyjbUOe5002ovPDHLkV1jaF)=B^X literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_43.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_43.png new file mode 100644 index 0000000000000000000000000000000000000000..16196a7062fb707b4adc7a2199a42d9709024ab5 GIT binary patch literal 1440 zcmV;R1z-A!P)7U9a@zky#-pYv!KVgZvz+5t*YFVhtb-(%y?K7`?KioPyUMwdCiB&ynu6BeyQr z^e>(QD6C3FID#g_S|eD-=D-WlNb3K}j#kAW~YV;#0$yx@WV`u1kUHaGWa`$Rbd>B-N9iks$P5+}( zzei?-Bith@*HwXi3EmgLdlGg}{oH9DOX1@=k9wkiR;KWtP-bQ{i&NIfLOhlNs7Lj= z8u$r8!tT*8;noTu0AIne>!L{MpWmNp8$J6+%LMqU0dh{@ElPHDgk0s1m>K;&>$Hyy zp!Lk760Vk7x8g425<5k=9>3#Z{KkSEFO8CT;*d{ZnX}L3{W>&(o`K5nSJsZ~;KFL_R>iI;QtDr;rNCnUM6A^z_1O zS5$!1%qw;RxlnIkU>D?ct<4DD=2%o9)Xw{H3g830N5h@*1{=Ki^_xLF^`An1WJ}v~ zG>%-i+Ib&ND6fP|1>zgX2dMj9e2S(Hl0M#fzyC_u z+nYTjQM*pLo`f_9=cH!dU!6eh6mSChHTHRvc4uc3G}oYssm^bR;5{;v)4zq2F}Px(Zqf3t-41= zzPISL+G~N7{@H9-N-2_HPb;Psa*{Eeu@qi%y$ha6KGm%iuaRJhf^viHQ@el+Wi2Bl z^hS>5`E2s7a~$2(v~2luf-<27eLvg*Bm;WK_2?cI`4RFn zw}O^!-2KZ_eMeifJIM$5Jy5xWd=A-lfOq{$Dc@ZH6_#PZ-Q-tfSNp4x&)H?cPX@>^ z0ATJBt`~Qc@3E7jhcC`n^ACi0;9ZPaj)IA`lCRl1oBUo~1)Tv@3~>N}d8GEhLVjzD z98Lal9G`zJn<7YefK{Wv0+TFd06g|iTd6aSs2iFugCf`=`YWvIe^%7W?cb%IBr&a|6#NMy(2Cee1xFhff?H-Ctu>KD+Azzq8*)q zzICIYjnq5a=_LG|1bQ>Uu8__4cdg+`(|WyHBmW7l z;G1z`Qn?dAiTo#R2NZ8|YF8If@nrJfhLcPG^~&w}QWx-tJ#k8B``Vt5uYcGZ%`O1o zJHkEh0CwvVR(vlo8Yh69{xPJ?Ae}wqetPvSg4+8g8~{)(kq@9($M~M)6kH*BCpddK zJH7DED=R=EdfAgeD%5)}unSr*fg%|JXA|rAj5Uku{pkYe0B>u!GoCO9FTQ>=h^GFx zknfEi4W8CGbKRnPFG?t_gj)sT6UYbX|4rPiH10*O-U|!iBAvt2P6DMlc;-esqgGbQ z3Z!1WC%s|m^PfOE#pQ)5%r(^5&>7)a!L!u}8D>7_1 z{n4m5I6@Se4s=HrYW~fjH;~`k?cBXaJ^KFxQ_;Jyc>n*600000NkvXXu0mjfVSBd? literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_45.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_45.png new file mode 100644 index 0000000000000000000000000000000000000000..5a2221cb9282fccb2758f6d5f0d0d854d864d06f GIT binary patch literal 1464 zcmV;p1xNacP){*AC&=UvF|wb8onNSMgr0X^)%cXZ89uFD*jrk`52vC5~V*2ygIu_c+ZfWq|64mx2MWN1WcemfPgu1hO5W zw@$i;nPXM$M;@voz9)wzQnP`49{fhOBXD|j9nTcBeB3qisjOUH%l;Gq*?NX%qr1&tO@r)Ts8mB!bMnvpr85PJY=QSVx2!#LVk^56{c{v&F9&G4Ghz4B-} zx2Avb6hL8RYSs~?XtvVKasylsuFj-(cEk6?Y)+9X=mYBZ`M zf7JAzdBPD5kFvDZT8|m2#*H>X;@-7cwJ(xVvy5-aaN6}ONZF_71RMN(A0P`OM;Jv0 zhd0u_4wY&Ap3=2-RWLh2E9OQrh(!sJ#&PEPEaPkYN^)nGf)QVm4Th(HOr|_hKkJuT z8m@}`h|^hQus-9_8_M-H2+|15bmms(vQs2AB&B~x<5PJwx*jJudW$2eX}0cF)kkX3 zD;U4WpR|{BU0QFkm&B(!3XZ_q2}{pawj&WIpwISroi#qC$890Kj~buyNclH^AtZvc zI^GDZ#^=a3KBXI3Hygku4&YVDS&l-DYc>9;L}oOrD`}LS0HHhou4Xq#BR1Rwpzm$361NU?3>-vvP2RVh;X=l562Mu$Jy zGy#5k0L=;RYFH0=CXlc)`m2l&AY=gQ1k!sAtD_}~D@A{FAY_3g%U2H&ef8oh&SK&J z?C8%P&ui#rfJ)pmy!YQoDDp)j!dBARXgB__Ny}hm0|UiZ`HoXjPX}1Z3ex8 z*Q&Cx3cHlnJ(2%}qael8x&E9K03cX8~_F{+qJEE~S5bm1;h}PoMe2 z{jf{vA78ak2cH=EZ^ZBv0Pub0e^ZKlI(C45`lsk+1}zh;8nQ%z{64j}k#GRWT|a;x z`Pyd!d_Hh>g-ZPP)>z<`H7iIW`-+o5PSiRcMxq*xD?u7$aXuqT^~jo~m*~DwMtO#_xTmQCasj zK0KJ+_tOL-1HIZ#@do4fu4#1mNlDX9Z@TKm?7lm{;W_8u-S~(n$PmQ=VE&()8M4N+TM1RJwNqG0000IQ``mB5SS(jt!;Kl*~oLCqa zK#bPfj{qsyk^^-7>cPi0&Pakv`#P-naX9IX8Hpfe=c>WS_Kn!-Wr9&V0elS3;UfXC z@QOsh^7{4Z%CRuB@~eW6?F9ILUZZm)CIA*Zk_gtaaMxr-FthTpe2S>AbgU#_TYk+1 zz(Oh$Au`F>=sR#{#m`J`I%nJ*UbIWJ;0XwA@T6x{=1L4OyW+WG==U>8?;T5Ha!~=* zi6D*Ro^|GUYVGef%&K_F4^O35quY7W2i1u{<>7IZDe&^KYvp5KslOim7&8)qGS5c> z(1CX(LPlN{W>vh$?va3VjUH!*_Iqm$E-k=P@EPqYt(2W&_H@S=Sl{kwp0dR@-1t>cb+Z!$F>~}jm}U@v`4Uv^~$P9f(qKV zg70C0*??k1&)2BBsk#T_W`QlNd#_8 zRr3?wN>v75nsja4EVz@PO}0j=Y;WMBm7Zxh`{ycxuj%K4U%3=mc5w+|?gA=|@>T~% zHjt4(R9Ak~=ITBm!Y@TKIn4 z475V@H}9tDpm!HS*=KDHy11k?}C&e_4|?8qho7Z3LrLMoJLnB5)YNs9zu zvvWr9sV?sK%A%c?008%Gd7_8}-&!K?_OF_;rzAjj3pN`#z*-XE@lV)!9QN1msxWOE zxN7xNcW|2*NRqSKiB+q=gKO}(wRJV>uL4b)%hUKo_oKU1zZXyX6Fmv_%Idg0 z4Um^=b_+UP@2%?Iz4|$vQUe4KYeu5mzUbIWaJ27P`=0>b`&Y{Z_}2qyN$}LU_MOl= z|BffCf946}2LnhaW|kp4)8b0i?=7T}lR%7*9w2+|M(vgeo@3R!tN%_m6&WD&!X$!K zlBKfCj$oFq=#H&~0p5rizD1VQQFz}Qq!_>>co$efsHXoB*7SmtFWEoD0Ds8gjwGP^ zB$P0~u55s-`|gD9I%n&)WPd#ata7^dl>TcZ_^V7_7TE6HeaYhFXgyN-cdutv;QYY8 zd`lvnIH=qSpcMQ!E(ZYnCUh3;yMS*E{x{;3-ik?UK6mWC7C1Tj?^o^Z;9upx z1LiIO;B(LaO%?KXoB%TYV@S;K#{_%h0^qxT0KM`(?*w++QfY4nBa9dIw~9?OdfAge zDm3~^m>m7%3Lm)h5qxy6=^UBIQN2Uo2Y3@^`1RC0 zMf9e=5d`p_>bIb=V8wQq8}Dfb@n=T#h8aLI`t2Aw8H~Vt2vrq>5Cc>y-W}G-X+%!s zzGY8T@2``Q@us?Lh~qc~klHJdNo852H=*#G2b|#Q*>R07*qoM6N<$g1T?i AOaK4? literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_47.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_47.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d5407ad0f5f04dc351b8d5fb995f2c99094d34 GIT binary patch literal 1369 zcmV-f1*ZCmP)ele$>*&Qi*EQrxQ7jLaRM!T7CwJ#s!_d;s{-G4=Upu7DVT>P&;g z2wGT}&G?l3BaNRK3Ph@B-d`91qn8md8?*v=UhhQq%4b(!^1LklVMkCI0OJWpu#TIF zQHh@?3AE~uyUxNsC$&N)co~5^hx=@W+=cdWF5v+;?;d?nw)=*FQH~%biqzOoJHcq$ zw*V*5Scg%4;DuRAx#j@bj$p|TFwH+1`?FWPSD#oO>T{M}j^lt2chVE9+IAXsS!4QL zv47NxA0>Bo)$p;bUeDkfRZ)&*afVR}t^Lkq{JWS>WB@D(j?>lw>a`eBUzkqs$O%Ro z-y^d({Pv)fB0B&lPNP%Rc<$U&z&0Zt!0WA1N5F>Ess*on7HHK+ zkMT3)%*g(!zA8SH0X)>w6B?+#v^G@RC^Be&r19^-2S7H6W{7rGdmTYCxV1{Kw3Wus zG(JW7yu8GZ`O`;W0kIwQ9+T`J>}}3rV)2N#Lv-B2nXG^dx-T9zr(MkOTu5V8+!?jiot( zMEx1r{tQqb3XNjc)sLYu0B*M%&g@A=V&R>Nr4qdQ*}Cbp%jyS!|Mvm3n$%ibw&!+G zPQ{MYU-7XdK-L6hHKnxjO0j=u8~{)(F;Igy@$zw$gOkPM)`0s!e0D<*%MysOQ}3zh+*+oo2`;w+ZZZ`aii zKvV%yM%WE2=QJLK7yw`&1?`&GSkaXOyg@-b(?38G1FXsht#NlXu!im`V09da{x$cV z@rf|NE<0nmgvH0+fRmziPuAa43O)&H9&fxKa8k5xG5)Tl;HnNCg)0ZB*wy%N#7WVA zeWhYPKHpxm3*N*6Cq@7DRk}O)xAOOZS_J@HYyLN_klk?t@bupza*Oy6^Wy_RXZ-;3 z%D3DTSgoY8+!@>rNle(br#8sidneMh6dP!eHs(CzhMo$hgx(#I{2)r{mg^<`d&YG?6Q~XT z7EpOofhG^e_aE zfU_x|qL(pnJm|eBA_j1B3$>VD*Y#e6(s}nDk9|ic$pErK zWekBc0582-^z!&j-p;NyLg!Dq0p%FTRqqi*1d(`*Oamj7pULl;b$Del`v4rF)`lSE zC_KM+P0&;MBa|+|;$77UYGDYH0Z2Sr8v#u}S>=0*+`GZ1UtkO%Dsa{iBxQTNsC6Xh zq5N4CPw`>&xCqQtp*5+2n;)&3YmA{q*k4Wg1s}&iNpaHAMjDHWN9S+?M&^z*0!;?) z{;UWUfnG!m!OHa-S`=2TmA{JOG0Z+dH3OqL67d>OWa()P5|34t4*>ojgR+n|&#U;T zr(2CC{Qb$EUl4jDD4Lh?ylAmkn@{Qd9tGd($_G$VK&GMx@EMRt`Lmz%cThfnqY+dK z>C7(*)L~<@MnKnq>2dd0g!x8L4Q5b&kpn9&qI^!qLT3kbGk{r?kLB?i0iDOu+67%B zz|474GXgvYBU=~Ej4lQcRr)AH!5)sUp76h0=r1^XEof%%2l#xSo*D&yzB^u?!iU=o z?e~KSMjHwj>MiW*{Qy621zQDBH22N!{RK4N@2qGEFD(Z~6u;`Gap9kPzAH|x3I^~i zmKIgsId>S2*65MsS=GQToZ3-{`@SQd>iqyh1hB3EAYNC)s&co27y&Xp^HqvJj3*xb zFj5hKUNajvyRpnJUn`^{0Kh)^@d--SP*nr$uz9-}au#eKz#9Rgzxd4vs|#AtvnSHZ z2s3>DbONK1U}bn}n9Qc$(F@7)O+^6OB3{`Tc349VP8!zB)$94*5IQ4@_m?%aSV!dd zla`S*%QqYWD3Mjufz(W@aOhyxeorv7AQZ7m-DCI4&x2X@nd1qBk(Xj1gou zSZc~TkMg(($(@Q?$)Xv8CnC{WLQ_5fDFSJA zZ{>E&^H&4s;RW;z?mY!rdD&Z3Y9|kAoTdEZIDY?bptrE&h^?-CT5wt8%4dAdLgGmc zuH5tRlL|#{%t1- zPE{lJQHlTnq!ak`G{8Yi4Vq_3`^wShiZl!KNScxJx=1JRt8^JrC1v+fJG#+vUY%(D z4fel|#gkf8{W}_v7SgqT0d45CIDv5EE&lHmpb_2i$TtGnee(7s${4DX3}4s367~e; fXVw>K^2~~V)y8fTxI6PC00000NkvXXu0mjf>V3UQ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_49.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_49.png new file mode 100644 index 0000000000000000000000000000000000000000..0e6845ac244980c1d2fcea4abc84ef0b33b215d9 GIT binary patch literal 1851 zcmV-B2gLY^P)Wqssi>-iO&uk9PLGs^@Sv~@?<@>&HLz*6iA zaTp;g3s-YKv;U|vFv79)u=|0136&9|_exhTtin4)#qUy@Q6T zfXKj1f54dItlGaaP%7S48hFVkiBUXOjTlNA8HM)d>& z3xKS=QLM`Np1R$;){2~uawE<$kah1BR1C3n99agAaQ+bip6wyFZHvDHFhR2e!KzVu z{_37!rSq@Q4_G>fJ_OAO1Sv2$dM=uGitu2w;BMmj^URJ01@t7D*#67XA}rk=QCMW zZ&GoFHy-D{In3y1diAFNB4`Gz4EJihCyOnTZIpgC;{4U9FyJg4$^as@e+Bg5Q8bS6 zGR+HuYSUMtbnjGxvhd!T-=p`?9)O{8eCcTtEgfE2V6rl$skf<%0xr{Y^y+m#1sK*(+|+TNqvo8#Ha?5Wm$Pw&&)1g6|FFf-3;WGn+M-5H&1ezw10wq)#> zUBf-bnuQkwcn#33ZvtnWkF#}kr1s;u%6?_aqc^ulr`Eguz3&%<0xeWGaVA*l5y_oO zScAr7SFaV@(XQ+Xh5>DOM8;)}ZAUC-#F@?);b-fn51&O&*7LONmCoPy{lmf0$%U2npl49PsVHhi}8QLbfQMYd-XWq`~g*cA<4?bKc{o4v8tx>h(pJ1?St zE0OVPGC<{ODbC`kKtZa+l4a3s=zFH4x3{wN_mqiY2Cy2TZ$q|MV3f-;9e-Dx&z@I;1@XZEdLb3#MvS-v zbf1t31lA+tWz{Zl*-JayCFoQL}jn^pk0H}1t z;dc!d3H<9%=55s0K1~zV*z?OzqH2tZ^!UE8+(4FIbQSedVd z-JJm<7DFdk*%l!i2woCKO{3NoCG%Sk;B}c%=HHnC+NSH0W{nfcQG7#`7*?~$7(w5A zKGL$h9zxspv@$u5KO&qh$ay}dP#0Og7w+8`()t!6K zEky65+OEe`_B!i)5qbZE5H!T9`QPe%1Y1A5pRs<6X&3{raavB+`6BY(1Y(VkXzE)U zL4>tw>_m{s#>#t3UUc$c?;_{FP66$QS7-j?^Hij-z3`5oUiTi^iDRus@qrV*oz|;} zGT(DxyN(1&blS+u(9nKPeF^-gqhAla%#X^XNZk3a1oM^lZ`WT0vEX1hYtg-E_D0`B z*cD-&=d1S2fOo{7^8W%D#o&4R%0PSZdAqkxMUiYh-+PakwRcu8G0Xt0*!m_Q8@F^-4GnaX14o pfU4j-JHMgo#B2{xWq>n!fIogQ{T#2oX!rmC002ovPDHLkV1iOkj#vNy literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_5.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_5.png new file mode 100644 index 0000000000000000000000000000000000000000..45decf285fb34e41768e7304fa41765308dbe80e GIT binary patch literal 1625 zcmV-f2B!ImP)?A%j88?oM5O-)g zJ&33g5w+InI1Xy9(JVTh<2a^i-B^pq*$mt`7he?~uVE$a8#VaqVS0tK?i6r++$rG0 zaT~yg<7h1Q&vpV;orFerS6ca$`sJYiZ6ML_p=X3#LBpcC!w6QK;i`Bt03zA)EkQ)r zXAw05&KJrP-{;-&Ck2R$24QeP?hq31R6HZ#yrLfcY04)`6oIX^?ZS~1>M6-GT5pd} zQ9cpTmvj>q*l`@<+7$vE_v=RJMS?r*`*=zLqri|HstIeyaLGyskreRB$|o8OV1?4S zP$QvOqbIE$jX+Be8RfrX7ZBCo(OPRrKFu-{$;F=1BxACS0NHDYlD$Y-xepS>pXBHn zz)WbgJaS~nVpjT$ukj)QHwrZD?~DLvr5~{f)R0jM|7^UE9@CTn0ZWfDd-Y5US;F9u>G}S?e@U+*zGVm{r=y z_sX$(#`C3T#NP$X7CT;7!5QP9BZBe@(iIWl46KeKVi7pg_F4BUCx>3!c*XEbbiK6j zV*nK`j#QOvs2siWbTb-Mc8?W>;?^%@twasbhrps+{l96u%WbdImaF;Ro=% zs$wX@g^)40jPkoIxJ?rso{7C`QkOpm`kglKtUbyv?stut$Naxc!A}h6U zd1jT*dCNfkT|lOwlZq>emiM0TWA*A*%PJug^0mD+dXf{3Ya<;C!h^IAia!Qm6?D=@ zR#=nZRmGZOkwOje?26Q*!82N|jYeTb*L0`V+V3}l#!W_|Gewf+p`I6bbkH?bKvMup zW4z~KRcbxHY3tvqpA|6LVj+X1DxPNG)jrm99a39uVP#$Q^tEur2u6ld8x{?6&P2wj zr2-LA?CPRgjR0tzvAFVxq z9{|OwG+_yl@2??po=n*Gi~^-8{Twld3i+3G0V|E6IzMW8SfcOcd~~0cn3j8w0JBEG zQJprt2oVLU{PF!6d`kPz@-TlU zxhw)iB1A?BQDtW%z!;)id!Fn`${EjvdVb{jl~+%$ODBP|9-5^u?Kj?&jAe#@ZGZ3i z-SQScZ{N~ruYT<>{$Bg+Y<_pi!+SxKz*j*7A`PG;wj@f) zbvwow=NMz0=Q$!A$1%LQ*L{ogJjZbyKWnbvy|L_dH@bFZuGiTxeJgCp$Q)ygWBdt# z3p)ZKW8k+rAF(SKm<}APq7ncPw$VuGd7eL;P+1>2S&e^#^R0a|c4nC%gKOW>wY=8> z44@RdLL5ej%EGrfpV@y`8JJ~&P6>Ep0CoT~jDT!l4cL(>E3h;3t$f7nUNdW7>i=d16lW8LB$ZI zJD6an^FQr)#7ofICa}|m&XfkW-s}EXmxUFy|F1d!!pmcza-4d!QFE>E&Kl+Ls2ROG z2$=oKu5U)E3CyAr2>9ry4y?)uS^Uq=zYx9$m{u@Z7Eso%vhYdgcg~2Rqj!4%T#7pI z>T9Jec#oPZGC$kMGOTK5yLz89FEJ3SV~K4_l?@!9Y4Ezv{}-|BZvhvgI_}NS=&Ux1 zpKyLQ8+Sa)R`o7#0vRwn?KrF96`2?4OO8ZYSW)wp-f94>dJO-%02qTicP0Sr8jC0p zs?KM!RBuvohBqJAzBo+uGhMymSHf0eN4-3b?yKMx zP=>OoR%@d1ihet$Xdl<1y$aQ5aV6KQ`D|=P@6$Vk3*Ag)MtXGS1qIIc=FP5QGBSs| zqlRN?SpDeu%rro=n^Nm9op|4yZ|7L2Ms{K#;6Zw|KZ{H zMd)>~_Qx8#0+&5_7%a;p8TPYhXXI35Hguf2W^83(K~Z4^ocD+XWd&R3*s;ifE|{)L zAXxj53D`Uv1YQG~xpsg-7(KbLJ+b-Es_{`qdzrtoc4biQ6TI=xIVnbn^j7wj@r`HO zTMsb1Nwu+EO$^&C>Q#Y|2@qClR-KD?4#;TNRrLm}kILBAVt`1ocZhcb%K|n~7K;Au zy=)M$HI=~k0>>*!4BHt14aXYUJp{JCgAU`cI*;~bGk%uwR4}lTVr{`-r`O;2`x&31 zI5zIdTgeoatj?4%>tyBNRgU+-l8><)OUPvmz~CLy-6bH(#;QGbe&m4N@ciH)`8?}92nEO0#;9@AMF zcRC*Js3zAm19+5jL3OAZV^=jzs*Y#%SW0K>K9ThvDt5dvz!Ts4=;@gf*EYvI{g z!M8h~A^S9!dJkX`WxiK0)dAWyYCId^$|jGgJanD!)!p4dUwG#fz6rE~tO9g~Rm6U0 z24?4}IT`0$be}*X=U3TfXAmeRy!5`E-x&N$p?eA$nWNN|EDEQ3e;7;v}-H#-Z@4sXqFWD>_~k{{?8 zRVy+;2C)|ql>lK)>ufL3K{jY2=O4%Mw**u(RT-5n7uG=R8@xbK&Q^NxiUDDN zGEht~gNh8#p>_^CYc}VB3sl{$AYuZ0kM#|9PUL)5GNRzKws~~v!3!LZN!b~D43uFg z&u3l_6@DK8H^T&G;4zD$XQX+xv5NDfvX((rp52?;1J3iDUTHkpTzf99Zv=V4fr^k~ zSu`qowsY8+Dkm9x6*?@S#uam+9t?tvOpA!IaX%#n=mrJSICB^pr6^ia7^`!YGN9mP zY;?HlJ}ZArr~S+lf;ls?MFrn919(AzG>$Z1Jv4jI%IO3_23dQf%)>H;Yng0TUb;50 zwQmf7gDaem2Z#Z|=r7uUr>nA$46rPzb5tT+9^jkk#hw{SE^t z`KZHVfK2d3Nf6cb%zn}gpp1()X@Ad98yb;0L|mf|cU2D%>Bs#?`|}t?owFA-iec40 z)V`+wpTG(&+WV0+)Zuv!QR}=z&f1BYnoW)j1E~8|#`5-|_Vo)f1j$ux%XXCj0000< KMNUMnLSTZ-kN8Re literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_51.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_51.png new file mode 100644 index 0000000000000000000000000000000000000000..38184aa75e307e689cff898bae3a09765ef43093 GIT binary patch literal 2258 zcmV;@2rc)CP)yrx@}qw{e!5KH$c($X zwqqT@0LpNxBw>WAE&R3QGylKU26h=>r3HL206TykMnE=*4%|^GC*;n`kNQz|V|Dia z=>OL>o?Ycx6-LFl7N2zvxw3m&zDf5EvvpXwtNV$GaSgdZz;(=?1BP$PH!2=!I^M_k zj&$?*w*3MNT?Lhc&V0a_eLDl7yw*-yK+~>uk`KJSUY+?+RaEl2D0hBBOOPSjc>MrZzTU40C#7I>$>Xi z0hprGKu|p@?!S8`xHI{GVIEL6x4sBE0R#mAW#cpmu>Gti-%0#8hgl}H{SE?vuA{3! zP|2~;Zg>SOqy1Hc$O zxjO)ed!kf8=q8`(QnN`X8QFT=`y*juo>{e9{z}+MxuaiR*Y%NL1}r?lmE_+oD+RDC zUuA$X@{df4T04hQRf9Vl;J&%H8j@W~&pwr)F8o>TU$Ohu86X;7*|)m4+ZL3LyN0?7 zaL&xJYB&8V_=G4&8LHKu>VC(5yyqS;`m3b-Sv=F*nL~E$KC?q$#+8HBzPUc5vkVlt zK3liDhv{$*_jC_;3Sn2C&H%IYbgrEkV>}pd_Q{3C#MXZ>03w(nI+LvOPxdZHxSvqMzR z?iK_>^a9de10nV4yc%@mZWSb-5;LodZT7&ofX5T>0iEpH;f+=iILV`(RYpWdKG|Y|U>8JCJ$ZZ4byK6$m<& zAN49W$QYTiA7y|p2$XU)6J+o25;Z$8;AT29e;E+s&n!8svz4;H(kA2#&~XwK#%l~Z zOF-t}j;Q3L?#fQ2U>68;J*#wl-${OCg!pp7g7Rj76(`X#d`$z{HIp4Cag*-~##8}; zwHG((7&qnv{h4-DQDyC6?xnvG)JeWVB|6uoD|Hy^{j|68%=M=Ng1Wa#`>Ox5_e@a# zj3df}Dd;4hF#v)9opHpSDeyiX3|8W4O1Obyp}vr__3dSQN$_Oiw5Iof$+4t8_N^ zWHW+O*(i=qJX`h*&*OoK&Wtf7Sz@LUHn5<>_+m4Jy1L1aS65iVS={QL(pmY@DZuDk z<^wB+2Qz|6aulNCDlsw9?4>|d%>-^d4iMsgOn$~DyG+wfKKje%G3DRK_W)TRTj~9{ zKHjgurI?h)V z27;<8vv#F`&f17W`>O++Vj~5{6&om+t7-Qc-!S9M5p}3hs^q#3GX{u0s9w#k(RP){ zPD{&ZUB!{Lq!S6pSeWhWy1c&|7&lIZE@+|?uC40ulwX;ixsLf#&o2RXNps5Sc=?lISz8bA42^NEP?WpqJ^3eou+MKinjuutTfb zLMN%+%5{^^{8Q{S6N2r9#ZnECDsDE5tO7yp%i{g`eSnT(1%hm_spz(96>49W@XY_X zo=J?O0us}Y`?Gl1ImTCJhs`3&=8qX*HTg_gb;aPEzRK1`LFRJW2h-63rPDSMT#i4g zl_NE#VAf&RHAJDm;qJ?j?Uq*Ltw)XzEDT(b1}#) zxy)atyVI7YzIg4Nk6IV)M*F*hcB4N_|4yJwYiNue!b~6oBJOeRu=mk#1j5b?po(XO g0lK~1l`O9R0h`z=xZ>{7K>z>%07*qoM6N<$f}HGIiU0rr literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_52.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_52.png new file mode 100644 index 0000000000000000000000000000000000000000..1259a591a4b81d5bf1d12cf1d6dc739f94e88a16 GIT binary patch literal 1615 zcmV-V2C(^wP)Pyk5SjJbkEZHyl<6x@C(^aBKXh7pNQ($GXCrJ`d|=h^m*T6 znLP*4#&V0UB16D!{C9X+JTFIq=vk^SIoqBCNFB1AK=a&ahdor8r_vfz59}E z6zXQs6w0$rem(`$4tNP)rn5+$OuNVs*0tyofhQA9B3(JZZTN{6GCt9ADD8h6q^uc% zmCQxw`Q8)}8Dh~syAHqwAmh~;Q@!paGm_wXK*n;b-H1b>{n;6P01hB^qO(I4*(;!p zxfx{j77e0w5;#ByusYT4p&4{JNf+&R_JuoSC&Px`2-1XiWcgKeObxTfub?s=?m+65 zFwel>9->Lja!%SU76cFuO|G*{=%w zS&LRyo2Ms%W7v^jof>5*`djF^0`wU^z8JC!+Wx>wc~><4(Hlg|9e|JZE600DCR%>> z>Ayi80y+((ZMaCALMvo><;OVZt)nyKa(p^du?fqM% zN509!hXzSLa()%#PjH=|fydFE@HSJV^#Q3Kch;*JpW;kMcxcodLF56Zu{=kJFhOM# z26@5dFXQ8lpzJ0?1RmX6?N=gSs$;c(C1hFcK`TWve<_MH#_$+HTQSV+B1W0zO2`f) z&!`f;sI`_PHAvoT?RWD{Bm~}C`IVWVlGE(dK+h30!_!?oXj@Ly?*QDNpdWc&&M^=NLS~y(4df_k|C0TKyGFAO+XAFwC9+>V+msLM=&S4E_+Vh_QaVc1vhezm8qiL%h%V|9Nmm(J_pJjsT zupqJOk&ACr-h*DC5l_8Vilm4TDFUtX^PC^O$fn2H_ego`9AO>~%}FFytt4^?G(EaM z5#u!~jr;uXXac7tVv)qJQm+$M4kQhE^L*CT^c%@3Ed77119*+0K#gxjuGbE&S7i*8 z8KO*pB)ggD=eEk|VcWUWoZwa*&^pm+fhjFh<{<4FCc{&z4cIMMWtajbq*3~=M`;0M3;D`$ZP=Id;cox1P;Nkcxz{Bw><$ncG z%KRK)cJ=YJ9LMADQA(+m;Pm)U_nn~xtIoL!2!9XS2Uvlq5^xJf>E`=90radIf8PqQ z0+kq43AhEL7X3uwS9nUWGzpXh>IsP-D6+@XgkMUz30&guc^t>mn3z?9=-N*deubq3 z=XG80n>*wI5|Pqa{@Pme$-=MDl;9%=$hg>uE2jH+V`(($Q1+e5~pLGS*{RBRXE1t9b&h6wzuTbDmLH)_}XN z>k?zbfY=#X(-NvDdX7 zu0I2bmdJXoXQ6v(-l{i{^J!yVbb!`m(F8rJ*^((6IX(1Vq^~j3n|QsCte0)!{YxXt zv+mv8oTiMF&WIw60@A&li8I2OojPMEq*ga-Rg^cqXxR;~YB7{a(!ssw6|0oQ3q#yP zc**04b4WQsCfk?R%HsBwFt5}?N-+zOk|he%x@a=X6WiIHztzGoMd<^G1HqgCMMfFC zGBDZ@in!#SO!tH@HReXpQ3|O7Bt}Z;Mbs!4J3^>l$cr{(BDvN`;g|AH0iv!jN>tXx zM(0I@k1D*iKUWNtZ$0?jOEGRA1|e9P{AnRTqGLwaE@G*u+pqJH2Au`CvMWj}7$I^t zq;4dqMH^!wVu{`wS`Q*?WUYMm6yf8yfis9|f!6KowXOuDLnkF}nb6mp&s{u#WN{g- zmMj&WOZS#&;`DiA=-8g_Ut2elE1~0iz*T^imLC;-9XGqV5jmYS63#H;($+>LpmuN8|WQgZ^dEi2Ke!%AU2ocZF5=)AMO(U0GF~ zp71TpZ}9}&>g#*W(szaCk&u4H4*2i@?*~Sr*Xju@&EJJF2t2E{yZ~Qk70yaPB<4pv zfp+B$lie-df)w*B5aU>R_VTXp4e~7rT zTC;P)o-BOIlik<9c>s<`*1lttV>J*VWjsI@Vs2KGz^BFX9Xyo8-;t1HspbGkd-$hf zwK8j6Lv36uv;_Y+gnuK5PVxvs7&t<+vx3Wnsa^`N?d=(yG#>$K)VDG)LbwJr?zI4E ztw!j{?32yhrTfu_nzw(bS;un#lyHvBT&`Rev8}X3=<2nGwyxy*Gu_qb9O?Sb0XRXC z16hoT5JT5M??)8`t!P@6WLAFBssyLTOk`s^um06%8R94nRy>qIY3EnYEbm;>Ika^t z-SpZM-g&xs0IejkVviSVTZ!}5qxZDu{JzI%i3c9E{p#xsdI&e<0XWh1uUfif@s&`G zS(XJwJOYB2`SlD^C`7KB2jhG|=%D-0xVn7+i&)QMQJ|h6>H#EyN(|S8<(gJ$F4o&nsm`WPkxlcCz-oxVCjc+#yM~ zQc5j1E{n(61l%|md#$$vxH7hKhk#4t4gnX(tpFFtvK(OBwo+>?+qNxPU*c-H%q;#c z$pM-$j#7etzbjxSf0reJQ6i-Uvxk!VTmk)ANBO(e1zc;3vqVY@W-a=P!f%KufyLh? zNg&$L6OueoWRI%}zm)PK@Dctls{*o05MBFFrozgGwTqy@L$0yfyQ4o z31qX&Nb-hamPRyMhY1lgmEwr1VkVz6{Dlf2wF-e1T7<~Ryb&B-E{=x1Sw;r;FG2xE znClT{RR`J?jUT0lU1O!9NTJN~Tv~OYUALdT*T&L}yJCc&5zs0HU$tijtP+&cd4Nbq z=_QFsXfZ3?6$#&LtNzqP)Z^b%5z4Oz$aIvV-6u&vKSr)~RJOmu&Cdui5k51tsQj(9 z))C8};Zil%Zwdd5zJJ!koe3+nZrfJ&b`!->hnp35GfJL8zfYt|GqTSJ_9?3@M8*T4 z1{BjnVBSaZl5i!$t9Jfbm5iwXUgmwKi}UtIz3+%3%mB)%Se_ll+ou9prJ6S8TiUUj zBCJfpMudMPcD7lfc9Irb(#%@_+5GrbT(d(qn0cf586#T_7y>e_M{itoY!ngKDwSX+ zP1%0Rto@^KlfaotlguAR51egCNhOf;N9f6}gXlj(A>I@~GH(?zGuC51dx(UCe$B|a zN6ToGTOEZL1z6>xN0f-2n-xM+f_9G#fXS1NcKfqr^;Cf9f{}xa5NKKCtPh8*IvpuR zKYq5`x9E_2TVM_6trN%|=IDe)YmCfL2rFEmQZ8$KBW^#+Z+85?%I(iaHsOn`kCebu zIF^5(%4f3?gb?}U5Y5x>t$C8hqdpx(`&f#oC6e0u2+^~RD$^cagpEPkJnbG~l%bgq zVc1x#jqMvua&P9$(PVP8N>e+5{YJgTYgcc+c8|t4Wa7THo(63nPvMX)N|Ed6nx#?-BF*XDj1>6w=-I z&$E4jqp`E@ow@J9-g_Omvl+xdDsOuh%|Fh-gNgB_V9Ouz1k%b;^7QGx6TMdh zI`Md4O!mXO$@5 zD)a^v=Mk?^MPQwMX61n7*Z$t4!jD|FgL{Yn7HHuNg)}Q6L`tFYO^(yn@^Z1~_)`9U z8^~I^2W0X8gTN&;UTL0>@d^xBqhj7adX2LzIC^axd~(7rv8H;C2m<+sFIb*+-^n3exdq#2v@9FVCc2V zL+i}hegGQ#k|dUb|3{EVNTjL35T&#Nps|vl?fJ|10W9I8 z8WJ6>t%FMwX;`VwB^noY(sHM~`GYwNQWn4F_s5g&T``ZE0?g^lhbRwUhwcOVZI zBO(loh7+xpX2B=|GCua&{?3%_y+Q0~uvPk5u3vf(R!A1ub)rnr&LGc>-uJXI^vk)~ zFq91)7SG?l50G`05z8O-08!=g6afhy37d_>Xs@V3jw-#S1U;xv1ABrzqS3wPj#qnt z2&2(6FYK_MqCX2m%gig{WlszJji3kv864pOEczuQkn&35%d2EEiqqD)XA9d>0;#m^ zIsKhLOE^6;%3y&xRD|wr!#@d^!jtPT?=59P`y3^FdH%M4t=0cVkR-fcsDG9rMhaPb zHfs6EN+Wbf>1XF3C47s&t_MKK2w!uLmZnMtWZj&6-n3mRL`IodPr%GSOZYGE3TOo* z0ZE4TjLgEbEOyKd49oMB@*57TG)Vv{_*q~DJA2=&z!N_00lYB& literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_8.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_8.png new file mode 100644 index 0000000000000000000000000000000000000000..3621243f71f10b63c819eca3ae8474717db41550 GIT binary patch literal 1612 zcmV-S2DABzP)c?O7i*cfGg~qE&{Vk${ma@O3rf!@U?EU@0qaf5RNJ-cQCr6@96x2Ob~R~ zH&p~`6Gl#w3(CxKH|G=4lf!q|H{AtPgCHyWj?N#b1OX~{j34hyZD1w{_-EcCzRrIJ z8U(ZUHH*MZaiQfbOKD9`)+?f1Ri{~bGl5dw`4Oz{0JX0fjF~ntQc#;TtDHw+-k1m- z0glYU$9C5;Xb|wZ!vd063WywG!Rtpg=Uq|ob<_VaDj(V^ZZtB8}+?l|UXB65PK8NRg zEf8mz@d~DR5WU}*FK5$>SA59>8!2C&pn1+Z~%1XAjEK4IUMLorS=3b>JF^=yx%*qqzJSo z(jF_$FhNJ#wBmSm=Gn(g4N}3jB2eyl>GZ1eqqZwTHccRUAsvG?-@CQYS^Ne7y5l1z zu=1$3<11KoScM!8S@ZE?bjRspCl31mm9VT+GjxsSJ^e&?^+B6mAq(+9mr`x$2j<43!PNN2g3R&@tl2B*uLDo*!`h72|Iqnb)NTolhKiV{2VToLy0mJ~BB33_s7w22FuhmKN zJtB+W6S2$GT8PyE5-1&+!V`xgp91a>X%{UBv;dHsO1oxtTb@sldX3{ePoDwgf>C6O z9y$I~f`RKSZNzPuEy|>f=(@%R85{n7Eu6o0IbTa3T92GbGk+D)TC;To3Y7tdzz*kI za%91&MQ=6r?0`k-{5nw_&{1lzWLT`@&85|JFXsT-Kz@U^NN=H)J~isAuSQe^TF9Ok zSoff^kvU(!6pB>-Xlvs+4e36#Jo*lSpg9`Jzj6&)*I?bF%_aS&=@GF)_{X8hZuBZx z3);Cu6a?B_SD`Y$)h&2MINC8-4v&2D5&%f<=mKg8%^=x8SiOb{vTN7w9q;+)TsQ4= zj;8>Kb}mZ&C^8HXMK(gcD`4e)G$>?XTd&@|)$2s83#dY?9}sz&=&vxsN~ddUk;oK- z7OYxm#%FSF^;rNyL6%Tdv1q4fgCTPK?wY}x4`tb?AnsZZ{Cxng^+6UUf$Z!|5OBFy z7l;-t$7R#tc<N6V% z6}qn&57lF=Ba3X>=?L;6-*U9I_H+%v6_yLI7K0i{8`H%A2&%eDc=KuUx|mLrFa4zH z$L~oq0P1`%7_@vgYlJ9hH3M|l3aisv2gAvAA4L9t8YOd0lzYaQXeU)t1`02D$94JH zCqWDLD%$?F@F$_5LJOvL^;kXME}%>Y$)bP(J{1xDe>$@Dj)i~MKbMr*&bD^|0000< KMNUMnLSTYT=Jyc* literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_9.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_9.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3d537162cb4c59a4c379e0493749eabde8edad GIT binary patch literal 1575 zcmV+?2H5$DP)pcN0+xJWYqe}7!LpR0Oc>?HOSF`VnM@v`EnoQ@=dDY7O7f^?jPksv_j_VH2szLkNIAfTV2boONDcc4LVm3_@l zpp>|1N=wl?LSdqk$@x)O>!DeE)IJsVMQp(3xUFDINpxNoRnE=oGU|Lwj~VujR1km4 zKxv{Esa$D~mZEoC6qf~#4s_YxVb~q9uLBPjJn{*XQMzn^sp(b8KTAyIH z^IHqP4YU@QHn9>$>0dkf)%)}8H_N_fD|n>j&^}+y`4Z3*J>$Cal1yn#Ca0ph@%ejH zD0MJ5&=t;~-AC_`Xcqxu1GE8@wJ(xThQ1Lr+xS;GSAtiIBk1~%=0A}&s>bgbWvVe! z$5w$iXAoG_D#@-uHN%PlaOX+%P+b~w*|SR2OcgW}`^wI)Ld5yVsg9PVD<{R}SHLF* z6g~M-XCnKpv`MvnFUbMWyD}@Aqq<#P(U4jVmjr;+`{tiVz-35|JdOi$@Td+moFBW4B(WP>dvWC`PV~3XD2On#b>Ii4j)B$p9Kv)8|)2b2LAY=A(LMov)pCl=3sz zRuxVLKz~|@BvKKK-qABb_bS;YQc~a9INGyL?~oMF*4Zn9GiEe@L9g7aATofYD4L~P z6#nUf;8iaO18N5=(t3`J_h2$WUnp7=b2*tN(<(p`KkIp=9+h}WCqJqTbued;JNo5U z!8?sJlDx`bI*#M_e+Q4`09wRHa*9u41kV<&`R`1uF{lnz=>FLG$@dnKPCftK$|sHQ808u7D4&&RGLbdEYvMG;AJjVHiK(I<(Z=5wAg~gO8 z1D`p7rWkT9Sjt(n&&NsgJ|Pe&v}-{^_Nue0j)?P*flk5b%7c;!wRtP9CbLmG~j+Awkm7jZX8046{*3(tpx^ zBz@^;QjkP-;m)V)XMU=E0E-E%%|4Mtc&nxAC^&-os`dU|?#OY`Wu z(&v`VQ9o&VQNRqKZJHa5Z$LUh-p^`A&_GYT=6pm?Pw)PmucPThZOvI>WWN$4p3ho~ z{jFfnsH3NT7PQkwpJ~sp&><=#D~H4VYvFH$!G!}NAA@WjH7yTo0S5RY4t^D6kjbkw Z`~cbttH@|hC}98q002ovPDHLkV1k|1=!pOT literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/meta.txt b/assets/dolphin/external/L2_Secret_door_128x64/meta.txt new file mode 100644 index 0000000000..4091b12769 --- /dev/null +++ b/assets/dolphin/external/L2_Secret_door_128x64/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 29 +Active frames: 24 +Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 0 diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index 1d3f351068..d7348b25cd 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -175,3 +175,10 @@ Max butthurt: 12 Min level: 2 Max level: 3 Weight: 4 + +Name: L2_Secret_door_128x64 +Min butthurt: 0 +Max butthurt: 12 +Min level: 2 +Max level: 3 +Weight: 4 From 890c9e87ceac86dc3d70dd3f09657483b1c4209b Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 1 Dec 2023 13:16:48 +0400 Subject: [PATCH 32/40] [FL-3690] Libraries cleanup; u2f crypto rework to use mbedtls (#3234) * examples: plugins: utilize fal_embedded * libs: removed fnv1a_hash * furi: added FURI_PACKED; apps, libs: changed to use FURI_PACKED * lib: mbedtls: using custom config * lib: toolbox: removed md5, switched to mbedtls * targets: f18: link fix * lib: added mbedtls_cfg.h * apps: nfc: explicit dependency on libmbedtls * u2f: reworking to mbedtls * u2f: replaced sha256 & hmac with mbedtls * u2f: functional rework using mbedtls * libs: dropped micro-ecc * u2f: dropped old implementation * toolbox: removed sha256 impl * mcheck() for mbedtls * libs: removed libmisc; split into smaller libs * apps: debug: fixed display_test * apps: include cleanups * fbt: fixed VERSIONCOMSTR * furi: added FURI_CHECK_RETURN * lib: removed qrcode * cleanup * fbt: lint_py+format_py: fixed excessive command length * api: Removed bzero from f7 * api: Removed bzero from f18 * Bump API Symbols Co-authored-by: Aleksandr Kutuzov --- .pvsoptions | 2 +- SConstruct | 11 +- .../debug/ccid_test/iso7816_t0_apdu.h | 4 +- .../debug/display_test/application.fam | 2 +- applications/debug/unit_tests/rpc/rpc_test.c | 36 +- .../example_plugins_advanced/application.fam | 2 + .../example_advanced_plugins.c | 5 +- applications/main/nfc/application.fam | 2 +- applications/main/u2f/application.fam | 2 +- applications/main/u2f/hmac_sha256.c | 98 - applications/main/u2f/hmac_sha256.h | 38 - applications/main/u2f/u2f.c | 237 +- applications/main/u2f/u2f_data.c | 2 +- applications/services/rpc/rpc_gui.c | 5 +- applications/services/rpc/rpc_i.h | 2 +- applications/services/rpc/rpc_storage.c | 16 +- .../storage_move_to_sd/storage_move_to_sd.c | 4 +- furi/core/common_defines.h | 8 + lib/ReadMe.md | 5 +- lib/SConscript | 73 +- lib/appframe.scons | 3 + lib/digital_signal/SConscript | 3 + lib/drivers/SConscript | 3 + lib/flipper_application/elf/elf_file.c | 7 +- lib/flipper_format/SConscript | 3 + lib/fnv1a-hash/fnv1a-hash.c | 10 - lib/fnv1a-hash/fnv1a-hash.h | 39 - lib/heatshrink.scons | 23 + lib/infrared/SConscript | 3 + lib/mbedtls | 2 +- lib/mbedtls.scons | 32 +- lib/mbedtls_cfg.h | 92 + lib/micro-ecc/LICENSE.txt | 21 - lib/micro-ecc/README.md | 41 - lib/micro-ecc/asm_arm.inc | 821 ------ lib/micro-ecc/asm_arm_mult_square.inc | 2311 ----------------- lib/micro-ecc/asm_arm_mult_square_umaal.inc | 1202 --------- lib/micro-ecc/curve-specific.inc | 1249 --------- lib/micro-ecc/platform-specific.inc | 94 - lib/micro-ecc/types.h | 108 - lib/micro-ecc/uECC.c | 1669 ------------ lib/micro-ecc/uECC.h | 367 --- lib/micro-ecc/uECC_vli.h | 172 -- lib/microtar.scons | 2 +- lib/misc.scons | 58 - lib/mlib.scons | 27 + lib/music_worker/SConscript | 3 + lib/nanopb.scons | 31 + lib/nfc/SConscript | 3 + lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 14 +- .../protocols/mf_ultralight/mf_ultralight.h | 2 +- lib/print/SConscript | 3 + lib/pulse_reader/SConscript | 3 + lib/qrcode/qrcode.c | 975 ------- lib/qrcode/qrcode.h | 99 - lib/signal_reader/SConscript | 5 +- lib/subghz/SConscript | 3 + lib/toolbox/SConscript | 5 +- lib/toolbox/md5.c | 299 --- lib/toolbox/md5.h | 83 - lib/toolbox/md5_calc.c | 46 +- lib/toolbox/sha256.c | 221 -- lib/toolbox/sha256.h | 24 - lib/u8g2/SConscript | 20 + lib/update_util/SConscript | 16 + scripts/fbt_tools/fbt_apps.py | 1 - scripts/fbt_tools/fbt_version.py | 4 +- targets/f18/api_symbols.csv | 211 +- targets/f18/target.json | 12 +- targets/f7/api_symbols.csv | 213 +- targets/f7/furi_hal/furi_hal_usb_ccid.c | 6 +- targets/f7/furi_hal/furi_hal_usb_cdc.c | 4 +- targets/f7/furi_hal/furi_hal_usb_hid.c | 12 +- targets/f7/furi_hal/furi_hal_usb_u2f.c | 2 +- targets/f7/target.json | 8 +- 75 files changed, 886 insertions(+), 10358 deletions(-) delete mode 100644 applications/main/u2f/hmac_sha256.c delete mode 100644 applications/main/u2f/hmac_sha256.h delete mode 100644 lib/fnv1a-hash/fnv1a-hash.c delete mode 100644 lib/fnv1a-hash/fnv1a-hash.h create mode 100644 lib/heatshrink.scons create mode 100644 lib/mbedtls_cfg.h delete mode 100644 lib/micro-ecc/LICENSE.txt delete mode 100644 lib/micro-ecc/README.md delete mode 100644 lib/micro-ecc/asm_arm.inc delete mode 100644 lib/micro-ecc/asm_arm_mult_square.inc delete mode 100644 lib/micro-ecc/asm_arm_mult_square_umaal.inc delete mode 100644 lib/micro-ecc/curve-specific.inc delete mode 100644 lib/micro-ecc/platform-specific.inc delete mode 100644 lib/micro-ecc/types.h delete mode 100644 lib/micro-ecc/uECC.c delete mode 100644 lib/micro-ecc/uECC.h delete mode 100644 lib/micro-ecc/uECC_vli.h delete mode 100644 lib/misc.scons create mode 100644 lib/mlib.scons create mode 100644 lib/nanopb.scons delete mode 100644 lib/qrcode/qrcode.c delete mode 100644 lib/qrcode/qrcode.h delete mode 100644 lib/toolbox/md5.c delete mode 100644 lib/toolbox/md5.h delete mode 100644 lib/toolbox/sha256.c delete mode 100644 lib/toolbox/sha256.h create mode 100644 lib/u8g2/SConscript create mode 100644 lib/update_util/SConscript diff --git a/.pvsoptions b/.pvsoptions index 0312180924..3337d7eb5c 100644 --- a/.pvsoptions +++ b/.pvsoptions @@ -1 +1 @@ ---ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* +--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* diff --git a/SConstruct b/SConstruct index a2c5cd9e7a..b42218a579 100644 --- a/SConstruct +++ b/SConstruct @@ -288,13 +288,17 @@ distenv.PhonyTarget( LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]], ) -# PY_LINT_SOURCES contains recursively-built modules' SConscript files + application manifests +# PY_LINT_SOURCES contains recursively-built modules' SConscript files # Here we add additional Python files residing in repo root firmware_env.Append( PY_LINT_SOURCES=[ # Py code folders "site_scons", "scripts", + "applications", + "applications_user", + "assets", + "targets", # Extra files "SConstruct", "firmware.scons", @@ -304,7 +308,10 @@ firmware_env.Append( black_commandline = "@${PYTHON3} -m black ${PY_BLACK_ARGS} ${PY_LINT_SOURCES}" -black_base_args = ["--include", '"\\.scons|\\.py|SConscript|SConstruct"'] +black_base_args = [ + "--include", + '"(\\.scons|\\.py|SConscript|SConstruct|\\.fam)$"', +] distenv.PhonyTarget( "lint_py", diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.h b/applications/debug/ccid_test/iso7816_t0_apdu.h index b66d66054d..5ca13eb604 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.h +++ b/applications/debug/ccid_test/iso7816_t0_apdu.h @@ -13,12 +13,12 @@ struct ISO7816_Command_APDU { //body uint8_t Lc; uint8_t Le; -} __attribute__((packed)); +} FURI_PACKED; struct ISO7816_Response_APDU { uint8_t SW1; uint8_t SW2; -} __attribute__((packed)); +} FURI_PACKED; void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen); void iso7816_read_command_apdu( diff --git a/applications/debug/display_test/application.fam b/applications/debug/display_test/application.fam index 6a2d9c20c1..7b2357b01d 100644 --- a/applications/debug/display_test/application.fam +++ b/applications/debug/display_test/application.fam @@ -4,7 +4,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="display_test_app", requires=["gui"], - fap_libs=["misc"], + fap_libs=["u8g2"], stack_size=1 * 1024, order=120, fap_category="Debug", diff --git a/applications/debug/unit_tests/rpc/rpc_test.c b/applications/debug/unit_tests/rpc/rpc_test.c index 5659ba877d..3faf615721 100644 --- a/applications/debug/unit_tests/rpc/rpc_test.c +++ b/applications/debug/unit_tests/rpc/rpc_test.c @@ -1,27 +1,31 @@ -#include "flipper.pb.h" #include #include -#include "pb_decode.h" -#include -#include "rpc/rpc_i.h" -#include "storage.pb.h" -#include "storage/filesystem_api_defines.h" -#include "storage/storage.h" #include -#include "../minunit.h" #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "../minunit.h" + +#include +#include +#include +#include +#include +#include + LIST_DEF(MsgList, PB_Main, M_POD_OPLIST) #define M_OPL_MsgList_t() LIST_OPLIST(MsgList) diff --git a/applications/examples/example_plugins_advanced/application.fam b/applications/examples/example_plugins_advanced/application.fam index 0c7e3e3b94..10fdc042ff 100644 --- a/applications/examples/example_plugins_advanced/application.fam +++ b/applications/examples/example_plugins_advanced/application.fam @@ -14,6 +14,7 @@ App( entry_point="advanced_plugin1_ep", requires=["example_advanced_plugins"], sources=["plugin1.c"], + fal_embedded=True, ) App( @@ -22,4 +23,5 @@ App( entry_point="advanced_plugin2_ep", requires=["example_advanced_plugins"], sources=["plugin2.c"], + fal_embedded=True, ) diff --git a/applications/examples/example_plugins_advanced/example_advanced_plugins.c b/applications/examples/example_plugins_advanced/example_advanced_plugins.c index 2b137e1d48..77ab820510 100644 --- a/applications/examples/example_plugins_advanced/example_advanced_plugins.c +++ b/applications/examples/example_plugins_advanced/example_advanced_plugins.c @@ -23,7 +23,10 @@ int32_t example_advanced_plugins_app(void* p) { PLUGIN_APP_ID, PLUGIN_API_VERSION, composite_api_resolver_get(resolver)); do { - if(plugin_manager_load_all(manager, APP_DATA_PATH("plugins")) != PluginManagerErrorNone) { + // For built-in .fals (fal_embedded==True), use APP_ASSETS_PATH + // Otherwise, use APP_DATA_PATH + if(plugin_manager_load_all(manager, APP_ASSETS_PATH("plugins")) != + PluginManagerErrorNone) { FURI_LOG_E(TAG, "Failed to load all libs"); break; } diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 33a2011a70..9a98b57c8c 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -13,7 +13,7 @@ App( "!plugins", "!nfc_cli.c", ], - fap_libs=["assets"], + fap_libs=["assets", "mbedtls"], fap_icon="icon.png", fap_category="NFC", ) diff --git a/applications/main/u2f/application.fam b/applications/main/u2f/application.fam index bf41eb0f7a..5e0cde736c 100644 --- a/applications/main/u2f/application.fam +++ b/applications/main/u2f/application.fam @@ -7,7 +7,7 @@ App( icon="A_U2F_14", order=80, resources="resources", - fap_libs=["assets"], + fap_libs=["assets", "mbedtls"], fap_category="USB", fap_icon="icon.png", ) diff --git a/applications/main/u2f/hmac_sha256.c b/applications/main/u2f/hmac_sha256.c deleted file mode 100644 index 611aa2a6f4..0000000000 --- a/applications/main/u2f/hmac_sha256.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * hmac.c - HMAC - * - * Copyright (C) 2017 Sergei Glushchenko - * Author: Sergei Glushchenko - * - * This file is a part of U2F firmware for STM32 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * As additional permission under GNU GPL version 3 section 7, you may - * distribute non-source form of the Program without the copy of the - * GNU GPL normally required by section 4, provided you inform the - * recipients of GNU GPL by a written offer. - * - */ -#include - -#include "sha256.h" -#include "hmac_sha256.h" - -static void _hmac_sha256_init(const hmac_context* ctx) { - hmac_sha256_context* context = (hmac_sha256_context*)ctx; - sha256_start(&context->sha_ctx); -} - -static void - _hmac_sha256_update(const hmac_context* ctx, const uint8_t* message, unsigned message_size) { - hmac_sha256_context* context = (hmac_sha256_context*)ctx; - sha256_update(&context->sha_ctx, message, message_size); -} - -static void _hmac_sha256_finish(const hmac_context* ctx, uint8_t* hash_result) { - hmac_sha256_context* context = (hmac_sha256_context*)ctx; - sha256_finish(&context->sha_ctx, hash_result); -} - -/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always - the same size as the hash result size. */ -static void hmac_init(const hmac_context* ctx, const uint8_t* K) { - uint8_t* pad = ctx->tmp + 2 * ctx->result_size; - unsigned i; - for(i = 0; i < ctx->result_size; ++i) pad[i] = K[i] ^ 0x36; - for(; i < ctx->block_size; ++i) pad[i] = 0x36; - - ctx->init_hash(ctx); - ctx->update_hash(ctx, pad, ctx->block_size); -} - -static void hmac_update(const hmac_context* ctx, const uint8_t* message, unsigned message_size) { - ctx->update_hash(ctx, message, message_size); -} - -static void hmac_finish(const hmac_context* ctx, const uint8_t* K, uint8_t* result) { - uint8_t* pad = ctx->tmp + 2 * ctx->result_size; - unsigned i; - for(i = 0; i < ctx->result_size; ++i) pad[i] = K[i] ^ 0x5c; - for(; i < ctx->block_size; ++i) pad[i] = 0x5c; - - ctx->finish_hash(ctx, result); - - ctx->init_hash(ctx); - ctx->update_hash(ctx, pad, ctx->block_size); - ctx->update_hash(ctx, result, ctx->result_size); - ctx->finish_hash(ctx, result); -} - -void hmac_sha256_init(hmac_sha256_context* ctx, const uint8_t* K) { - ctx->hmac_ctx.init_hash = _hmac_sha256_init; - ctx->hmac_ctx.update_hash = _hmac_sha256_update; - ctx->hmac_ctx.finish_hash = _hmac_sha256_finish; - ctx->hmac_ctx.block_size = 64; - ctx->hmac_ctx.result_size = 32; - ctx->hmac_ctx.tmp = ctx->tmp; - hmac_init(&ctx->hmac_ctx, K); -} - -void hmac_sha256_update( - const hmac_sha256_context* ctx, - const uint8_t* message, - unsigned message_size) { - hmac_update(&ctx->hmac_ctx, message, message_size); -} - -void hmac_sha256_finish(const hmac_sha256_context* ctx, const uint8_t* K, uint8_t* hash_result) { - hmac_finish(&ctx->hmac_ctx, K, hash_result); -} diff --git a/applications/main/u2f/hmac_sha256.h b/applications/main/u2f/hmac_sha256.h deleted file mode 100644 index add123142d..0000000000 --- a/applications/main/u2f/hmac_sha256.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "sha256.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct hmac_context { - void (*init_hash)(const struct hmac_context* context); - void (*update_hash)( - const struct hmac_context* context, - const uint8_t* message, - unsigned message_size); - void (*finish_hash)(const struct hmac_context* context, uint8_t* hash_result); - unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ - unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ - uint8_t* tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */ -} hmac_context; - -typedef struct hmac_sha256_context { - hmac_context hmac_ctx; - sha256_context sha_ctx; - uint8_t tmp[32 * 2 + 64]; -} hmac_sha256_context; - -void hmac_sha256_init(hmac_sha256_context* ctx, const uint8_t* K); - -void hmac_sha256_update( - const hmac_sha256_context* ctx, - const uint8_t* message, - unsigned message_size); - -void hmac_sha256_finish(const hmac_sha256_context* ctx, const uint8_t* K, uint8_t* hash_result); - -#ifdef __cplusplus -} -#endif diff --git a/applications/main/u2f/u2f.c b/applications/main/u2f/u2f.c index ce70212a9f..3bdafe9185 100644 --- a/applications/main/u2f/u2f.c +++ b/applications/main/u2f/u2f.c @@ -1,18 +1,22 @@ -#include #include "u2f.h" #include "u2f_hid.h" #include "u2f_data.h" + +#include #include #include #include // for lfs_tobe32 -#include "toolbox/sha256.h" -#include "hmac_sha256.h" -#include "micro-ecc/uECC.h" +#include +#include +#include +#include #define TAG "U2f" #define WORKER_TAG TAG "Worker" +#define MCHECK(expr) furi_check((expr) == 0) + #define U2F_CMD_REGISTER 0x01 #define U2F_CMD_AUTHENTICATE 0x02 #define U2F_CMD_VERSION 0x03 @@ -25,16 +29,26 @@ typedef enum { 0x08, // "dont-enforce-user-presence-and-sign" - send auth response even if user is missing } U2fAuthMode; +#define U2F_HASH_SIZE 32 +#define U2F_NONCE_SIZE 32 +#define U2F_CHALLENGE_SIZE 32 +#define U2F_APP_ID_SIZE 32 + +#define U2F_EC_KEY_SIZE 32 +#define U2F_EC_BIGNUM_SIZE 32 +#define U2F_EC_POINT_SIZE 65 + typedef struct { uint8_t format; uint8_t xy[64]; -} __attribute__((packed)) U2fPubKey; +} FURI_PACKED U2fPubKey; +_Static_assert(sizeof(U2fPubKey) == U2F_EC_POINT_SIZE, "U2fPubKey size mismatch"); typedef struct { uint8_t len; - uint8_t hash[32]; - uint8_t nonce[32]; -} __attribute__((packed)) U2fKeyHandle; + uint8_t hash[U2F_HASH_SIZE]; + uint8_t nonce[U2F_NONCE_SIZE]; +} FURI_PACKED U2fKeyHandle; typedef struct { uint8_t cla; @@ -42,16 +56,16 @@ typedef struct { uint8_t p1; uint8_t p2; uint8_t len[3]; - uint8_t challenge[32]; - uint8_t app_id[32]; -} __attribute__((packed)) U2fRegisterReq; + uint8_t challenge[U2F_CHALLENGE_SIZE]; + uint8_t app_id[U2F_APP_ID_SIZE]; +} FURI_PACKED U2fRegisterReq; typedef struct { uint8_t reserved; U2fPubKey pub_key; U2fKeyHandle key_handle; uint8_t cert[]; -} __attribute__((packed)) U2fRegisterResp; +} FURI_PACKED U2fRegisterResp; typedef struct { uint8_t cla; @@ -59,16 +73,16 @@ typedef struct { uint8_t p1; uint8_t p2; uint8_t len[3]; - uint8_t challenge[32]; - uint8_t app_id[32]; + uint8_t challenge[U2F_CHALLENGE_SIZE]; + uint8_t app_id[U2F_APP_ID_SIZE]; U2fKeyHandle key_handle; -} __attribute__((packed)) U2fAuthReq; +} FURI_PACKED U2fAuthReq; typedef struct { uint8_t user_present; uint32_t counter; uint8_t signature[]; -} __attribute__((packed)) U2fAuthResp; +} FURI_PACKED U2fAuthResp; static const uint8_t ver_str[] = {"U2F_V2"}; @@ -78,19 +92,20 @@ static const uint8_t state_user_missing[] = {0x69, 0x85}; static const uint8_t state_wrong_data[] = {0x6A, 0x80}; struct U2fData { - uint8_t device_key[32]; - uint8_t cert_key[32]; + uint8_t device_key[U2F_EC_KEY_SIZE]; + uint8_t cert_key[U2F_EC_KEY_SIZE]; uint32_t counter; - const struct uECC_Curve_t* p_curve; bool ready; bool user_present; U2fEvtCallback callback; void* context; + mbedtls_ecp_group group; }; -static int u2f_uecc_random(uint8_t* dest, unsigned size) { +static int u2f_uecc_random_cb(void* context, uint8_t* dest, unsigned size) { + UNUSED(context); furi_hal_random_fill_buf(dest, size); - return 1; + return 0; } U2fData* u2f_alloc() { @@ -99,6 +114,7 @@ U2fData* u2f_alloc() { void u2f_free(U2fData* U2F) { furi_assert(U2F); + mbedtls_ecp_group_free(&U2F->group); free(U2F); } @@ -129,8 +145,8 @@ bool u2f_init(U2fData* U2F) { } } - U2F->p_curve = uECC_secp256r1(); - uECC_set_rng(u2f_uecc_random); + mbedtls_ecp_group_init(&U2F->group); + mbedtls_ecp_group_load(&U2F->group, MBEDTLS_ECP_DP_SECP256R1); U2F->ready = true; return true; @@ -171,21 +187,63 @@ static uint8_t u2f_der_encode_signature(uint8_t* der, uint8_t* sig) { der[0] = 0x30; uint8_t len = 2; - len += u2f_der_encode_int(der + len, sig, 32); - len += u2f_der_encode_int(der + len, sig + 32, 32); + len += u2f_der_encode_int(der + len, sig, U2F_HASH_SIZE); + len += u2f_der_encode_int(der + len, sig + U2F_HASH_SIZE, U2F_HASH_SIZE); der[1] = len - 2; return len; } +static void + u2f_ecc_sign(mbedtls_ecp_group* grp, const uint8_t* key, uint8_t* hash, uint8_t* signature) { + mbedtls_mpi r, s, d; + + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + mbedtls_mpi_init(&d); + + MCHECK(mbedtls_mpi_read_binary(&d, key, U2F_EC_KEY_SIZE)); + MCHECK(mbedtls_ecdsa_sign(grp, &r, &s, &d, hash, U2F_HASH_SIZE, u2f_uecc_random_cb, NULL)); + MCHECK(mbedtls_mpi_write_binary(&r, signature, U2F_EC_BIGNUM_SIZE)); + MCHECK(mbedtls_mpi_write_binary(&s, signature + U2F_EC_BIGNUM_SIZE, U2F_EC_BIGNUM_SIZE)); + + mbedtls_mpi_free(&r); + mbedtls_mpi_free(&s); + mbedtls_mpi_free(&d); +} + +static void u2f_ecc_compute_public_key( + mbedtls_ecp_group* grp, + const uint8_t* private_key, + U2fPubKey* public_key) { + mbedtls_ecp_point Q; + mbedtls_mpi d; + size_t olen; + + mbedtls_ecp_point_init(&Q); + mbedtls_mpi_init(&d); + + MCHECK(mbedtls_mpi_read_binary(&d, private_key, U2F_EC_KEY_SIZE)); + MCHECK(mbedtls_ecp_mul(grp, &Q, &d, &grp->G, u2f_uecc_random_cb, NULL)); + MCHECK(mbedtls_ecp_check_privkey(grp, &d)); + + MCHECK(mbedtls_ecp_point_write_binary( + grp, &Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, (unsigned char*)public_key, sizeof(U2fPubKey))); + + mbedtls_ecp_point_free(&Q); + mbedtls_mpi_free(&d); +} + +/////////////////////////////////////////// + static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { U2fRegisterReq* req = (U2fRegisterReq*)buf; U2fRegisterResp* resp = (U2fRegisterResp*)buf; U2fKeyHandle handle; - uint8_t private[32]; + uint8_t private[U2F_EC_KEY_SIZE]; U2fPubKey pub_key; - uint8_t hash[32]; - uint8_t signature[64]; + uint8_t hash[U2F_HASH_SIZE]; + uint8_t signature[U2F_EC_BIGNUM_SIZE * 2]; if(u2f_data_check(false) == false) { U2F->ready = false; @@ -201,40 +259,54 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { } U2F->user_present = false; - hmac_sha256_context hmac_ctx; - sha256_context sha_ctx; + handle.len = U2F_HASH_SIZE * 2; - handle.len = 32 * 2; // Generate random nonce furi_hal_random_fill_buf(handle.nonce, 32); - // Generate private key - hmac_sha256_init(&hmac_ctx, U2F->device_key); - hmac_sha256_update(&hmac_ctx, req->app_id, 32); - hmac_sha256_update(&hmac_ctx, handle.nonce, 32); - hmac_sha256_finish(&hmac_ctx, U2F->device_key, private); + { + mbedtls_md_context_t hmac_ctx; + mbedtls_md_init(&hmac_ctx); + MCHECK(mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1)); + MCHECK(mbedtls_md_hmac_starts(&hmac_ctx, U2F->device_key, sizeof(U2F->device_key))); - // Generate private key handle - hmac_sha256_init(&hmac_ctx, U2F->device_key); - hmac_sha256_update(&hmac_ctx, private, 32); - hmac_sha256_update(&hmac_ctx, req->app_id, 32); - hmac_sha256_finish(&hmac_ctx, U2F->device_key, handle.hash); + // Generate private key + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, handle.nonce, sizeof(handle.nonce))); + MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, private)); + + MCHECK(mbedtls_md_hmac_reset(&hmac_ctx)); + + // Generate private key handle + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, private, sizeof(private))); + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); + MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, handle.hash)); + } // Generate public key - pub_key.format = 0x04; // Uncompressed point - uECC_compute_public_key(private, pub_key.xy, U2F->p_curve); + u2f_ecc_compute_public_key(&U2F->group, private, &pub_key); // Generate signature - uint8_t reserved_byte = 0; - sha256_start(&sha_ctx); - sha256_update(&sha_ctx, &reserved_byte, 1); - sha256_update(&sha_ctx, req->app_id, 32); - sha256_update(&sha_ctx, req->challenge, 32); - sha256_update(&sha_ctx, handle.hash, handle.len); - sha256_update(&sha_ctx, (uint8_t*)&pub_key, 65); - sha256_finish(&sha_ctx, hash); + { + uint8_t reserved_byte = 0; - uECC_sign(U2F->cert_key, hash, 32, signature, U2F->p_curve); + mbedtls_sha256_context sha_ctx; + + mbedtls_sha256_init(&sha_ctx); + mbedtls_sha256_starts(&sha_ctx, 0); + + mbedtls_sha256_update(&sha_ctx, &reserved_byte, 1); + mbedtls_sha256_update(&sha_ctx, req->app_id, sizeof(req->app_id)); + mbedtls_sha256_update(&sha_ctx, req->challenge, sizeof(req->challenge)); + mbedtls_sha256_update(&sha_ctx, handle.hash, handle.len); + mbedtls_sha256_update(&sha_ctx, (uint8_t*)&pub_key, sizeof(U2fPubKey)); + + mbedtls_sha256_finish(&sha_ctx, hash); + mbedtls_sha256_free(&sha_ctx); + } + + // Sign hash + u2f_ecc_sign(&U2F->group, U2F->cert_key, hash, signature); // Encode response message resp->reserved = 0x05; @@ -250,13 +322,11 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { U2fAuthReq* req = (U2fAuthReq*)buf; U2fAuthResp* resp = (U2fAuthResp*)buf; - uint8_t priv_key[32]; + uint8_t priv_key[U2F_EC_KEY_SIZE]; uint8_t mac_control[32]; - hmac_sha256_context hmac_ctx; - sha256_context sha_ctx; uint8_t flags = 0; - uint8_t hash[32]; - uint8_t signature[64]; + uint8_t hash[U2F_HASH_SIZE]; + uint8_t signature[U2F_HASH_SIZE * 2]; uint32_t be_u2f_counter; if(u2f_data_check(false) == false) { @@ -281,26 +351,42 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { be_u2f_counter = lfs_tobe32(U2F->counter + 1); // Generate hash - sha256_start(&sha_ctx); - sha256_update(&sha_ctx, req->app_id, 32); - sha256_update(&sha_ctx, &flags, 1); - sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), 4); - sha256_update(&sha_ctx, req->challenge, 32); - sha256_finish(&sha_ctx, hash); + { + mbedtls_sha256_context sha_ctx; - // Recover private key - hmac_sha256_init(&hmac_ctx, U2F->device_key); - hmac_sha256_update(&hmac_ctx, req->app_id, 32); - hmac_sha256_update(&hmac_ctx, req->key_handle.nonce, 32); - hmac_sha256_finish(&hmac_ctx, U2F->device_key, priv_key); + mbedtls_sha256_init(&sha_ctx); + mbedtls_sha256_starts(&sha_ctx, 0); - // Generate and verify private key handle - hmac_sha256_init(&hmac_ctx, U2F->device_key); - hmac_sha256_update(&hmac_ctx, priv_key, 32); - hmac_sha256_update(&hmac_ctx, req->app_id, 32); - hmac_sha256_finish(&hmac_ctx, U2F->device_key, mac_control); + mbedtls_sha256_update(&sha_ctx, req->app_id, sizeof(req->app_id)); + mbedtls_sha256_update(&sha_ctx, &flags, 1); + mbedtls_sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), sizeof(be_u2f_counter)); + mbedtls_sha256_update(&sha_ctx, req->challenge, sizeof(req->challenge)); - if(memcmp(req->key_handle.hash, mac_control, 32) != 0) { + mbedtls_sha256_finish(&sha_ctx, hash); + mbedtls_sha256_free(&sha_ctx); + } + + { + mbedtls_md_context_t hmac_ctx; + mbedtls_md_init(&hmac_ctx); + MCHECK(mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1)); + MCHECK(mbedtls_md_hmac_starts(&hmac_ctx, U2F->device_key, sizeof(U2F->device_key))); + + // Recover private key + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); + MCHECK(mbedtls_md_hmac_update( + &hmac_ctx, req->key_handle.nonce, sizeof(req->key_handle.nonce))); + MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, priv_key)); + + MCHECK(mbedtls_md_hmac_reset(&hmac_ctx)); + + // Generate and verify private key handle + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, priv_key, sizeof(priv_key))); + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); + MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, mac_control)); + } + + if(memcmp(req->key_handle.hash, mac_control, sizeof(mac_control)) != 0) { FURI_LOG_W(TAG, "Wrong handle!"); memcpy(&buf[0], state_wrong_data, 2); return 2; @@ -311,7 +397,8 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { return 2; } - uECC_sign(priv_key, hash, 32, signature, U2F->p_curve); + // Sign hash + u2f_ecc_sign(&U2F->group, priv_key, hash, signature); resp->user_present = flags; resp->counter = be_u2f_counter; diff --git a/applications/main/u2f/u2f_data.c b/applications/main/u2f/u2f_data.c index 34360f3d63..cb9c4c2947 100644 --- a/applications/main/u2f/u2f_data.c +++ b/applications/main/u2f/u2f_data.c @@ -37,7 +37,7 @@ typedef struct { uint32_t counter; uint8_t random_salt[24]; uint32_t control; -} __attribute__((packed)) U2fCounterData; +} FURI_PACKED U2fCounterData; bool u2f_data_check(bool cert_only) { bool state = false; diff --git a/applications/services/rpc/rpc_gui.c b/applications/services/rpc/rpc_gui.c index 9eff4bca6c..ca8fc61a45 100644 --- a/applications/services/rpc/rpc_gui.c +++ b/applications/services/rpc/rpc_gui.c @@ -1,9 +1,10 @@ -#include "flipper.pb.h" #include "rpc_i.h" -#include "gui.pb.h" #include #include +#include +#include + #define TAG "RpcGui" typedef enum { diff --git a/applications/services/rpc/rpc_i.h b/applications/services/rpc/rpc_i.h index 16e5e594d1..ffca50231c 100644 --- a/applications/services/rpc/rpc_i.h +++ b/applications/services/rpc/rpc_i.h @@ -1,6 +1,6 @@ #pragma once #include "rpc.h" -#include "storage/filesystem_api_defines.h" +#include #include #include #include diff --git a/applications/services/rpc/rpc_storage.c b/applications/services/rpc/rpc_storage.c index 913d89f1af..a934d1c31a 100644 --- a/applications/services/rpc/rpc_storage.c +++ b/applications/services/rpc/rpc_storage.c @@ -1,18 +1,18 @@ -#include "flipper.pb.h" #include #include #include -#include "pb_decode.h" -#include "rpc/rpc.h" -#include "rpc_i.h" -#include "storage.pb.h" -#include "storage/filesystem_api_defines.h" -#include "storage/storage.h" -#include +#include +#include +#include +#include #include #include #include +#include +#include +#include + #define TAG "RpcStorage" #define MAX_NAME_LENGTH 255 diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.c b/applications/system/storage_move_to_sd/storage_move_to_sd.c index 25893f0110..5d1e694bca 100644 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.c +++ b/applications/system/storage_move_to_sd/storage_move_to_sd.c @@ -1,8 +1,8 @@ #include "storage_move_to_sd.h" + #include #include -#include "loader/loader.h" -#include +#include #include #include diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index 2b30c3b06d..b0062e6591 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -17,6 +17,10 @@ extern "C" { #define FURI_WEAK __attribute__((weak)) #endif +#ifndef FURI_PACKED +#define FURI_PACKED __attribute__((packed)) +#endif + #ifndef FURI_IS_IRQ_MASKED #define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U) #endif @@ -47,6 +51,10 @@ void __furi_critical_exit(__FuriCriticalInfo info); #define FURI_CRITICAL_EXIT() __furi_critical_exit(__furi_critical_info); #endif +#ifndef FURI_CHECK_RETURN +#define FURI_CHECK_RETURN __attribute__((__warn_unused_result__)) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/ReadMe.md b/lib/ReadMe.md index 326d933aa5..3adb770187 100644 --- a/lib/ReadMe.md +++ b/lib/ReadMe.md @@ -11,7 +11,6 @@ - `fatfs` - FatFS file system driver - `flipper_application` - Flipper application library, used for FAPs - `flipper_format` - Flipper File Format library -- `fnv1a-hash` - FNV-1a hash library - `heatshrink` - Heatshrink compression library - `ibutton` - ibutton library, used by iButton application - `infrared` - Infrared library, used by Infrared application @@ -19,7 +18,6 @@ - `libusb_stm32` - LibUSB for STM32 series MCU - `littlefs` - LittleFS file system driver, used by internal storage - `mbedtls` - MbedTLS cryptography library -- `micro-ecc` - MicroECC cryptography library - `microtar` - MicroTAR library - `mlib` - M-Lib C containers library - `nanopb` - NanoPB library, protobuf implementation for MCU @@ -28,11 +26,10 @@ - `print` - Tiny printf implementation - `digital_signal` - Digital Signal library used by NFC for software implemented protocols - `pulse_reader` - Pulse Reader library used by NFC for software implemented protocols -- `qrcode` - QR-Code library - `stm32wb_cmsis` - STM32WB series CMSIS headers, extends CMSIS Core - `stm32wb_copro` - STM32WB Copro library: contains WPAN and radio co-processor firmware - `stm32wb_hal` - STM32WB HAL library, extends STM32WB CMSIS and provides HAL - `subghz` - Subghz library, used by SubGhz application -- `toolbox` - Toolbox library, contains various things that is used by flipper firmware +- `toolbox` - Toolbox library, contains various things that is used by Flipper firmware - `u8g2` - u8g2 graphics library, used by GUI subsystem - `update_util` - update utilities library, used by updater \ No newline at end of file diff --git a/lib/SConscript b/lib/SConscript index f2cc9d18a0..4835724e09 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -1,87 +1,24 @@ Import("env") -env.Append( - LINT_SOURCES=[ - Dir("app-scened-template"), - Dir("digital_signal"), - Dir("pulse_reader"), - Dir("signal_reader"), - Dir("drivers"), - Dir("flipper_format"), - Dir("infrared"), - Dir("nfc"), - Dir("subghz"), - Dir("toolbox"), - Dir("u8g2"), - Dir("update_util"), - Dir("print"), - Dir("music_worker"), - ], -) - env.Append( CPPPATH=[ "#/", "#/lib", # TODO FL-3553: remove! - "#/lib/mlib", # Ugly hack Dir("../assets/compiled"), ], - SDK_HEADERS=[ - *( - File(f"#/lib/mlib/m-{name}.h") - for name in ( - "algo", - "array", - "bptree", - "core", - "deque", - "dict", - "list", - "rbtree", - "tuple", - "variant", - ) - ), - ], - CPPDEFINES=[ - '"M_MEMORY_FULL(x)=abort()"', - ], ) -# drivers -# fatfs -# flipper_format -# infrared -# littlefs -# subghz -# toolbox -# one_wire -# micro-ecc -# misc -# digital_signal -# fnv1a_hash -# microtar -# nfc -# qrcode -# u8g2 -# update_util -# heatshrink -# nanopb -# apps -# app-scened-template -# callback-connector -# app-template - - libs = env.BuildModules( [ + "mlib", "stm32wb", "freertos", "print", "microtar", + "mbedtls", "toolbox", "libusb_stm32", "drivers", @@ -91,17 +28,19 @@ libs = env.BuildModules( "ibutton", "infrared", "littlefs", - "mbedtls", "subghz", "nfc", "digital_signal", "pulse_reader", "signal_reader", "appframe", - "misc", + "u8g2", "lfrfid", "flipper_application", "music_worker", + "nanopb", + "update_util", + "heatshrink", ], ) diff --git a/lib/appframe.scons b/lib/appframe.scons index 935986d644..fb268579d6 100644 --- a/lib/appframe.scons +++ b/lib/appframe.scons @@ -5,6 +5,9 @@ env.Append( "#/lib/app-scened-template", "#/lib/callback-connector", ], + LINT_SOURCES=[ + Dir("app-scened-template"), + ], ) diff --git a/lib/digital_signal/SConscript b/lib/digital_signal/SConscript index b94c26f780..41d3348904 100644 --- a/lib/digital_signal/SConscript +++ b/lib/digital_signal/SConscript @@ -8,6 +8,9 @@ env.Append( File("digital_signal.h"), File("digital_sequence.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="digital_signal") diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript index cf93d4bce9..a790d54a7a 100644 --- a/lib/drivers/SConscript +++ b/lib/drivers/SConscript @@ -9,6 +9,9 @@ env.Append( File("st25r3916_reg.h"), File("st25r3916.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 8a78cca413..6543168662 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -1,7 +1,8 @@ -#include "storage/storage.h" -#include #include "elf_file.h" #include "elf_file_i.h" + +#include +#include #include "elf_api_interface.h" #include "../api_hashtable/api_hashtable.h" @@ -34,7 +35,7 @@ const uint8_t trampoline_code_little_endian[TRAMPOLINE_CODE_SIZE] = typedef struct { uint8_t code[TRAMPOLINE_CODE_SIZE]; uint32_t addr; -} __attribute__((packed)) JMPTrampoline; +} FURI_PACKED JMPTrampoline; /**************************************************************************************************/ /********************************************* Caches *********************************************/ diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript index 9c9e8b6f33..f16cd4f391 100644 --- a/lib/flipper_format/SConscript +++ b/lib/flipper_format/SConscript @@ -9,6 +9,9 @@ env.Append( File("flipper_format_i.h"), File("flipper_format_stream.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) diff --git a/lib/fnv1a-hash/fnv1a-hash.c b/lib/fnv1a-hash/fnv1a-hash.c deleted file mode 100644 index 69c675f310..0000000000 --- a/lib/fnv1a-hash/fnv1a-hash.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "fnv1a-hash.h" - -// FNV-1a hash, 32-bit -uint32_t fnv1a_buffer_hash(const uint8_t* buffer, uint32_t length, uint32_t hash) -{ - for (uint32_t i = 0; i < length; i++) { - hash = (hash ^ buffer[i]) * 16777619ULL; - } - return hash; -} diff --git a/lib/fnv1a-hash/fnv1a-hash.h b/lib/fnv1a-hash/fnv1a-hash.h deleted file mode 100644 index 3218cc27c7..0000000000 --- a/lib/fnv1a-hash/fnv1a-hash.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define FNV_1A_INIT 2166136261UL - -// FNV-1a hash, 32-bit -uint32_t fnv1a_buffer_hash(const uint8_t* buffer, uint32_t length, uint32_t hash); - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -// constexpr FNV-1a hash for strings, 32-bit -inline constexpr uint32_t fnv1a_string_hash(const char* str) { - uint32_t hash = FNV_1A_INIT; - - while(*str) { - hash = (hash ^ *str) * 16777619ULL; - str += 1; - } - return hash; -} -#else -// FNV-1a hash for strings, 32-bit -inline uint32_t fnv1a_string_hash(const char* str) { - uint32_t hash = FNV_1A_INIT; - - while(*str) { - hash = (hash ^ *str) * 16777619ULL; - str += 1; - } - return hash; -} -#endif diff --git a/lib/heatshrink.scons b/lib/heatshrink.scons new file mode 100644 index 0000000000..241b5a34e3 --- /dev/null +++ b/lib/heatshrink.scons @@ -0,0 +1,23 @@ +from fbt.util import GLOB_FILE_EXCLUSION + +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/heatshrink", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="heatshrink") +libenv.ApplyLibFlags() + +sources = Glob( + "heatshrink/heatshrink_*.c*", + exclude=GLOB_FILE_EXCLUSION, + source=True, +) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/infrared/SConscript b/lib/infrared/SConscript index 9a1543f00f..a32248a645 100644 --- a/lib/infrared/SConscript +++ b/lib/infrared/SConscript @@ -10,6 +10,9 @@ env.Append( File("worker/infrared_worker.h"), File("worker/infrared_transmit.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) diff --git a/lib/mbedtls b/lib/mbedtls index d65aeb3734..edb8fec988 160000 --- a/lib/mbedtls +++ b/lib/mbedtls @@ -1 +1 @@ -Subproject commit d65aeb37349ad1a50e0f6c9b694d4b5290d60e49 +Subproject commit edb8fec9882084344a314368ac7fd957a187519c diff --git a/lib/mbedtls.scons b/lib/mbedtls.scons index 79a4a25203..77add76966 100644 --- a/lib/mbedtls.scons +++ b/lib/mbedtls.scons @@ -2,13 +2,21 @@ Import("env") env.Append( CPPPATH=[ - "#/lib/mbedtls", + # "#/lib/mbedtls", "#/lib/mbedtls/include", ], SDK_HEADERS=[ File("mbedtls/include/mbedtls/des.h"), File("mbedtls/include/mbedtls/sha1.h"), + File("mbedtls/include/mbedtls/sha256.h"), + File("mbedtls/include/mbedtls/md5.h"), + File("mbedtls/include/mbedtls/md.h"), + File("mbedtls/include/mbedtls/ecdsa.h"), + File("mbedtls/include/mbedtls/ecdh.h"), + File("mbedtls/include/mbedtls/ecp.h"), + # File("mbedtls/include/mbedtls/sha1.h"), ], + CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"mbedtls_cfg.h\\"')], ) @@ -20,14 +28,30 @@ libenv.AppendUnique( # Required for lib to be linkable with .faps "-mword-relocations", "-mlong-calls", + # Crappy code :) + "-Wno-redundant-decls", ], ) +# If we were to build full mbedtls, we would need to use this: +# sources = libenv.GlobRecursive("*.c*", "mbedtls/library") +# Otherwise, we can just use the files we need: sources = [ - "mbedtls/library/des.c", - "mbedtls/library/sha1.c", - "mbedtls/library/platform_util.c", + File("mbedtls/library/bignum.c"), + File("mbedtls/library/bignum_core.c"), + File("mbedtls/library/ecdsa.c"), + File("mbedtls/library/ecp.c"), + File("mbedtls/library/ecp_curves.c"), + File("mbedtls/library/md.c"), + File("mbedtls/library/md5.c"), + File("mbedtls/library/platform_util.c"), + File("mbedtls/library/ripemd160.c"), + File("mbedtls/library/sha1.c"), + File("mbedtls/library/sha256.c"), + File("mbedtls/library/des.c"), ] +Depends(sources, File("mbedtls_cfg.h")) + lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/mbedtls_cfg.h b/lib/mbedtls_cfg.h new file mode 100644 index 0000000000..5af98e9657 --- /dev/null +++ b/lib/mbedtls_cfg.h @@ -0,0 +1,92 @@ +#pragma once + +/** +* A subset of the mbedTLS configuration options that are relevant to the +* Flipper Zero firmware and apps. They are built to "mbedtls" library you can +* link your apps with. +* +* If you need more features, either bring the full mbedtls library into your +* app using "fap_private_libs" or open an issue on GitHub to add them to the +* default configuration. +**/ + +#define MBEDTLS_HAVE_ASM + +#define MBEDTLS_NO_UDBL_DIVISION +#define MBEDTLS_NO_64BIT_MULTIPLICATION + +#define MBEDTLS_DEPRECATED_WARNING + +#define MBEDTLS_AES_FEWER_TABLES +// #define MBEDTLS_CHECK_RETURN_WARNING + +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_MODE_CFB +#define MBEDTLS_CIPHER_MODE_CTR +#define MBEDTLS_CIPHER_MODE_OFB +#define MBEDTLS_CIPHER_MODE_XTS + +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/* Short Weierstrass curves (supporting ECP, ECDH, ECDSA) */ +// #define MBEDTLS_ECP_DP_SECP192R1_ENABLED +// #define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +// #define MBEDTLS_ECP_DP_SECP384R1_ENABLED +// #define MBEDTLS_ECP_DP_SECP521R1_ENABLED +// #define MBEDTLS_ECP_DP_SECP192K1_ENABLED +// #define MBEDTLS_ECP_DP_SECP224K1_ENABLED +// #define MBEDTLS_ECP_DP_SECP256K1_ENABLED +// #define MBEDTLS_ECP_DP_BP256R1_ENABLED +// #define MBEDTLS_ECP_DP_BP384R1_ENABLED +// #define MBEDTLS_ECP_DP_BP512R1_ENABLED +/* Montgomery curves (supporting ECP) */ +// #define MBEDTLS_ECP_DP_CURVE25519_ENABLED +// #define MBEDTLS_ECP_DP_CURVE448_ENABLED + +#define MBEDTLS_ECP_NIST_OPTIM + +#define MBEDTLS_GENPRIME +// #define MBEDTLS_PKCS1_V15 +// #define MBEDTLS_PKCS1_V21 + +#define MBEDTLS_MD_C + +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_OID_C + +// #define MBEDTLS_CHACHA20_C +// #define MBEDTLS_CHACHAPOLY_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_DES_C +#define MBEDTLS_DHM_C + +#define MBEDTLS_ECDH_C + +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C + +#define MBEDTLS_GCM_C + +#define MBEDTLS_AES_C +#define MBEDTLS_MD5_C + +// #define MBEDTLS_PEM_PARSE_C +// #define MBEDTLS_PEM_WRITE_C + +// #define MBEDTLS_PLATFORM_MEMORY +// #define MBEDTLS_PLATFORM_C + +// #define MBEDTLS_RIPEMD160_C +// #define MBEDTLS_RSA_C +#define MBEDTLS_SHA224_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA1_C + +#define MBEDTLS_ERROR_C \ No newline at end of file diff --git a/lib/micro-ecc/LICENSE.txt b/lib/micro-ecc/LICENSE.txt deleted file mode 100644 index ab099ae5a5..0000000000 --- a/lib/micro-ecc/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2014, Kenneth MacKay -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/micro-ecc/README.md b/lib/micro-ecc/README.md deleted file mode 100644 index 111321bf76..0000000000 --- a/lib/micro-ecc/README.md +++ /dev/null @@ -1,41 +0,0 @@ -micro-ecc -========== - -A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors. - -The static version of micro-ecc (ie, where the curve was selected at compile-time) can be found in the "static" branch. - -Features --------- - - * Resistant to known side-channel attacks. - * Written in C, with optional GCC inline assembly for AVR, ARM and Thumb platforms. - * Supports 8, 32, and 64-bit architectures. - * Small code size. - * No dynamic memory allocation. - * Support for 5 standard curves: secp160r1, secp192r1, secp224r1, secp256r1, and secp256k1. - * BSD 2-clause license. - -Usage Notes ------------ -### Point Representation ### -Compressed points are represented in the standard format as defined in http://www.secg.org/sec1-v2.pdf; uncompressed points are represented in standard format, but without the `0x04` prefix. All functions except `uECC_decompress()` only accept uncompressed points; use `uECC_compress()` and `uECC_decompress()` to convert between compressed and uncompressed point representations. - -Private keys are represented in the standard format. - -### Using the Code ### - -I recommend just copying (or symlink) the uECC files into your project. Then just `#include "uECC.h"` to use the micro-ecc functions. - -For use with Arduino, you can use the Library Manager to download micro-ecc (**Sketch**=>**Include Library**=>**Manage Libraries**). You can then use uECC just like any other Arduino library (uECC should show up in the **Sketch**=>**Import Library** submenu). - -See uECC.h for documentation for each function. - -### Compilation Notes ### - - * Should compile with any C/C++ compiler that supports stdint.h (this includes Visual Studio 2013). - * If you want to change the defaults for any of the uECC compile-time options (such as `uECC_OPTIMIZATION_LEVEL`), you must change them in your Makefile or similar so that uECC.c is compiled with the desired values (ie, compile uECC.c with `-DuECC_OPTIMIZATION_LEVEL=3` or whatever). - * When compiling for a Thumb-1 platform, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). - * When compiling for an ARM/Thumb-2 platform with `uECC_OPTIMIZATION_LEVEL` >= 3, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). - * When compiling for AVR, you must have optimizations enabled (compile with `-O1` or higher). - * When building for Windows, you will need to link in the `advapi32.lib` system library. diff --git a/lib/micro-ecc/asm_arm.inc b/lib/micro-ecc/asm_arm.inc deleted file mode 100644 index 43844da6a5..0000000000 --- a/lib/micro-ecc/asm_arm.inc +++ /dev/null @@ -1,821 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_ASM_ARM_H_ -#define _UECC_ASM_ARM_H_ - -#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - #define uECC_MIN_WORDS 8 -#endif -#if uECC_SUPPORTS_secp224r1 - #undef uECC_MIN_WORDS - #define uECC_MIN_WORDS 7 -#endif -#if uECC_SUPPORTS_secp192r1 - #undef uECC_MIN_WORDS - #define uECC_MIN_WORDS 6 -#endif -#if uECC_SUPPORTS_secp160r1 - #undef uECC_MIN_WORDS - #define uECC_MIN_WORDS 5 -#endif - -#if (uECC_PLATFORM == uECC_arm_thumb) - #define REG_RW "+l" - #define REG_WRITE "=l" -#else - #define REG_RW "+r" - #define REG_WRITE "=r" -#endif - -#if (uECC_PLATFORM == uECC_arm_thumb || uECC_PLATFORM == uECC_arm_thumb2) - #define REG_RW_LO "+l" - #define REG_WRITE_LO "=l" -#else - #define REG_RW_LO "+r" - #define REG_WRITE_LO "=r" -#endif - -#if (uECC_PLATFORM == uECC_arm_thumb2) - #define RESUME_SYNTAX -#else - #define RESUME_SYNTAX ".syntax divided \n\t" -#endif - -#if (uECC_OPTIMIZATION_LEVEL >= 2) - -uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { -#if (uECC_MAX_WORDS != uECC_MIN_WORDS) - #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2) - uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1; - #else /* ARM */ - uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4; - #endif -#endif - uint32_t carry; - uint32_t left_word; - uint32_t right_word; - - __asm__ volatile ( - ".syntax unified \n\t" - "movs %[carry], #0 \n\t" - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - "adr %[left], 1f \n\t" - ".align 4 \n\t" - "adds %[jump], %[left] \n\t" - #endif - - "ldmia %[lptr]!, {%[left]} \n\t" - "ldmia %[rptr]!, {%[right]} \n\t" - "adds %[left], %[right] \n\t" - "stmia %[dptr]!, {%[left]} \n\t" - - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - "bx %[jump] \n\t" - #endif - "1: \n\t" - REPEAT(DEC(uECC_MAX_WORDS), - "ldmia %[lptr]!, {%[left]} \n\t" - "ldmia %[rptr]!, {%[right]} \n\t" - "adcs %[left], %[right] \n\t" - "stmia %[dptr]!, {%[left]} \n\t") - - "adcs %[carry], %[carry] \n\t" - RESUME_SYNTAX - : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right), - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - [jump] REG_RW_LO (jump), - #endif - [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word), - [right] REG_WRITE_LO (right_word) - : - : "cc", "memory" - ); - return carry; -} -#define asm_add 1 - -#pragma GCC diagnostic ignored "-Wredundant-decls" -uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { -#if (uECC_MAX_WORDS != uECC_MIN_WORDS) - #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2) - uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1; - #else /* ARM */ - uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4; - #endif -#endif - uint32_t carry; - uint32_t left_word; - uint32_t right_word; - - __asm__ volatile ( - ".syntax unified \n\t" - "movs %[carry], #0 \n\t" - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - "adr %[left], 1f \n\t" - ".align 4 \n\t" - "adds %[jump], %[left] \n\t" - #endif - - "ldmia %[lptr]!, {%[left]} \n\t" - "ldmia %[rptr]!, {%[right]} \n\t" - "subs %[left], %[right] \n\t" - "stmia %[dptr]!, {%[left]} \n\t" - - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - "bx %[jump] \n\t" - #endif - "1: \n\t" - REPEAT(DEC(uECC_MAX_WORDS), - "ldmia %[lptr]!, {%[left]} \n\t" - "ldmia %[rptr]!, {%[right]} \n\t" - "sbcs %[left], %[right] \n\t" - "stmia %[dptr]!, {%[left]} \n\t") - - "adcs %[carry], %[carry] \n\t" - RESUME_SYNTAX - : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right), - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - [jump] REG_RW_LO (jump), - #endif - [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word), - [right] REG_WRITE_LO (right_word) - : - : "cc", "memory" - ); - return !carry; /* Note that on ARM, carry flag set means "no borrow" when subtracting - (for some reason...) */ -} -#define asm_sub 1 - -#endif /* (uECC_OPTIMIZATION_LEVEL >= 2) */ - -#if (uECC_OPTIMIZATION_LEVEL >= 3) - -#if (uECC_PLATFORM != uECC_arm_thumb) - -#if uECC_ARM_USE_UMAAL - #include "asm_arm_mult_square_umaal.inc" -#else - #include "asm_arm_mult_square.inc" -#endif - -#if (uECC_OPTIMIZATION_LEVEL == 3) - -uECC_VLI_API void uECC_vli_mult(uint32_t *result, - const uint32_t *left, - const uint32_t *right, - wordcount_t num_words) { - register uint32_t *r0 __asm__("r0") = result; - register const uint32_t *r1 __asm__("r1") = left; - register const uint32_t *r2 __asm__("r2") = right; - register uint32_t r3 __asm__("r3") = num_words; - - __asm__ volatile ( - ".syntax unified \n\t" -#if (uECC_MIN_WORDS == 5) - FAST_MULT_ASM_5 - #if (uECC_MAX_WORDS > 5) - FAST_MULT_ASM_5_TO_6 - #endif - #if (uECC_MAX_WORDS > 6) - FAST_MULT_ASM_6_TO_7 - #endif - #if (uECC_MAX_WORDS > 7) - FAST_MULT_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 6) - FAST_MULT_ASM_6 - #if (uECC_MAX_WORDS > 6) - FAST_MULT_ASM_6_TO_7 - #endif - #if (uECC_MAX_WORDS > 7) - FAST_MULT_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 7) - FAST_MULT_ASM_7 - #if (uECC_MAX_WORDS > 7) - FAST_MULT_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 8) - FAST_MULT_ASM_8 -#endif - "1: \n\t" - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); -} -#define asm_mult 1 - -#if uECC_SQUARE_FUNC -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { - register uint32_t *r0 __asm__("r0") = result; - register const uint32_t *r1 __asm__("r1") = left; - register uint32_t r2 __asm__("r2") = num_words; - - __asm__ volatile ( - ".syntax unified \n\t" -#if (uECC_MIN_WORDS == 5) - FAST_SQUARE_ASM_5 - #if (uECC_MAX_WORDS > 5) - FAST_SQUARE_ASM_5_TO_6 - #endif - #if (uECC_MAX_WORDS > 6) - FAST_SQUARE_ASM_6_TO_7 - #endif - #if (uECC_MAX_WORDS > 7) - FAST_SQUARE_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 6) - FAST_SQUARE_ASM_6 - #if (uECC_MAX_WORDS > 6) - FAST_SQUARE_ASM_6_TO_7 - #endif - #if (uECC_MAX_WORDS > 7) - FAST_SQUARE_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 7) - FAST_SQUARE_ASM_7 - #if (uECC_MAX_WORDS > 7) - FAST_SQUARE_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 8) - FAST_SQUARE_ASM_8 -#endif - - "1: \n\t" - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); -} -#define asm_square 1 -#endif /* uECC_SQUARE_FUNC */ - -#else /* (uECC_OPTIMIZATION_LEVEL > 3) */ - -uECC_VLI_API void uECC_vli_mult(uint32_t *result, - const uint32_t *left, - const uint32_t *right, - wordcount_t num_words) { - register uint32_t *r0 __asm__("r0") = result; - register const uint32_t *r1 __asm__("r1") = left; - register const uint32_t *r2 __asm__("r2") = right; - register uint32_t r3 __asm__("r3") = num_words; - -#if uECC_SUPPORTS_secp160r1 - if (num_words == 5) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_MULT_ASM_5 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if uECC_SUPPORTS_secp192r1 - if (num_words == 6) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_MULT_ASM_6 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if uECC_SUPPORTS_secp224r1 - if (num_words == 7) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_MULT_ASM_7 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - if (num_words == 8) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_MULT_ASM_8 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -} -#define asm_mult 1 - -#if uECC_SQUARE_FUNC -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { - register uint32_t *r0 __asm__("r0") = result; - register const uint32_t *r1 __asm__("r1") = left; - register uint32_t r2 __asm__("r2") = num_words; - -#if uECC_SUPPORTS_secp160r1 - if (num_words == 5) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_SQUARE_ASM_5 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if uECC_SUPPORTS_secp192r1 - if (num_words == 6) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_SQUARE_ASM_6 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if uECC_SUPPORTS_secp224r1 - if (num_words == 7) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_SQUARE_ASM_7 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - if (num_words == 8) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_SQUARE_ASM_8 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -} -#define asm_square 1 -#endif /* uECC_SQUARE_FUNC */ - -#endif /* (uECC_OPTIMIZATION_LEVEL > 3) */ - -#endif /* uECC_PLATFORM != uECC_arm_thumb */ - -#endif /* (uECC_OPTIMIZATION_LEVEL >= 3) */ - -/* ---- "Small" implementations ---- */ - -#if !asm_add -uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uint32_t carry = 0; - uint32_t left_word; - uint32_t right_word; - - __asm__ volatile ( - ".syntax unified \n\t" - "1: \n\t" - "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ - "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ - "lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */ - "adcs %[left], %[left], %[right] \n\t" /* Add with carry. */ - "adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */ - "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ - "subs %[ctr], #1 \n\t" /* Decrement counter. */ - "bne 1b \n\t" /* Loop until counter == 0. */ - RESUME_SYNTAX - : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right), - [ctr] REG_RW (num_words), [carry] REG_RW (carry), - [left] REG_WRITE (left_word), [right] REG_WRITE (right_word) - : - : "cc", "memory" - ); - return carry; -} -#define asm_add 1 -#endif - -#if !asm_sub -uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */ - uint32_t left_word; - uint32_t right_word; - - __asm__ volatile ( - ".syntax unified \n\t" - "1: \n\t" - "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ - "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ - "lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */ - "sbcs %[left], %[left], %[right] \n\t" /* Subtract with borrow. */ - "adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */ - "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ - "subs %[ctr], #1 \n\t" /* Decrement counter. */ - "bne 1b \n\t" /* Loop until counter == 0. */ - RESUME_SYNTAX - : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right), - [ctr] REG_RW (num_words), [carry] REG_RW (carry), - [left] REG_WRITE (left_word), [right] REG_WRITE (right_word) - : - : "cc", "memory" - ); - return !carry; -} -#define asm_sub 1 -#endif - -#if !asm_mult -uECC_VLI_API void uECC_vli_mult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { -#if (uECC_PLATFORM != uECC_arm_thumb) - uint32_t c0 = 0; - uint32_t c1 = 0; - uint32_t c2 = 0; - uint32_t k = 0; - uint32_t i; - uint32_t t0, t1; - - __asm__ volatile ( - ".syntax unified \n\t" - - "1: \n\t" /* outer loop (k < num_words) */ - "movs %[i], #0 \n\t" /* i = 0 */ - "b 3f \n\t" - - "2: \n\t" /* outer loop (k >= num_words) */ - "movs %[i], %[k] \n\t" /* i = k */ - "subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */ - - "3: \n\t" /* inner loop */ - "subs %[t0], %[k], %[i] \n\t" /* t0 = k-i */ - - "ldr %[t1], [%[right], %[t0]] \n\t" /* t1 = right[k - i] */ - "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */ - - "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ - - "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ - "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ - "adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */ - - "adds %[i], #4 \n\t" /* i += 4 */ - "cmp %[i], %[last_word] \n\t" /* i > (num_words - 1) (times 4)? */ - "bgt 4f \n\t" /* if so, exit the loop */ - "cmp %[i], %[k] \n\t" /* i <= k? */ - "ble 3b \n\t" /* if so, continue looping */ - - "4: \n\t" /* end inner loop */ - - "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ - "mov %[c0], %[c1] \n\t" /* c0 = c1 */ - "mov %[c1], %[c2] \n\t" /* c1 = c2 */ - "movs %[c2], #0 \n\t" /* c2 = 0 */ - "adds %[k], #4 \n\t" /* k += 4 */ - "cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */ - "ble 1b \n\t" /* if so, loop back, start with i = 0 */ - "cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ - "ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */ - /* end outer loop */ - - "str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */ - RESUME_SYNTAX - : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), - [k] "+r" (k), [i] "=&r" (i), [t0] "=&r" (t0), [t1] "=&r" (t1) - : [result] "r" (result), [left] "r" (left), [right] "r" (right), - [last_word] "r" ((num_words - 1) * 4) - : "cc", "memory" - ); - -#else /* Thumb-1 */ - uint32_t r4, r5, r6, r7; - - __asm__ volatile ( - ".syntax unified \n\t" - "subs %[r3], #1 \n\t" /* r3 = num_words - 1 */ - "lsls %[r3], #2 \n\t" /* r3 = (num_words - 1) * 4 */ - "mov r8, %[r3] \n\t" /* r8 = (num_words - 1) * 4 */ - "lsls %[r3], #1 \n\t" /* r3 = (num_words - 1) * 8 */ - "mov r9, %[r3] \n\t" /* r9 = (num_words - 1) * 8 */ - "movs %[r3], #0 \n\t" /* c0 = 0 */ - "movs %[r4], #0 \n\t" /* c1 = 0 */ - "movs %[r5], #0 \n\t" /* c2 = 0 */ - "movs %[r6], #0 \n\t" /* k = 0 */ - - "push {%[r0]} \n\t" /* keep result on the stack */ - - "1: \n\t" /* outer loop (k < num_words) */ - "movs %[r7], #0 \n\t" /* r7 = i = 0 */ - "b 3f \n\t" - - "2: \n\t" /* outer loop (k >= num_words) */ - "movs %[r7], %[r6] \n\t" /* r7 = k */ - "mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */ - "subs %[r7], %[r0] \n\t" /* r7 = i = k - (num_words - 1) (times 4) */ - - "3: \n\t" /* inner loop */ - "mov r10, %[r3] \n\t" - "mov r11, %[r4] \n\t" - "mov r12, %[r5] \n\t" - "mov r14, %[r6] \n\t" - "subs %[r0], %[r6], %[r7] \n\t" /* r0 = k - i */ - - "ldr %[r4], [%[r2], %[r0]] \n\t" /* r4 = right[k - i] */ - "ldr %[r0], [%[r1], %[r7]] \n\t" /* r0 = left[i] */ - - "lsrs %[r3], %[r0], #16 \n\t" /* r3 = a1 */ - "uxth %[r0], %[r0] \n\t" /* r0 = a0 */ - - "lsrs %[r5], %[r4], #16 \n\t" /* r5 = b1 */ - "uxth %[r4], %[r4] \n\t" /* r4 = b0 */ - - "movs %[r6], %[r3] \n\t" /* r6 = a1 */ - "muls %[r6], %[r5], %[r6] \n\t" /* r6 = a1 * b1 */ - "muls %[r3], %[r4], %[r3] \n\t" /* r3 = b0 * a1 */ - "muls %[r5], %[r0], %[r5] \n\t" /* r5 = a0 * b1 */ - "muls %[r0], %[r4], %[r0] \n\t" /* r0 = a0 * b0 */ - - /* Add middle terms */ - "lsls %[r4], %[r3], #16 \n\t" - "lsrs %[r3], %[r3], #16 \n\t" - "adds %[r0], %[r4] \n\t" - "adcs %[r6], %[r3] \n\t" - - "lsls %[r4], %[r5], #16 \n\t" - "lsrs %[r5], %[r5], #16 \n\t" - "adds %[r0], %[r4] \n\t" - "adcs %[r6], %[r5] \n\t" - - "mov %[r3], r10\n\t" - "mov %[r4], r11\n\t" - "mov %[r5], r12\n\t" - "adds %[r3], %[r0] \n\t" /* add low word to c0 */ - "adcs %[r4], %[r6] \n\t" /* add high word to c1, including carry */ - "movs %[r0], #0 \n\t" /* r0 = 0 (does not affect carry bit) */ - "adcs %[r5], %[r0] \n\t" /* add carry to c2 */ - - "mov %[r6], r14\n\t" /* r6 = k */ - - "adds %[r7], #4 \n\t" /* i += 4 */ - "cmp %[r7], r8 \n\t" /* i > (num_words - 1) (times 4)? */ - "bgt 4f \n\t" /* if so, exit the loop */ - "cmp %[r7], %[r6] \n\t" /* i <= k? */ - "ble 3b \n\t" /* if so, continue looping */ - - "4: \n\t" /* end inner loop */ - - "ldr %[r0], [sp, #0] \n\t" /* r0 = result */ - - "str %[r3], [%[r0], %[r6]] \n\t" /* result[k] = c0 */ - "mov %[r3], %[r4] \n\t" /* c0 = c1 */ - "mov %[r4], %[r5] \n\t" /* c1 = c2 */ - "movs %[r5], #0 \n\t" /* c2 = 0 */ - "adds %[r6], #4 \n\t" /* k += 4 */ - "cmp %[r6], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */ - "ble 1b \n\t" /* if so, loop back, start with i = 0 */ - "cmp %[r6], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ - "ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */ - /* end outer loop */ - - "str %[r3], [%[r0], %[r6]] \n\t" /* result[num_words * 2 - 1] = c0 */ - "pop {%[r0]} \n\t" /* pop result off the stack */ - - ".syntax divided \n\t" - : [r3] "+l" (num_words), [r4] "=&l" (r4), - [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) - : [r0] "l" (result), [r1] "l" (left), [r2] "l" (right) - : "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); -#endif -} -#define asm_mult 1 -#endif - -#if uECC_SQUARE_FUNC -#if !asm_square -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { -#if (uECC_PLATFORM != uECC_arm_thumb) - uint32_t c0 = 0; - uint32_t c1 = 0; - uint32_t c2 = 0; - uint32_t k = 0; - uint32_t i, tt; - uint32_t t0, t1; - - __asm__ volatile ( - ".syntax unified \n\t" - - "1: \n\t" /* outer loop (k < num_words) */ - "movs %[i], #0 \n\t" /* i = 0 */ - "b 3f \n\t" - - "2: \n\t" /* outer loop (k >= num_words) */ - "movs %[i], %[k] \n\t" /* i = k */ - "subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */ - - "3: \n\t" /* inner loop */ - "subs %[tt], %[k], %[i] \n\t" /* tt = k-i */ - - "ldr %[t1], [%[left], %[tt]] \n\t" /* t1 = left[k - i] */ - "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */ - - "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ - - "cmp %[i], %[tt] \n\t" /* (i < k - i) ? */ - "bge 4f \n\t" /* if i >= k - i, skip */ - "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ - "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ - "adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */ - - "4: \n\t" - "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ - "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ - "adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */ - - "adds %[i], #4 \n\t" /* i += 4 */ - "cmp %[i], %[k] \n\t" /* i >= k? */ - "bge 5f \n\t" /* if so, exit the loop */ - "subs %[tt], %[k], %[i] \n\t" /* tt = k - i */ - "cmp %[i], %[tt] \n\t" /* i <= k - i? */ - "ble 3b \n\t" /* if so, continue looping */ - - "5: \n\t" /* end inner loop */ - - "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ - "mov %[c0], %[c1] \n\t" /* c0 = c1 */ - "mov %[c1], %[c2] \n\t" /* c1 = c2 */ - "movs %[c2], #0 \n\t" /* c2 = 0 */ - "adds %[k], #4 \n\t" /* k += 4 */ - "cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */ - "ble 1b \n\t" /* if so, loop back, start with i = 0 */ - "cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ - "ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */ - /* end outer loop */ - - "str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */ - RESUME_SYNTAX - : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), - [k] "+r" (k), [i] "=&r" (i), [tt] "=&r" (tt), [t0] "=&r" (t0), [t1] "=&r" (t1) - : [result] "r" (result), [left] "r" (left), [last_word] "r" ((num_words - 1) * 4) - : "cc", "memory" - ); - -#else - uint32_t r3, r4, r5, r6, r7; - - __asm__ volatile ( - ".syntax unified \n\t" - "subs %[r2], #1 \n\t" /* r2 = num_words - 1 */ - "lsls %[r2], #2 \n\t" /* r2 = (num_words - 1) * 4 */ - "mov r8, %[r2] \n\t" /* r8 = (num_words - 1) * 4 */ - "lsls %[r2], #1 \n\t" /* r2 = (num_words - 1) * 8 */ - "mov r9, %[r2] \n\t" /* r9 = (num_words - 1) * 8 */ - "movs %[r2], #0 \n\t" /* c0 = 0 */ - "movs %[r3], #0 \n\t" /* c1 = 0 */ - "movs %[r4], #0 \n\t" /* c2 = 0 */ - "movs %[r5], #0 \n\t" /* k = 0 */ - - "push {%[r0]} \n\t" /* keep result on the stack */ - - "1: \n\t" /* outer loop (k < num_words) */ - "movs %[r6], #0 \n\t" /* r6 = i = 0 */ - "b 3f \n\t" - - "2: \n\t" /* outer loop (k >= num_words) */ - "movs %[r6], %[r5] \n\t" /* r6 = k */ - "mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */ - "subs %[r6], %[r0] \n\t" /* r6 = i = k - (num_words - 1) (times 4) */ - - "3: \n\t" /* inner loop */ - "mov r10, %[r2] \n\t" - "mov r11, %[r3] \n\t" - "mov r12, %[r4] \n\t" - "mov r14, %[r5] \n\t" - "subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */ - - "ldr %[r3], [%[r1], %[r7]] \n\t" /* r3 = left[k - i] */ - "ldr %[r0], [%[r1], %[r6]] \n\t" /* r0 = left[i] */ - - "lsrs %[r2], %[r0], #16 \n\t" /* r2 = a1 */ - "uxth %[r0], %[r0] \n\t" /* r0 = a0 */ - - "lsrs %[r4], %[r3], #16 \n\t" /* r4 = b1 */ - "uxth %[r3], %[r3] \n\t" /* r3 = b0 */ - - "movs %[r5], %[r2] \n\t" /* r5 = a1 */ - "muls %[r5], %[r4], %[r5] \n\t" /* r5 = a1 * b1 */ - "muls %[r2], %[r3], %[r2] \n\t" /* r2 = b0 * a1 */ - "muls %[r4], %[r0], %[r4] \n\t" /* r4 = a0 * b1 */ - "muls %[r0], %[r3], %[r0] \n\t" /* r0 = a0 * b0 */ - - /* Add middle terms */ - "lsls %[r3], %[r2], #16 \n\t" - "lsrs %[r2], %[r2], #16 \n\t" - "adds %[r0], %[r3] \n\t" - "adcs %[r5], %[r2] \n\t" - - "lsls %[r3], %[r4], #16 \n\t" - "lsrs %[r4], %[r4], #16 \n\t" - "adds %[r0], %[r3] \n\t" - "adcs %[r5], %[r4] \n\t" - - /* Add to acc, doubling if necessary */ - "mov %[r2], r10\n\t" - "mov %[r3], r11\n\t" - "mov %[r4], r12\n\t" - - "cmp %[r6], %[r7] \n\t" /* (i < k - i) ? */ - "bge 4f \n\t" /* if i >= k - i, skip */ - "movs %[r7], #0 \n\t" /* r7 = 0 */ - "adds %[r2], %[r0] \n\t" /* add low word to c0 */ - "adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */ - "adcs %[r4], %[r7] \n\t" /* add carry to c2 */ - "4: \n\t" - "movs %[r7], #0 \n\t" /* r7 = 0 */ - "adds %[r2], %[r0] \n\t" /* add low word to c0 */ - "adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */ - "adcs %[r4], %[r7] \n\t" /* add carry to c2 */ - - "mov %[r5], r14\n\t" /* r5 = k */ - - "adds %[r6], #4 \n\t" /* i += 4 */ - "cmp %[r6], %[r5] \n\t" /* i >= k? */ - "bge 5f \n\t" /* if so, exit the loop */ - "subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */ - "cmp %[r6], %[r7] \n\t" /* i <= k - i? */ - "ble 3b \n\t" /* if so, continue looping */ - - "5: \n\t" /* end inner loop */ - - "ldr %[r0], [sp, #0] \n\t" /* r0 = result */ - - "str %[r2], [%[r0], %[r5]] \n\t" /* result[k] = c0 */ - "mov %[r2], %[r3] \n\t" /* c0 = c1 */ - "mov %[r3], %[r4] \n\t" /* c1 = c2 */ - "movs %[r4], #0 \n\t" /* c2 = 0 */ - "adds %[r5], #4 \n\t" /* k += 4 */ - "cmp %[r5], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */ - "ble 1b \n\t" /* if so, loop back, start with i = 0 */ - "cmp %[r5], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ - "ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */ - /* end outer loop */ - - "str %[r2], [%[r0], %[r5]] \n\t" /* result[num_words * 2 - 1] = c0 */ - "pop {%[r0]} \n\t" /* pop result off the stack */ - - ".syntax divided \n\t" - : [r2] "+l" (num_words), [r3] "=&l" (r3), [r4] "=&l" (r4), - [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) - : [r0] "l" (result), [r1] "l" (left) - : "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); -#endif -} -#define asm_square 1 -#endif -#endif /* uECC_SQUARE_FUNC */ - -#endif /* _UECC_ASM_ARM_H_ */ diff --git a/lib/micro-ecc/asm_arm_mult_square.inc b/lib/micro-ecc/asm_arm_mult_square.inc deleted file mode 100644 index 8907fc1858..0000000000 --- a/lib/micro-ecc/asm_arm_mult_square.inc +++ /dev/null @@ -1,2311 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_ASM_ARM_MULT_SQUARE_H_ -#define _UECC_ASM_ARM_MULT_SQUARE_H_ - -#define FAST_MULT_ASM_5 \ - "push {r3} \n\t" \ - "add r0, 12 \n\t" \ - "add r2, 12 \n\t" \ - "ldmia r1!, {r3,r4} \n\t" \ - "ldmia r2!, {r6,r7} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adc r10, r10, r14 \n\t" \ - "stmia r0!, {r9, r10} \n\t" \ - \ - "sub r0, 28 \n\t" \ - "sub r2, 20 \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - "ldmia r1!, {r5} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adc r11, r11, r9 \n\t" \ - "stmia r0!, {r10, r11} \n\t" \ - "pop {r3} \n\t" - -#define FAST_MULT_ASM_5_TO_6 \ - "cmp r3, #5 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high, r5 = right high */ \ - "ldr r4, [r1] \n\t" \ - "ldr r5, [r2] \n\t" \ - \ - "sub r0, #20 \n\t" \ - "sub r1, #20 \n\t" \ - "sub r2, #20 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - /* skip past already-loaded (r4, r5) */ \ - "ldr r7, [r1], #8 \n\t" \ - "ldr r8, [r2], #8 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "umull r11, r12, r4, r5 \n\t" \ - "adds r11, r11, r14 \n\t" \ - "adc r12, r12, r9 \n\t" \ - "stmia r0!, {r11, r12} \n\t" - -#define FAST_MULT_ASM_6 \ - "push {r3} \n\t" \ - "add r0, 12 \n\t" \ - "add r2, 12 \n\t" \ - "ldmia r1!, {r3,r4,r5} \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adc r12, r12, r10 \n\t" \ - "stmia r0!, {r11, r12} \n\t" \ - \ - "sub r0, 36 \n\t" \ - "sub r2, 24 \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r1!, {r5} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r2!, {r8} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r3, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r5, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "umull r10, r11, r5, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adc r14, r14, r11 \n\t" \ - "stmia r0!, {r12, r14} \n\t" \ - "pop {r3} \n\t" - -#define FAST_MULT_ASM_6_TO_7 \ - "cmp r3, #6 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high, r5 = right high */ \ - "ldr r4, [r1] \n\t" \ - "ldr r5, [r2] \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - "sub r2, #24 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - /* skip past already-loaded (r4, r5) */ \ - "ldr r7, [r1], #8 \n\t" \ - "ldr r8, [r2], #8 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "umull r11, r12, r4, r5 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adc r12, r12, r10 \n\t" \ - "stmia r0!, {r11, r12} \n\t" - -#define FAST_MULT_ASM_7 \ - "push {r3} \n\t" \ - "add r0, 24 \n\t" \ - "add r2, 24 \n\t" \ - "ldmia r1!, {r3} \n\t" \ - "ldmia r2!, {r6} \n\t" \ - \ - "umull r9, r10, r3, r6 \n\t" \ - "stmia r0!, {r9, r10} \n\t" \ - \ - "sub r0, 20 \n\t" \ - "sub r2, 16 \n\t" \ - "ldmia r2!, {r6, r7, r8} \n\t" \ - "ldmia r1!, {r4, r5} \n\t" \ - \ - "umull r9, r10, r3, r6 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umull r9, r12, r3, r7 \n\t" \ - "adds r10, r10, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r9, r11, r4, r6 \n\t" \ - "adds r10, r10, r9 \n\t" \ - "adcs r12, r12, r11 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r5, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "umull r9, r10, r3, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adc r12, r12, r10 \n\t" \ - "stmia r0!, {r11, r12} \n\t" \ - \ - "sub r0, 44 \n\t" \ - "sub r1, 16 \n\t" \ - "sub r2, 28 \n\t" \ - "ldmia r1!, {r3,r4,r5} \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - \ - "umull r9, r10, r3, r6 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umull r9, r12, r3, r7 \n\t" \ - "adds r10, r10, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r9, r11, r4, r6 \n\t" \ - "adds r10, r10, r9 \n\t" \ - "adcs r12, r12, r11 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r5, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r5} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r3, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r5, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r4, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r3, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r2!, {r8} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r4, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "umull r10, r11, r3, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adc r14, r14, r11 \n\t" \ - "stmia r0!, {r12, r14} \n\t" \ - "pop {r3} \n\t" - -#define FAST_MULT_ASM_7_TO_8 \ - "cmp r3, #7 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high, r5 = right high */ \ - "ldr r4, [r1] \n\t" \ - "ldr r5, [r2] \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - "sub r2, #28 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - /* skip past already-loaded (r4, r5) */ \ - "ldr r7, [r1], #8 \n\t" \ - "ldr r8, [r2], #8 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "umull r11, r12, r4, r5 \n\t" \ - "adds r11, r11, r10 \n\t" \ - "adc r12, r12, r14 \n\t" \ - "stmia r0!, {r11, r12} \n\t" - -#define FAST_MULT_ASM_8 \ - "push {r3} \n\t" \ - "add r0, 24 \n\t" \ - "add r2, 24 \n\t" \ - "ldmia r1!, {r3,r4} \n\t" \ - "ldmia r2!, {r6,r7} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adc r10, r10, r14 \n\t" \ - "stmia r0!, {r9, r10} \n\t" \ - \ - "sub r0, 28 \n\t" \ - "sub r2, 20 \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - "ldmia r1!, {r5} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adc r11, r11, r9 \n\t" \ - "stmia r0!, {r10, r11} \n\t" \ - \ - "sub r0, 52 \n\t" \ - "sub r1, 20 \n\t" \ - "sub r2, 32 \n\t" \ - "ldmia r1!, {r3,r4,r5} \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r1!, {r5} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r5, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r5, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r2!, {r8} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r5, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r3, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r5, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r4, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r5, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r3, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r4, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "umull r9, r10, r4, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adc r12, r12, r10 \n\t" \ - "stmia r0!, {r11, r12} \n\t" \ - "pop {r3} \n\t" - -#define FAST_SQUARE_ASM_5 \ - "push {r2} \n\t" \ - "ldmia r1!, {r2,r3,r4,r5,r6} \n\t" \ - "push {r1} \n\t" \ - \ - "umull r11, r12, r2, r2 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r2, r3 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r11, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r8, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r2, r4 \n\t" \ - "adds r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r3 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r5 \n\t" \ - "umull r1, r14, r3, r4 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r2, r6 \n\t" \ - "umull r1, r14, r3, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "umull r1, r14, r4, r4 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r3, r6 \n\t" \ - "umull r1, r14, r4, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r8, #0 \n\t" \ - "umull r1, r10, r4, r6 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "umull r1, r10, r5, r5 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r1, r10, r5, r6 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "adds r12, r12, r1 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r1, r10, r6, r6 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "stmia r0!, {r8, r11} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_5_TO_6 \ - "cmp r2, #5 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #20 \n\t" \ - "sub r1, #20 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r6,r7,r8,r9,r10,r11} \n\t" \ - "umull r3, r4, r6, r11 \n\t" \ - "umull r6, r5, r7, r11 \n\t" \ - "adds r4, r4, r6 \n\t" \ - "umull r7, r6, r8, r11 \n\t" \ - "adcs r5, r5, r7 \n\t" \ - "umull r8, r7, r9, r11 \n\t" \ - "adcs r6, r6, r8 \n\t" \ - "umull r9, r8, r10, r11 \n\t" \ - "adcs r7, r7, r9 \n\t" \ - "adcs r8, r8, #0 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r9, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r14, [r0], #4 \n\t" \ - "adds r3, r3, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r4, r4, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r5, r5, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r6, r6, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r7, r7, r14 \n\t" \ - "adcs r8, r8, #0 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "sub r0, #20 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r8, r9, r11, r11 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9} \n\t" - -#define FAST_SQUARE_ASM_6 \ - "push {r2} \n\t" \ - "ldmia r1!, {r2,r3,r4,r5,r6,r7} \n\t" \ - "push {r1} \n\t" \ - \ - "umull r11, r12, r2, r2 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r2, r3 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r11, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r8, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r2, r4 \n\t" \ - "adds r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r3 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r5 \n\t" \ - "umull r1, r14, r3, r4 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r2, r6 \n\t" \ - "umull r1, r14, r3, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "umull r1, r14, r4, r4 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r7 \n\t" \ - "umull r1, r14, r3, r6 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r1, r14, r4, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r3, r7 \n\t" \ - "umull r1, r14, r4, r6 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "umull r1, r14, r5, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r4, r7 \n\t" \ - "umull r1, r14, r5, r6 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r8, #0 \n\t" \ - "umull r1, r10, r5, r7 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "umull r1, r10, r6, r6 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r1, r10, r6, r7 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "adds r12, r12, r1 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r1, r10, r7, r7 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "stmia r0!, {r8, r11} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_6_TO_7 \ - "cmp r2, #6 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r6,r7,r8,r9,r10,r11,r12} \n\t" \ - "umull r3, r4, r6, r12 \n\t" \ - "umull r6, r5, r7, r12 \n\t" \ - "adds r4, r4, r6 \n\t" \ - "umull r7, r6, r8, r12 \n\t" \ - "adcs r5, r5, r7 \n\t" \ - "umull r8, r7, r9, r12 \n\t" \ - "adcs r6, r6, r8 \n\t" \ - "umull r9, r8, r10, r12 \n\t" \ - "adcs r7, r7, r9 \n\t" \ - "umull r10, r9, r11, r12 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r10, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r14, [r0], #4 \n\t" \ - "adds r3, r3, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r4, r4, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r5, r5, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r6, r6, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r7, r7, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r8, r8, r14 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "sub r0, #24 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r9, r10, r12, r12 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10} \n\t" - -#define FAST_SQUARE_ASM_7 \ - "push {r2} \n\t" \ - "ldmia r1!, {r2, r3, r4, r5, r6, r7, r8} \n\t" \ - "push {r1} \n\t" \ - "sub r1, 4 \n\t" \ - \ - "add r0, 24 \n\t" \ - "umull r9, r10, r2, r8 \n\t" \ - "stmia r0!, {r9, r10} \n\t" \ - "sub r0, 32 \n\t" \ - \ - "umull r11, r12, r2, r2 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r2, r3 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r11, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r8, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r2, r4 \n\t" \ - "adds r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r3 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r5 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r3, r4 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r2, r6 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r3, r5 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r4, r4 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r7 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r3, r6 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r4, r5 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "ldmia r1!, {r2} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r3, r7 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r4, r6 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r5, r5 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r3, r2 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r4, r7 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r5, r6 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r4, r2 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r5, r7 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r6, r6 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r5, r2 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r6, r7 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r8, #0 \n\t" \ - "umull r1, r10, r6, r2 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "umull r1, r10, r7, r7 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r1, r10, r7, r2 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "adds r12, r12, r1 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r1, r10, r2, r2 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "stmia r0!, {r8, r11} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_7_TO_8 \ - "cmp r2, #7 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r6,r7,r8,r9,r10,r11,r12,r14} \n\t" \ - "umull r3, r4, r6, r14 \n\t" \ - "umull r6, r5, r7, r14 \n\t" \ - "adds r4, r4, r6 \n\t" \ - "umull r7, r6, r8, r14 \n\t" \ - "adcs r5, r5, r7 \n\t" \ - "umull r8, r7, r9, r14 \n\t" \ - "adcs r6, r6, r8 \n\t" \ - "umull r9, r8, r10, r14 \n\t" \ - "adcs r7, r7, r9 \n\t" \ - "umull r10, r9, r11, r14 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "umull r11, r10, r12, r14 \n\t" \ - "adcs r9, r9, r11 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r11, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r12, [r0], #4 \n\t" \ - "adds r3, r3, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r4, r4, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r5, r5, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r6, r6, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r7, r7, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r8, r8, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "sub r0, #28 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r10, r11, r14, r14 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} \n\t" - -#define FAST_SQUARE_ASM_8 \ - "push {r2} \n\t" \ - "ldmia r1!, {r2,r3,r4,r5,r6,r7,r8,r9} \n\t" \ - "push {r1} \n\t" \ - "sub r1, 8 \n\t" \ - \ - "add r0, 24 \n\t" \ - "umull r10, r11, r2, r8 \n\t" \ - "umull r12, r14, r2, r9 \n\t" \ - "umull r8, r9, r3, r9 \n\t" \ - "adds r11, r11, r12 \n\t" \ - "adcs r12, r14, r8 \n\t" \ - "adcs r14, r9, #0 \n\t" \ - "stmia r0!, {r10, r11, r12, r14} \n\t" \ - "sub r0, 40 \n\t" \ - \ - "umull r11, r12, r2, r2 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r2, r3 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r11, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r8, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r2, r4 \n\t" \ - "adds r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r3 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r5 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r3, r4 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r2, r6 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r3, r5 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r4, r4 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r7 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r3, r6 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r4, r5 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "ldmia r1!, {r2} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r3, r7 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r4, r6 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r5, r5 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r3, r2 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r4, r7 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r5, r6 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r4, r2 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r5, r7 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r6, r6 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r4, r3 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r5, r2 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r6, r7 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r5, r3 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r6, r2 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r7, r7 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r6, r3 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r7, r2 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r8, #0 \n\t" \ - "umull r1, r10, r7, r3 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "umull r1, r10, r2, r2 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r1, r10, r2, r3 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "adds r12, r12, r1 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r1, r10, r3, r3 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "stmia r0!, {r8, r11} \n\t" \ - "pop {r1, r2} \n\t" - -#endif /* _UECC_ASM_ARM_MULT_SQUARE_H_ */ diff --git a/lib/micro-ecc/asm_arm_mult_square_umaal.inc b/lib/micro-ecc/asm_arm_mult_square_umaal.inc deleted file mode 100644 index c554d20e38..0000000000 --- a/lib/micro-ecc/asm_arm_mult_square_umaal.inc +++ /dev/null @@ -1,1202 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_ASM_ARM_MULT_SQUARE_H_ -#define _UECC_ASM_ARM_MULT_SQUARE_H_ - -#define FAST_MULT_ASM_5 \ - "push {r3} \n\t" \ - "ldmia r2!, {r3, r4, r5, r6, r7} \n\t" \ - "push {r2} \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "umull r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "mov r14, #0 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - "str r12, [r0], #4 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "pop {r2, r3} \n\t" - -#define FAST_MULT_ASM_5_TO_6 \ - "cmp r3, #5 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high */ \ - "ldr r4, [r1] \n\t" \ - \ - "sub r0, #20 \n\t" \ - "sub r1, #20 \n\t" \ - "sub r2, #20 \n\t" \ - \ - /* Do right side */ \ - "ldr r14, [r2], #4 \n\t" \ - "mov r5, #0 \n\t" \ - "ldr r6, [r0], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r7, [r0], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r8, [r0], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r9, [r0], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r10, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "sub r0, #20 \n\t" \ - \ - /* r4 = right high */ \ - "ldr r4, [r2], #4 \n\t" \ - \ - /* Do left side */ \ - "ldr r14, [r1], #4 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r12, r5, r4, r14 \n\t" \ - "str r12, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "str r5, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "str r6, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "str r7, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "stmia r0!, {r9, r10} \n\t" - -#define FAST_MULT_ASM_6 \ - "ldmia r2!, {r4, r5, r6} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umull r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - "ldmia r2!, {r4, r5, r6} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" - -#define FAST_MULT_ASM_6_TO_7 \ - "cmp r3, #6 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high */ \ - "ldr r4, [r1] \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - "sub r2, #24 \n\t" \ - \ - /* Do right side */ \ - "ldr r14, [r2], #4 \n\t" \ - "mov r5, #0 \n\t" \ - "ldr r6, [r0], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r7, [r0], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r8, [r0], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r9, [r0], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r10, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r11, [r0], #4 \n\t" \ - "umaal r10, r11, r4, r14 \n\t" \ - "sub r0, #24 \n\t" \ - \ - /* r4 = right high */ \ - "ldr r4, [r2], #4 \n\t" \ - \ - /* Do left side */ \ - "ldr r14, [r1], #4 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r12, r5, r4, r14 \n\t" \ - "str r12, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "str r5, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "str r6, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "str r7, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r10, r11, r4, r14 \n\t" \ - "stmia r0!, {r10, r11} \n\t" - -#define FAST_MULT_ASM_7 \ - "ldmia r2!, {r4, r5, r6, r7} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umull r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - "str r12, [r0], #4 \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - "ldmia r2!, {r4, r5, r6} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" - -#define FAST_MULT_ASM_7_TO_8 \ - "cmp r3, #7 \n\t" \ - "beq 1f \n\t" \ - "push {r3} \n\t" \ - \ - /* r4 = left high */ \ - "ldr r4, [r1] \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - "sub r2, #28 \n\t" \ - \ - /* Do right side */ \ - "ldr r14, [r2], #4 \n\t" \ - "mov r5, #0 \n\t" \ - "ldr r6, [r0], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r7, [r0], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r8, [r0], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r9, [r0], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r10, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r11, [r0], #4 \n\t" \ - "umaal r10, r11, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "umaal r11, r12, r4, r14 \n\t" \ - "sub r0, #28 \n\t" \ - \ - /* r4 = right high */ \ - "ldr r4, [r2], #4 \n\t" \ - \ - /* Do left side */ \ - "ldr r14, [r1], #4 \n\t" \ - "mov r3, #0 \n\t" \ - "umaal r3, r5, r4, r14 \n\t" \ - "str r3, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "str r5, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "str r6, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "str r7, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "str r9, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r10, r11, r4, r14 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r11, r12, r4, r14 \n\t" \ - "stmia r0!, {r11, r12} \n\t" \ - "pop {r3} \n\t" - -#define FAST_MULT_ASM_8 \ - "ldmia r2!, {r4, r5, r6, r7} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umull r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - "str r12, [r0], #4 \n\t" \ - \ - "sub r0, #32 \n\t" \ - "sub r1, #32 \n\t" \ - "ldmia r2!, {r4, r5, r6, r7} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - "str r12, [r0], #4 \n\t" - -#define FAST_SQUARE_ASM_5 \ - "ldmia r1!, {r9,r10,r11,r12,r14} \n\t" \ - "push {r1, r2} \n\t" \ - \ - "umull r1, r2, r10, r9 \n\t" \ - "mov r3, #0 \n\t" \ - "umaal r2, r3, r11, r9 \n\t" \ - "mov r4, #0 \n\t" \ - "umaal r3, r4, r12, r9 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r14, r9 \n\t" \ - \ - "mov r6, #0 \n\t" \ - "umaal r6, r3, r11, r10 \n\t" \ - "umaal r3, r4, r12, r10 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - \ - "umull r7, r8, r9, r9 \n\t" \ - /* Store carry in r9 */ \ - "mov r9, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "stmia r0!, {r7,r8} \n\t" \ - \ - "umull r7, r8, r10, r10 \n\t" \ - "adcs r7, r7, r2 \n\t" \ - "adcs r8, r8, r6 \n\t" \ - "stmia r0!, {r7,r8} \n\t" \ - \ - "umaal r4, r5, r14, r10 \n\t" \ - /* Store carry in r10 */ \ - "mov r10, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - \ - "mov r1, #0 \n\t" \ - "umaal r1, r4, r12, r11 \n\t" \ - "umaal r4, r5, r14, r11 \n\t" \ - \ - "mov r2, #0 \n\t" \ - "umaal r2, r5, r14, r12 \n\t" \ - /* Load carry from r9 */ \ - "lsrs r9, #1 \n\t" \ - "adcs r1, r1, r1 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - /* r9 is 0 now */ \ - "adc r9, r9, #0 \n\t" \ - \ - /* Use carry from r10 */ \ - "umaal r3, r10, r11, r11 \n\t" \ - "adds r10, r10, r1 \n\t" \ - "stmia r0!, {r3,r10} \n\t" \ - \ - "umull r6, r10, r12, r12 \n\t" \ - "adcs r6, r6, r4 \n\t" \ - "adcs r10, r10, r2 \n\t" \ - "stmia r0!, {r6,r10} \n\t" \ - \ - "umull r6, r10, r14, r14 \n\t" \ - "adcs r6, r6, r5 \n\t" \ - "adcs r10, r10, r9 \n\t" \ - "stmia r0!, {r6,r10} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_5_TO_6 \ - "cmp r2, #5 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #20 \n\t" \ - "sub r1, #20 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r5,r6,r7,r8,r9,r14} \n\t" \ - "umull r3, r4, r5, r14 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r6, r14 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r7, r14 \n\t" \ - "mov r7, #0 \n\t" \ - "umaal r6, r7, r8, r14 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r7, r8, r9, r14 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r9, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r12, [r0], #4 \n\t" \ - "adds r3, r3, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r4, r4, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r5, r5, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r6, r6, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r7, r7, r12 \n\t" \ - "adcs r8, r8, #0 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "sub r0, #20 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r8, r9, r14, r14 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9} \n\t" - -#define FAST_SQUARE_ASM_6 \ - "ldmia r1!, {r8,r9,r10,r11,r12,r14} \n\t" \ - "push {r1, r2} \n\t" \ - \ - "umull r1, r2, r9, r8 \n\t" \ - "mov r3, #0 \n\t" \ - "umaal r2, r3, r10, r8 \n\t" \ - "mov r4, #0 \n\t" \ - "umaal r3, r4, r11, r8 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r12, r8 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r14, r8 \n\t" \ - \ - "mov r7, #0 \n\t" \ - "umaal r7, r3, r10, r9 \n\t" \ - "umaal r3, r4, r11, r9 \n\t" \ - "umaal r4, r5, r12, r9 \n\t" \ - "push {r4, r5} \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - \ - "umull r4, r5, r8, r8 \n\t" \ - /* Store carry in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r5, r5, r1 \n\t" \ - "stmia r0!, {r4,r5} \n\t" \ - \ - "umull r4, r5, r9, r9 \n\t" \ - "adcs r4, r4, r2 \n\t" \ - "adcs r5, r5, r7 \n\t" \ - "stmia r0!, {r4,r5} \n\t" \ - \ - "pop {r4, r5} \n\t" \ - "umaal r5, r6, r14, r9 \n\t" \ - /* Store carry in r9 */ \ - "mov r9, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - \ - "mov r1, #0 \n\t" \ - "umaal r1, r4, r11, r10 \n\t" \ - "umaal r4, r5, r12, r10 \n\t" \ - "umaal r5, r6, r14, r10 \n\t" \ - \ - "mov r2, #0 \n\t" \ - "umaal r2, r5, r12, r11 \n\t" \ - "umaal r5, r6, r14, r11 \n\t" \ - \ - "mov r7, #0 \n\t" \ - "umaal r7, r6, r14, r12 \n\t" \ - \ - /* Load carry from r8 */ \ - "lsrs r8, #1 \n\t" \ - "adcs r1, r1, r1 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - /* Use carry from r9 */ \ - "umaal r3, r9, r10, r10 \n\t" \ - "adds r9, r9, r1 \n\t" \ - "stmia r0!, {r3,r9} \n\t" \ - \ - "umull r9, r10, r11, r11 \n\t" \ - "adcs r9, r9, r4 \n\t" \ - "adcs r10, r10, r2 \n\t" \ - "stmia r0!, {r9,r10} \n\t" \ - \ - "umull r9, r10, r12, r12 \n\t" \ - "adcs r9, r9, r5 \n\t" \ - "adcs r10, r10, r7 \n\t" \ - "stmia r0!, {r9,r10} \n\t" \ - \ - "umull r9, r10, r14, r14 \n\t" \ - "adcs r9, r9, r6 \n\t" \ - "adcs r10, r10, r8 \n\t" \ - "stmia r0!, {r9,r10} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_6_TO_7 \ - "cmp r2, #6 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r5,r6,r7,r8,r9,r10,r14} \n\t" \ - "umull r3, r4, r5, r14 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r6, r14 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r7, r14 \n\t" \ - "mov r7, #0 \n\t" \ - "umaal r6, r7, r8, r14 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r7, r8, r9, r14 \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r10, r14 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r10, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r12, [r0], #4 \n\t" \ - "adds r3, r3, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r4, r4, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r5, r5, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r6, r6, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r7, r7, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r8, r8, r12 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "sub r0, #24 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r9, r10, r14, r14 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10} \n\t" - -#define FAST_SQUARE_ASM_7 \ - "ldmia r1!, {r9,r10,r11,r12} \n\t" \ - "push {r2} \n\t" \ - \ - "umull r14, r2, r10, r9 \n\t" \ - "mov r3, #0 \n\t" \ - "umaal r2, r3, r11, r9 \n\t" \ - "mov r4, #0 \n\t" \ - "umaal r3, r4, r12, r9 \n\t" \ - \ - "mov r5, #0 \n\t" \ - "umaal r5, r3, r11, r10 \n\t" \ - "adds r14, r14, r14 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - /* Store carry in r7 */ \ - "mov r7, #0 \n\t" \ - "adc r7, r7, #0 \n\t" \ - \ - "umull r6, r8, r9, r9 \n\t" \ - "adds r8, r8, r14 \n\t" \ - "stmia r0!, {r6,r8} \n\t" \ - \ - "umull r6, r8, r10, r10 \n\t" \ - "adcs r6, r6, r2 \n\t" \ - "adcs r8, r8, r5 \n\t" \ - "stmia r0!, {r6,r8} \n\t" \ - /* Store carry in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "ldmia r1!, {r2, r6, r14} \n\t" \ - "push {r1} \n\t" \ - "umaal r3, r4, r2, r9 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r6, r9 \n\t" \ - "mov r1, #0 \n\t" \ - "umaal r5, r1, r14, r9 \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umaal r3, r9, r12, r10 \n\t" \ - "umaal r9, r4, r2, r10 \n\t" \ - "umaal r4, r5, r6, r10 \n\t" \ - "umaal r5, r1, r14, r10 \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umaal r10, r9, r12, r11 \n\t" \ - "umaal r9, r4, r2, r11 \n\t" \ - "umaal r4, r5, r6, r11 \n\t" \ - "umaal r5, r1, r14, r11 \n\t" \ - \ - /* Load carry from r7 */ \ - "lsrs r7, #1 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - /* Store carry back in r7 */ \ - "adc r7, r7, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r3, r8, r11, r11 \n\t" \ - "adds r8, r8, r10 \n\t" \ - "stmia r0!, {r3,r8} \n\t" \ - /* Store carry back in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "mov r3, #0 \n\t" \ - "umaal r3, r4, r2, r12 \n\t" \ - "umaal r4, r5, r6, r12 \n\t" \ - "umaal r5, r1, r14, r12 \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umaal r10, r5, r6, r2 \n\t" \ - "umaal r5, r1, r14, r2 \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umaal r11, r1, r14, r6 \n\t" \ - \ - /* Load carry from r7 */ \ - "lsrs r7, #1 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adcs r1, r1, r1 \n\t" \ - "adc r7, r7, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r8, r9, r12, r12 \n\t" \ - "adds r9, r9, r3 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - \ - "umull r8, r9, r2, r2 \n\t" \ - "adcs r8, r8, r4 \n\t" \ - "adcs r9, r9, r10 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - \ - "umull r8, r9, r6, r6 \n\t" \ - "adcs r8, r8, r5 \n\t" \ - "adcs r9, r9, r11 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - \ - "umull r8, r9, r14, r14 \n\t" \ - "adcs r8, r8, r1 \n\t" \ - "adcs r9, r9, r7 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_7_TO_8 \ - "cmp r2, #7 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r5,r6,r7,r8,r9,r10,r11,r14} \n\t" \ - "umull r3, r4, r5, r14 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r6, r14 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r7, r14 \n\t" \ - "mov r7, #0 \n\t" \ - "umaal r6, r7, r8, r14 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r7, r8, r9, r14 \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r10, r14 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r11, r14 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r11, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r12, [r0], #4 \n\t" \ - "adds r3, r3, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r4, r4, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r5, r5, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r6, r6, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r7, r7, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r8, r8, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "sub r0, #28 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r10, r11, r14, r14 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} \n\t" - -#define FAST_SQUARE_ASM_8 \ - "ldmia r1!, {r10,r11,r12,r14} \n\t" \ - "push {r2} \n\t" \ - \ - "umull r2, r3, r11, r10 \n\t" \ - "mov r4, #0 \n\t" \ - "umaal r3, r4, r12, r10 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r14, r10 \n\t" \ - \ - "mov r6, #0 \n\t" \ - "umaal r6, r4, r12, r11 \n\t" \ - "adds r2, r2, r2 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - /* Store carry in r7 */ \ - "mov r7, #0 \n\t" \ - "adc r7, r7, #0 \n\t" \ - \ - "umull r8, r9, r10, r10 \n\t" \ - "adds r9, r9, r2 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - \ - "umull r8, r9, r11, r11 \n\t" \ - "adcs r8, r8, r3 \n\t" \ - "adcs r9, r9, r6 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - /* Store carry in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "ldmia r1!, {r2, r3} \n\t" \ - "push {r1} \n\t" \ - "umaal r4, r5, r2, r10 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r3, r10 \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umaal r9, r4, r14, r11 \n\t" \ - "umaal r4, r5, r2, r11 \n\t" \ - \ - "mov r1, #0 \n\t" \ - "umaal r1, r4, r14, r12 \n\t" \ - \ - /* Load carry from r7 */ \ - "lsrs r7, #1 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r1, r1, r1 \n\t" \ - /* Store carry back in r7 */ \ - "adc r7, r7, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r8, r9, r12, r12 \n\t" \ - "adds r9, r9, r1 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - /* Store carry back in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "pop {r1} \n\t" \ - /* TODO could fix up r1 value on stack here */ \ - /* and leave the value on the stack (rather */ \ - /* than popping) if supporting curves > 256 bits */ \ - "ldr r9, [r1], #4 \n\t" \ - "ldr r1, [r1] \n\t" \ - \ - "push {r7} \n\t" \ - "umaal r5, r6, r9, r10 \n\t" \ - "mov r7, #0 \n\t" \ - "umaal r6, r7, r1, r10 \n\t" \ - /* Carry now stored in r10 */ \ - "pop {r10} \n\t" \ - \ - "umaal r4, r5, r3, r11 \n\t" \ - "umaal r5, r6, r9, r11 \n\t" \ - "umaal r6, r7, r1, r11 \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umaal r11, r4, r2, r12 \n\t" \ - "umaal r4, r5, r3, r12 \n\t" \ - "umaal r5, r6, r9, r12 \n\t" \ - "umaal r6, r7, r1, r12 \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umaal r12, r4, r2, r14 \n\t" \ - "umaal r4, r5, r3, r14 \n\t" \ - "umaal r5, r6, r9, r14 \n\t" \ - "umaal r6, r7, r1, r14 \n\t" \ - \ - /* Load carry from r10 */ \ - "lsrs r10, #1 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r8, r11, r14, r14 \n\t" \ - "adds r11, r11, r12 \n\t" \ - "stmia r0!, {r8,r11} \n\t" \ - /* Store carry back in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umaal r11, r5, r3, r2 \n\t" \ - "umaal r5, r6, r9, r2 \n\t" \ - "umaal r6, r7, r1, r2 \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umaal r12, r6, r9, r3 \n\t" \ - "umaal r6, r7, r1, r3 \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umaal r14, r7, r1, r9 \n\t" \ - \ - /* Load carry from r10 */ \ - "lsrs r10, #1 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r14, r14, r14 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adc r10, r10, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r4, r8, r2, r2 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "stmia r0!, {r4,r8} \n\t" \ - \ - "umull r4, r8, r3, r3 \n\t" \ - "adcs r4, r4, r5 \n\t" \ - "adcs r8, r8, r12 \n\t" \ - "stmia r0!, {r4,r8} \n\t" \ - \ - "umull r4, r8, r9, r9 \n\t" \ - "adcs r4, r4, r6 \n\t" \ - "adcs r8, r8, r14 \n\t" \ - "stmia r0!, {r4,r8} \n\t" \ - \ - "umull r4, r8, r1, r1 \n\t" \ - "adcs r4, r4, r7 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "stmia r0!, {r4,r8} \n\t" \ - /* TODO pop {r1, r2} if supporting curves > 256 bits */ \ - "pop {r2} \n\t" - -#endif /* _UECC_ASM_ARM_MULT_SQUARE_H_ */ diff --git a/lib/micro-ecc/curve-specific.inc b/lib/micro-ecc/curve-specific.inc deleted file mode 100644 index f5d3da842c..0000000000 --- a/lib/micro-ecc/curve-specific.inc +++ /dev/null @@ -1,1249 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_CURVE_SPECIFIC_H_ -#define _UECC_CURVE_SPECIFIC_H_ - -#define num_bytes_secp160r1 20 -#define num_bytes_secp192r1 24 -#define num_bytes_secp224r1 28 -#define num_bytes_secp256r1 32 -#define num_bytes_secp256k1 32 - -#if (uECC_WORD_SIZE == 1) - -#define num_words_secp160r1 20 -#define num_words_secp192r1 24 -#define num_words_secp224r1 28 -#define num_words_secp256r1 32 -#define num_words_secp256k1 32 - -#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) \ - 0x##a, 0x##b, 0x##c, 0x##d, 0x##e, 0x##f, 0x##g, 0x##h -#define BYTES_TO_WORDS_4(a, b, c, d) 0x##a, 0x##b, 0x##c, 0x##d - -#elif (uECC_WORD_SIZE == 4) - -#define num_words_secp160r1 5 -#define num_words_secp192r1 6 -#define num_words_secp224r1 7 -#define num_words_secp256r1 8 -#define num_words_secp256k1 8 - -#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e -#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a - -#elif (uECC_WORD_SIZE == 8) - -#define num_words_secp160r1 3 -#define num_words_secp192r1 3 -#define num_words_secp224r1 4 -#define num_words_secp256r1 4 -#define num_words_secp256k1 4 - -#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##h##g##f##e##d##c##b##a##ull -#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a##ull - -#endif /* uECC_WORD_SIZE */ - -#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \ - uECC_SUPPORTS_secp224r1 || uECC_SUPPORTS_secp256r1 -static void double_jacobian_default(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * Z1, - uECC_Curve curve) { - /* t1 = X, t2 = Y, t3 = Z */ - uECC_word_t t4[uECC_MAX_WORDS]; - uECC_word_t t5[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - - if (uECC_vli_isZero(Z1, num_words)) { - return; - } - - uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */ - uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */ - uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */ - uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */ - uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */ - - uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ - uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */ - uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */ - uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */ - - uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */ - uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */ - if (uECC_vli_testBit(X1, 0)) { - uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); - uECC_vli_rshift1(X1, num_words); - X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1); - } else { - uECC_vli_rshift1(X1, num_words); - } - /* t1 = 3/2*(x1^2 - z1^4) = B */ - - uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */ - uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */ - uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */ - uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */ - uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */ - uECC_vli_modSub(t4, X1, t4, curve->p, num_words); /* t4 = B * (A - x3) - y1^4 = y3 */ - - uECC_vli_set(X1, Z1, num_words); - uECC_vli_set(Z1, Y1, num_words); - uECC_vli_set(Y1, t4, num_words); -} - -/* Computes result = x^3 + ax + b. result must not overlap x. */ -static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { - uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */ - wordcount_t num_words = curve->num_words; - - uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ - uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ - uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */ - uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); /* r = x^3 - 3x + b */ -} -#endif /* uECC_SUPPORTS_secp... */ - -#if uECC_SUPPORT_COMPRESSED_POINT -#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \ - uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1 -/* Compute a = sqrt(a) (mod curve_p). */ -static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) { - bitcount_t i; - uECC_word_t p1[uECC_MAX_WORDS] = {1}; - uECC_word_t l_result[uECC_MAX_WORDS] = {1}; - wordcount_t num_words = curve->num_words; - - /* When curve->p == 3 (mod 4), we can compute - sqrt(a) = a^((curve->p + 1) / 4) (mod curve->p). */ - uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */ - for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) { - uECC_vli_modSquare_fast(l_result, l_result, curve); - if (uECC_vli_testBit(p1, i)) { - uECC_vli_modMult_fast(l_result, l_result, a, curve); - } - } - uECC_vli_set(a, l_result, num_words); -} -#endif /* uECC_SUPPORTS_secp... */ -#endif /* uECC_SUPPORT_COMPRESSED_POINT */ - -#if uECC_SUPPORTS_secp160r1 - -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp160r1 = { - num_words_secp160r1, - num_bytes_secp160r1, - 161, /* num_n_bits */ - { BYTES_TO_WORDS_8(FF, FF, FF, 7F, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_4(FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(57, 22, 75, CA, D3, AE, 27, F9), - BYTES_TO_WORDS_8(C8, F4, 01, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 01, 00, 00, 00) }, - { BYTES_TO_WORDS_8(82, FC, CB, 13, B9, 8B, C3, 68), - BYTES_TO_WORDS_8(89, 69, 64, 46, 28, 73, F5, 8E), - BYTES_TO_WORDS_4(68, B5, 96, 4A), - - BYTES_TO_WORDS_8(32, FB, C5, 7A, 37, 51, 23, 04), - BYTES_TO_WORDS_8(12, C9, DC, 59, 7D, 94, 68, 31), - BYTES_TO_WORDS_4(55, 28, A6, 23) }, - { BYTES_TO_WORDS_8(45, FA, 65, C5, AD, D4, D4, 81), - BYTES_TO_WORDS_8(9F, F8, AC, 65, 8B, 7A, BD, 54), - BYTES_TO_WORDS_4(FC, BE, 97, 1C) }, - &double_jacobian_default, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_default, -#endif - &x_side_default, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp160r1 -#endif -}; - -uECC_Curve uECC_secp160r1(void) { return &curve_secp160r1; } - -#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) -/* Computes result = product % curve_p - see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354 - - Note that this only works if log2(omega) < log2(p) / 2 */ -static void omega_mult_secp160r1(uECC_word_t *result, const uECC_word_t *right); -#if uECC_WORD_SIZE == 8 -static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) { - uECC_word_t tmp[2 * num_words_secp160r1]; - uECC_word_t copy; - - uECC_vli_clear(tmp, num_words_secp160r1); - uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1); - - omega_mult_secp160r1(tmp, product + num_words_secp160r1 - 1); /* (Rq, q) = q * c */ - - product[num_words_secp160r1 - 1] &= 0xffffffff; - copy = tmp[num_words_secp160r1 - 1]; - tmp[num_words_secp160r1 - 1] &= 0xffffffff; - uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */ - uECC_vli_clear(product, num_words_secp160r1); - tmp[num_words_secp160r1 - 1] = copy; - omega_mult_secp160r1(product, tmp + num_words_secp160r1 - 1); /* Rq*c */ - uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */ - - while (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) { - uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); - } -} - -static void omega_mult_secp160r1(uint64_t *result, const uint64_t *right) { - uint32_t carry; - unsigned i; - - /* Multiply by (2^31 + 1). */ - carry = 0; - for (i = 0; i < num_words_secp160r1; ++i) { - uint64_t tmp = (right[i] >> 32) | (right[i + 1] << 32); - result[i] = (tmp << 31) + tmp + carry; - carry = (tmp >> 33) + (result[i] < tmp || (carry && result[i] == tmp)); - } - result[i] = carry; -} -#else -static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) { - uECC_word_t tmp[2 * num_words_secp160r1]; - uECC_word_t carry; - - uECC_vli_clear(tmp, num_words_secp160r1); - uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1); - - omega_mult_secp160r1(tmp, product + num_words_secp160r1); /* (Rq, q) = q * c */ - - carry = uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */ - uECC_vli_clear(product, num_words_secp160r1); - omega_mult_secp160r1(product, tmp + num_words_secp160r1); /* Rq*c */ - carry += uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */ - - while (carry > 0) { - --carry; - uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); - } - if (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) { - uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); - } -} -#endif - -#if uECC_WORD_SIZE == 1 -static void omega_mult_secp160r1(uint8_t *result, const uint8_t *right) { - uint8_t carry; - uint8_t i; - - /* Multiply by (2^31 + 1). */ - uECC_vli_set(result + 4, right, num_words_secp160r1); /* 2^32 */ - uECC_vli_rshift1(result + 4, num_words_secp160r1); /* 2^31 */ - result[3] = right[0] << 7; /* get last bit from shift */ - - carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */ - for (i = num_words_secp160r1; carry; ++i) { - uint16_t sum = (uint16_t)result[i] + carry; - result[i] = (uint8_t)sum; - carry = sum >> 8; - } -} -#elif uECC_WORD_SIZE == 4 -static void omega_mult_secp160r1(uint32_t *result, const uint32_t *right) { - uint32_t carry; - unsigned i; - - /* Multiply by (2^31 + 1). */ - uECC_vli_set(result + 1, right, num_words_secp160r1); /* 2^32 */ - uECC_vli_rshift1(result + 1, num_words_secp160r1); /* 2^31 */ - result[0] = right[0] << 31; /* get last bit from shift */ - - carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */ - for (i = num_words_secp160r1; carry; ++i) { - uint64_t sum = (uint64_t)result[i] + carry; - result[i] = (uint32_t)sum; - carry = sum >> 32; - } -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) */ - -#endif /* uECC_SUPPORTS_secp160r1 */ - -#if uECC_SUPPORTS_secp192r1 - -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp192r1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp192r1 = { - num_words_secp192r1, - num_bytes_secp192r1, - 192, /* num_n_bits */ - { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(31, 28, D2, B4, B1, C9, 6B, 14), - BYTES_TO_WORDS_8(36, F8, DE, 99, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(12, 10, FF, 82, FD, 0A, FF, F4), - BYTES_TO_WORDS_8(00, 88, A1, 43, EB, 20, BF, 7C), - BYTES_TO_WORDS_8(F6, 90, 30, B0, 0E, A8, 8D, 18), - - BYTES_TO_WORDS_8(11, 48, 79, 1E, A1, 77, F9, 73), - BYTES_TO_WORDS_8(D5, CD, 24, 6B, ED, 11, 10, 63), - BYTES_TO_WORDS_8(78, DA, C8, FF, 95, 2B, 19, 07) }, - { BYTES_TO_WORDS_8(B1, B9, 46, C1, EC, DE, B8, FE), - BYTES_TO_WORDS_8(49, 30, 24, 72, AB, E9, A7, 0F), - BYTES_TO_WORDS_8(E7, 80, 9C, E5, 19, 05, 21, 64) }, - &double_jacobian_default, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_default, -#endif - &x_side_default, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp192r1 -#endif -}; - -uECC_Curve uECC_secp192r1(void) { return &curve_secp192r1; } - -#if (uECC_OPTIMIZATION_LEVEL > 0) -/* Computes result = product % curve_p. - See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */ -#if uECC_WORD_SIZE == 1 -static void vli_mmod_fast_secp192r1(uint8_t *result, uint8_t *product) { - uint8_t tmp[num_words_secp192r1]; - uint8_t carry; - - uECC_vli_set(result, product, num_words_secp192r1); - - uECC_vli_set(tmp, &product[24], num_words_secp192r1); - carry = uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; - tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27]; - tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31]; - tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35]; - tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39]; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[8] = product[40]; - tmp[1] = tmp[9] = product[41]; - tmp[2] = tmp[10] = product[42]; - tmp[3] = tmp[11] = product[43]; - tmp[4] = tmp[12] = product[44]; - tmp[5] = tmp[13] = product[45]; - tmp[6] = tmp[14] = product[46]; - tmp[7] = tmp[15] = product[47]; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); - } -} -#elif uECC_WORD_SIZE == 4 -static void vli_mmod_fast_secp192r1(uint32_t *result, uint32_t *product) { - uint32_t tmp[num_words_secp192r1]; - int carry; - - uECC_vli_set(result, product, num_words_secp192r1); - - uECC_vli_set(tmp, &product[6], num_words_secp192r1); - carry = uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[1] = 0; - tmp[2] = product[6]; - tmp[3] = product[7]; - tmp[4] = product[8]; - tmp[5] = product[9]; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[2] = product[10]; - tmp[1] = tmp[3] = product[11]; - tmp[4] = tmp[5] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); - } -} -#else -static void vli_mmod_fast_secp192r1(uint64_t *result, uint64_t *product) { - uint64_t tmp[num_words_secp192r1]; - int carry; - - uECC_vli_set(result, product, num_words_secp192r1); - - uECC_vli_set(tmp, &product[3], num_words_secp192r1); - carry = (int)uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = 0; - tmp[1] = product[3]; - tmp[2] = product[4]; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[1] = product[5]; - tmp[2] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); - } -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */ - -#endif /* uECC_SUPPORTS_secp192r1 */ - -#if uECC_SUPPORTS_secp224r1 - -#if uECC_SUPPORT_COMPRESSED_POINT -static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve); -#endif -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp224r1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp224r1 = { - num_words_secp224r1, - num_bytes_secp224r1, - 224, /* num_n_bits */ - { BYTES_TO_WORDS_8(01, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_4(FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(3D, 2A, 5C, 5C, 45, 29, DD, 13), - BYTES_TO_WORDS_8(3E, F0, B8, E0, A2, 16, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_4(FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(21, 1D, 5C, 11, D6, 80, 32, 34), - BYTES_TO_WORDS_8(22, 11, C2, 56, D3, C1, 03, 4A), - BYTES_TO_WORDS_8(B9, 90, 13, 32, 7F, BF, B4, 6B), - BYTES_TO_WORDS_4(BD, 0C, 0E, B7), - - BYTES_TO_WORDS_8(34, 7E, 00, 85, 99, 81, D5, 44), - BYTES_TO_WORDS_8(64, 47, 07, 5A, A0, 75, 43, CD), - BYTES_TO_WORDS_8(E6, DF, 22, 4C, FB, 23, F7, B5), - BYTES_TO_WORDS_4(88, 63, 37, BD) }, - { BYTES_TO_WORDS_8(B4, FF, 55, 23, 43, 39, 0B, 27), - BYTES_TO_WORDS_8(BA, D8, BF, D7, B7, B0, 44, 50), - BYTES_TO_WORDS_8(56, 32, 41, F5, AB, B3, 04, 0C), - BYTES_TO_WORDS_4(85, 0A, 05, B4) }, - &double_jacobian_default, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_secp224r1, -#endif - &x_side_default, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp224r1 -#endif -}; - -uECC_Curve uECC_secp224r1(void) { return &curve_secp224r1; } - - -#if uECC_SUPPORT_COMPRESSED_POINT -/* Routine 3.2.4 RS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1_rs(uECC_word_t *d1, - uECC_word_t *e1, - uECC_word_t *f1, - const uECC_word_t *d0, - const uECC_word_t *e0, - const uECC_word_t *f0) { - uECC_word_t t[num_words_secp224r1]; - - uECC_vli_modSquare_fast(t, d0, &curve_secp224r1); /* t <-- d0 ^ 2 */ - uECC_vli_modMult_fast(e1, d0, e0, &curve_secp224r1); /* e1 <-- d0 * e0 */ - uECC_vli_modAdd(d1, t, f0, curve_secp224r1.p, num_words_secp224r1); /* d1 <-- t + f0 */ - uECC_vli_modAdd(e1, e1, e1, curve_secp224r1.p, num_words_secp224r1); /* e1 <-- e1 + e1 */ - uECC_vli_modMult_fast(f1, t, f0, &curve_secp224r1); /* f1 <-- t * f0 */ - uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */ - uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */ -} - -/* Routine 3.2.5 RSS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1_rss(uECC_word_t *d1, - uECC_word_t *e1, - uECC_word_t *f1, - const uECC_word_t *d0, - const uECC_word_t *e0, - const uECC_word_t *f0, - const bitcount_t j) { - bitcount_t i; - - uECC_vli_set(d1, d0, num_words_secp224r1); /* d1 <-- d0 */ - uECC_vli_set(e1, e0, num_words_secp224r1); /* e1 <-- e0 */ - uECC_vli_set(f1, f0, num_words_secp224r1); /* f1 <-- f0 */ - for (i = 1; i <= j; i++) { - mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */ - } -} - -/* Routine 3.2.6 RM; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1_rm(uECC_word_t *d2, - uECC_word_t *e2, - uECC_word_t *f2, - const uECC_word_t *c, - const uECC_word_t *d0, - const uECC_word_t *e0, - const uECC_word_t *d1, - const uECC_word_t *e1) { - uECC_word_t t1[num_words_secp224r1]; - uECC_word_t t2[num_words_secp224r1]; - - uECC_vli_modMult_fast(t1, e0, e1, &curve_secp224r1); /* t1 <-- e0 * e1 */ - uECC_vli_modMult_fast(t1, t1, c, &curve_secp224r1); /* t1 <-- t1 * c */ - /* t1 <-- p - t1 */ - uECC_vli_modSub(t1, curve_secp224r1.p, t1, curve_secp224r1.p, num_words_secp224r1); - uECC_vli_modMult_fast(t2, d0, d1, &curve_secp224r1); /* t2 <-- d0 * d1 */ - uECC_vli_modAdd(t2, t2, t1, curve_secp224r1.p, num_words_secp224r1); /* t2 <-- t2 + t1 */ - uECC_vli_modMult_fast(t1, d0, e1, &curve_secp224r1); /* t1 <-- d0 * e1 */ - uECC_vli_modMult_fast(e2, d1, e0, &curve_secp224r1); /* e2 <-- d1 * e0 */ - uECC_vli_modAdd(e2, e2, t1, curve_secp224r1.p, num_words_secp224r1); /* e2 <-- e2 + t1 */ - uECC_vli_modSquare_fast(f2, e2, &curve_secp224r1); /* f2 <-- e2^2 */ - uECC_vli_modMult_fast(f2, f2, c, &curve_secp224r1); /* f2 <-- f2 * c */ - /* f2 <-- p - f2 */ - uECC_vli_modSub(f2, curve_secp224r1.p, f2, curve_secp224r1.p, num_words_secp224r1); - uECC_vli_set(d2, t2, num_words_secp224r1); /* d2 <-- t2 */ -} - -/* Routine 3.2.7 RP; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1_rp(uECC_word_t *d1, - uECC_word_t *e1, - uECC_word_t *f1, - const uECC_word_t *c, - const uECC_word_t *r) { - wordcount_t i; - wordcount_t pow2i = 1; - uECC_word_t d0[num_words_secp224r1]; - uECC_word_t e0[num_words_secp224r1] = {1}; /* e0 <-- 1 */ - uECC_word_t f0[num_words_secp224r1]; - - uECC_vli_set(d0, r, num_words_secp224r1); /* d0 <-- r */ - /* f0 <-- p - c */ - uECC_vli_modSub(f0, curve_secp224r1.p, c, curve_secp224r1.p, num_words_secp224r1); - for (i = 0; i <= 6; i++) { - mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */ - mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, e0); /* RM (d1,e1,f1,c,d1,e1,d0,e0) */ - uECC_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */ - uECC_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */ - uECC_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */ - pow2i *= 2; - } -} - -/* Compute a = sqrt(a) (mod curve_p). */ -/* Routine 3.2.8 mp_mod_sqrt_224; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) { - (void)curve; - bitcount_t i; - uECC_word_t e1[num_words_secp224r1]; - uECC_word_t f1[num_words_secp224r1]; - uECC_word_t d0[num_words_secp224r1]; - uECC_word_t e0[num_words_secp224r1]; - uECC_word_t f0[num_words_secp224r1]; - uECC_word_t d1[num_words_secp224r1]; - - /* s = a; using constant instead of random value */ - mod_sqrt_secp224r1_rp(d0, e0, f0, a, a); /* RP (d0, e0, f0, c, s) */ - mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */ - for (i = 1; i <= 95; i++) { - uECC_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */ - uECC_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */ - uECC_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */ - mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */ - if (uECC_vli_isZero(d1, num_words_secp224r1)) { /* if d1 == 0 */ - break; - } - } - uECC_vli_modInv(f1, e0, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- 1 / e0 */ - uECC_vli_modMult_fast(a, d0, f1, &curve_secp224r1); /* a <-- d0 / e0 */ -} -#endif /* uECC_SUPPORT_COMPRESSED_POINT */ - -#if (uECC_OPTIMIZATION_LEVEL > 0) -/* Computes result = product % curve_p - from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -#if uECC_WORD_SIZE == 1 -static void vli_mmod_fast_secp224r1(uint8_t *result, uint8_t *product) { - uint8_t tmp[num_words_secp224r1]; - int8_t carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp224r1); - - /* s1 */ - tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; - tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; - tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; - tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31]; - tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35]; - tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39]; - tmp[24] = product[40]; tmp[25] = product[41]; tmp[26] = product[42]; tmp[27] = product[43]; - carry = uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* s2 */ - tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47]; - tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51]; - tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55]; - tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* d1 */ - tmp[0] = product[28]; tmp[1] = product[29]; tmp[2] = product[30]; tmp[3] = product[31]; - tmp[4] = product[32]; tmp[5] = product[33]; tmp[6] = product[34]; tmp[7] = product[35]; - tmp[8] = product[36]; tmp[9] = product[37]; tmp[10] = product[38]; tmp[11] = product[39]; - tmp[12] = product[40]; tmp[13] = product[41]; tmp[14] = product[42]; tmp[15] = product[43]; - tmp[16] = product[44]; tmp[17] = product[45]; tmp[18] = product[46]; tmp[19] = product[47]; - tmp[20] = product[48]; tmp[21] = product[49]; tmp[22] = product[50]; tmp[23] = product[51]; - tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - /* d2 */ - tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47]; - tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51]; - tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55]; - tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; - tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); - } - } -} -#elif uECC_WORD_SIZE == 4 -static void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product) -{ - uint32_t tmp[num_words_secp224r1]; - int carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp224r1); - - /* s1 */ - tmp[0] = tmp[1] = tmp[2] = 0; - tmp[3] = product[7]; - tmp[4] = product[8]; - tmp[5] = product[9]; - tmp[6] = product[10]; - carry = uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* s2 */ - tmp[3] = product[11]; - tmp[4] = product[12]; - tmp[5] = product[13]; - tmp[6] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* d1 */ - tmp[0] = product[7]; - tmp[1] = product[8]; - tmp[2] = product[9]; - tmp[3] = product[10]; - tmp[4] = product[11]; - tmp[5] = product[12]; - tmp[6] = product[13]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - /* d2 */ - tmp[0] = product[11]; - tmp[1] = product[12]; - tmp[2] = product[13]; - tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); - } - } -} -#else -static void vli_mmod_fast_secp224r1(uint64_t *result, uint64_t *product) -{ - uint64_t tmp[num_words_secp224r1]; - int carry = 0; - - /* t */ - uECC_vli_set(result, product, num_words_secp224r1); - result[num_words_secp224r1 - 1] &= 0xffffffff; - - /* s1 */ - tmp[0] = 0; - tmp[1] = product[3] & 0xffffffff00000000ull; - tmp[2] = product[4]; - tmp[3] = product[5] & 0xffffffff; - uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* s2 */ - tmp[1] = product[5] & 0xffffffff00000000ull; - tmp[2] = product[6]; - tmp[3] = 0; - uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* d1 */ - tmp[0] = (product[3] >> 32) | (product[4] << 32); - tmp[1] = (product[4] >> 32) | (product[5] << 32); - tmp[2] = (product[5] >> 32) | (product[6] << 32); - tmp[3] = product[6] >> 32; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - /* d2 */ - tmp[0] = (product[5] >> 32) | (product[6] << 32); - tmp[1] = product[6] >> 32; - tmp[2] = tmp[3] = 0; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1); - } while (carry < 0); - } else { - while (uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) { - uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); - } - } -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */ - -#endif /* uECC_SUPPORTS_secp224r1 */ - -#if uECC_SUPPORTS_secp256r1 - -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp256r1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp256r1 = { - num_words_secp256r1, - num_bytes_secp256r1, - 256, /* num_n_bits */ - { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3), - BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4), - BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77), - BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8), - BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B), - - BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB), - BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B), - BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E), - BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F) }, - { BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B), - BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65), - BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3), - BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A) }, - &double_jacobian_default, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_default, -#endif - &x_side_default, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp256r1 -#endif -}; - -uECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; } - - -#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) -/* Computes result = product % curve_p - from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -#if uECC_WORD_SIZE == 1 -static void vli_mmod_fast_secp256r1(uint8_t *result, uint8_t *product) { - uint8_t tmp[num_words_secp256r1]; - int8_t carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp256r1); - - /* s1 */ - tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; - tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; - tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; - tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47]; - tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51]; - tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55]; - tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59]; - tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63]; - carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s2 */ - tmp[12] = product[48]; tmp[13] = product[49]; tmp[14] = product[50]; tmp[15] = product[51]; - tmp[16] = product[52]; tmp[17] = product[53]; tmp[18] = product[54]; tmp[19] = product[55]; - tmp[20] = product[56]; tmp[21] = product[57]; tmp[22] = product[58]; tmp[23] = product[59]; - tmp[24] = product[60]; tmp[25] = product[61]; tmp[26] = product[62]; tmp[27] = product[63]; - tmp[28] = tmp[29] = tmp[30] = tmp[31] = 0; - carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s3 */ - tmp[0] = product[32]; tmp[1] = product[33]; tmp[2] = product[34]; tmp[3] = product[35]; - tmp[4] = product[36]; tmp[5] = product[37]; tmp[6] = product[38]; tmp[7] = product[39]; - tmp[8] = product[40]; tmp[9] = product[41]; tmp[10] = product[42]; tmp[11] = product[43]; - tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; - tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59]; - tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s4 */ - tmp[0] = product[36]; tmp[1] = product[37]; tmp[2] = product[38]; tmp[3] = product[39]; - tmp[4] = product[40]; tmp[5] = product[41]; tmp[6] = product[42]; tmp[7] = product[43]; - tmp[8] = product[44]; tmp[9] = product[45]; tmp[10] = product[46]; tmp[11] = product[47]; - tmp[12] = product[52]; tmp[13] = product[53]; tmp[14] = product[54]; tmp[15] = product[55]; - tmp[16] = product[56]; tmp[17] = product[57]; tmp[18] = product[58]; tmp[19] = product[59]; - tmp[20] = product[60]; tmp[21] = product[61]; tmp[22] = product[62]; tmp[23] = product[63]; - tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55]; - tmp[28] = product[32]; tmp[29] = product[33]; tmp[30] = product[34]; tmp[31] = product[35]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* d1 */ - tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47]; - tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51]; - tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55]; - tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; - tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - tmp[24] = product[32]; tmp[25] = product[33]; tmp[26] = product[34]; tmp[27] = product[35]; - tmp[28] = product[40]; tmp[29] = product[41]; tmp[30] = product[42]; tmp[31] = product[43]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d2 */ - tmp[0] = product[48]; tmp[1] = product[49]; tmp[2] = product[50]; tmp[3] = product[51]; - tmp[4] = product[52]; tmp[5] = product[53]; tmp[6] = product[54]; tmp[7] = product[55]; - tmp[8] = product[56]; tmp[9] = product[57]; tmp[10] = product[58]; tmp[11] = product[59]; - tmp[12] = product[60]; tmp[13] = product[61]; tmp[14] = product[62]; tmp[15] = product[63]; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; - tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - tmp[24] = product[36]; tmp[25] = product[37]; tmp[26] = product[38]; tmp[27] = product[39]; - tmp[28] = product[44]; tmp[29] = product[45]; tmp[30] = product[46]; tmp[31] = product[47]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d3 */ - tmp[0] = product[52]; tmp[1] = product[53]; tmp[2] = product[54]; tmp[3] = product[55]; - tmp[4] = product[56]; tmp[5] = product[57]; tmp[6] = product[58]; tmp[7] = product[59]; - tmp[8] = product[60]; tmp[9] = product[61]; tmp[10] = product[62]; tmp[11] = product[63]; - tmp[12] = product[32]; tmp[13] = product[33]; tmp[14] = product[34]; tmp[15] = product[35]; - tmp[16] = product[36]; tmp[17] = product[37]; tmp[18] = product[38]; tmp[19] = product[39]; - tmp[20] = product[40]; tmp[21] = product[41]; tmp[22] = product[42]; tmp[23] = product[43]; - tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; - tmp[28] = product[48]; tmp[29] = product[49]; tmp[30] = product[50]; tmp[31] = product[51]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d4 */ - tmp[0] = product[56]; tmp[1] = product[57]; tmp[2] = product[58]; tmp[3] = product[59]; - tmp[4] = product[60]; tmp[5] = product[61]; tmp[6] = product[62]; tmp[7] = product[63]; - tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; - tmp[12] = product[36]; tmp[13] = product[37]; tmp[14] = product[38]; tmp[15] = product[39]; - tmp[16] = product[40]; tmp[17] = product[41]; tmp[18] = product[42]; tmp[19] = product[43]; - tmp[20] = product[44]; tmp[21] = product[45]; tmp[22] = product[46]; tmp[23] = product[47]; - tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; - tmp[28] = product[52]; tmp[29] = product[53]; tmp[30] = product[54]; tmp[31] = product[55]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); - } - } -} -#elif uECC_WORD_SIZE == 4 -static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { - uint32_t tmp[num_words_secp256r1]; - int carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp256r1); - - /* s1 */ - tmp[0] = tmp[1] = tmp[2] = 0; - tmp[3] = product[11]; - tmp[4] = product[12]; - tmp[5] = product[13]; - tmp[6] = product[14]; - tmp[7] = product[15]; - carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s2 */ - tmp[3] = product[12]; - tmp[4] = product[13]; - tmp[5] = product[14]; - tmp[6] = product[15]; - tmp[7] = 0; - carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s3 */ - tmp[0] = product[8]; - tmp[1] = product[9]; - tmp[2] = product[10]; - tmp[3] = tmp[4] = tmp[5] = 0; - tmp[6] = product[14]; - tmp[7] = product[15]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s4 */ - tmp[0] = product[9]; - tmp[1] = product[10]; - tmp[2] = product[11]; - tmp[3] = product[13]; - tmp[4] = product[14]; - tmp[5] = product[15]; - tmp[6] = product[13]; - tmp[7] = product[8]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* d1 */ - tmp[0] = product[11]; - tmp[1] = product[12]; - tmp[2] = product[13]; - tmp[3] = tmp[4] = tmp[5] = 0; - tmp[6] = product[8]; - tmp[7] = product[10]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d2 */ - tmp[0] = product[12]; - tmp[1] = product[13]; - tmp[2] = product[14]; - tmp[3] = product[15]; - tmp[4] = tmp[5] = 0; - tmp[6] = product[9]; - tmp[7] = product[11]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d3 */ - tmp[0] = product[13]; - tmp[1] = product[14]; - tmp[2] = product[15]; - tmp[3] = product[8]; - tmp[4] = product[9]; - tmp[5] = product[10]; - tmp[6] = 0; - tmp[7] = product[12]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d4 */ - tmp[0] = product[14]; - tmp[1] = product[15]; - tmp[2] = 0; - tmp[3] = product[9]; - tmp[4] = product[10]; - tmp[5] = product[11]; - tmp[6] = 0; - tmp[7] = product[13]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); - } - } -} -#else -static void vli_mmod_fast_secp256r1(uint64_t *result, uint64_t *product) { - uint64_t tmp[num_words_secp256r1]; - int carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp256r1); - - /* s1 */ - tmp[0] = 0; - tmp[1] = product[5] & 0xffffffff00000000ull; - tmp[2] = product[6]; - tmp[3] = product[7]; - carry = (int)uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s2 */ - tmp[1] = product[6] << 32; - tmp[2] = (product[6] >> 32) | (product[7] << 32); - tmp[3] = product[7] >> 32; - carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s3 */ - tmp[0] = product[4]; - tmp[1] = product[5] & 0xffffffff; - tmp[2] = 0; - tmp[3] = product[7]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s4 */ - tmp[0] = (product[4] >> 32) | (product[5] << 32); - tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull); - tmp[2] = product[7]; - tmp[3] = (product[6] >> 32) | (product[4] << 32); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* d1 */ - tmp[0] = (product[5] >> 32) | (product[6] << 32); - tmp[1] = (product[6] >> 32); - tmp[2] = 0; - tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32); - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d2 */ - tmp[0] = product[6]; - tmp[1] = product[7]; - tmp[2] = 0; - tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull); - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d3 */ - tmp[0] = (product[6] >> 32) | (product[7] << 32); - tmp[1] = (product[7] >> 32) | (product[4] << 32); - tmp[2] = (product[4] >> 32) | (product[5] << 32); - tmp[3] = (product[6] << 32); - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d4 */ - tmp[0] = product[7]; - tmp[1] = product[4] & 0xffffffff00000000ull; - tmp[2] = product[5]; - tmp[3] = product[6] & 0xffffffff00000000ull; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); - } - } -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) */ - -#endif /* uECC_SUPPORTS_secp256r1 */ - -#if uECC_SUPPORTS_secp256k1 - -static void double_jacobian_secp256k1(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * Z1, - uECC_Curve curve); -static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp256k1 = { - num_words_secp256k1, - num_bytes_secp256k1, - 256, /* num_n_bits */ - { BYTES_TO_WORDS_8(2F, FC, FF, FF, FE, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(41, 41, 36, D0, 8C, 5E, D2, BF), - BYTES_TO_WORDS_8(3B, A0, 48, AF, E6, DC, AE, BA), - BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(98, 17, F8, 16, 5B, 81, F2, 59), - BYTES_TO_WORDS_8(D9, 28, CE, 2D, DB, FC, 9B, 02), - BYTES_TO_WORDS_8(07, 0B, 87, CE, 95, 62, A0, 55), - BYTES_TO_WORDS_8(AC, BB, DC, F9, 7E, 66, BE, 79), - - BYTES_TO_WORDS_8(B8, D4, 10, FB, 8F, D0, 47, 9C), - BYTES_TO_WORDS_8(19, 54, 85, A6, 48, B4, 17, FD), - BYTES_TO_WORDS_8(A8, 08, 11, 0E, FC, FB, A4, 5D), - BYTES_TO_WORDS_8(65, C4, A3, 26, 77, DA, 3A, 48) }, - { BYTES_TO_WORDS_8(07, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00) }, - &double_jacobian_secp256k1, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_default, -#endif - &x_side_secp256k1, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp256k1 -#endif -}; - -uECC_Curve uECC_secp256k1(void) { return &curve_secp256k1; } - - -/* Double in place */ -static void double_jacobian_secp256k1(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * Z1, - uECC_Curve curve) { - /* t1 = X, t2 = Y, t3 = Z */ - uECC_word_t t4[num_words_secp256k1]; - uECC_word_t t5[num_words_secp256k1]; - - if (uECC_vli_isZero(Z1, num_words_secp256k1)) { - return; - } - - uECC_vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */ - uECC_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */ - uECC_vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */ - uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */ - uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */ - - uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */ - uECC_vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */ - if (uECC_vli_testBit(Y1, 0)) { - uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1); - uECC_vli_rshift1(Y1, num_words_secp256k1); - Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1); - } else { - uECC_vli_rshift1(Y1, num_words_secp256k1); - } - /* t2 = 3/2*(x1^2) = B */ - - uECC_vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */ - uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */ - uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */ - - uECC_vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */ - uECC_vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */ - uECC_vli_modSub(Y1, Y1, t5, curve->p, num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */ -} - -/* Computes result = x^3 + b. result must not overlap x. */ -static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { - uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ - uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 */ - uECC_vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */ -} - -#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256k1) -static void omega_mult_secp256k1(uECC_word_t *result, const uECC_word_t *right); -static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product) { - uECC_word_t tmp[2 * num_words_secp256k1]; - uECC_word_t carry; - - uECC_vli_clear(tmp, num_words_secp256k1); - uECC_vli_clear(tmp + num_words_secp256k1, num_words_secp256k1); - - omega_mult_secp256k1(tmp, product + num_words_secp256k1); /* (Rq, q) = q * c */ - - carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q */ - uECC_vli_clear(product, num_words_secp256k1); - omega_mult_secp256k1(product, tmp + num_words_secp256k1); /* Rq*c */ - carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */ - - while (carry > 0) { - --carry; - uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); - } - if (uECC_vli_cmp_unsafe(result, curve_secp256k1.p, num_words_secp256k1) > 0) { - uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); - } -} - -#if uECC_WORD_SIZE == 1 -static void omega_mult_secp256k1(uint8_t * result, const uint8_t * right) { - /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ - uECC_word_t r0 = 0; - uECC_word_t r1 = 0; - uECC_word_t r2 = 0; - wordcount_t k; - - /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ - muladd(0xD1, right[0], &r0, &r1, &r2); - result[0] = r0; - r0 = r1; - r1 = r2; - /* r2 is still 0 */ - - for (k = 1; k < num_words_secp256k1; ++k) { - muladd(0x03, right[k - 1], &r0, &r1, &r2); - muladd(0xD1, right[k], &r0, &r1, &r2); - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - muladd(0x03, right[num_words_secp256k1 - 1], &r0, &r1, &r2); - result[num_words_secp256k1] = r0; - result[num_words_secp256k1 + 1] = r1; - /* add the 2^32 multiple */ - result[4 + num_words_secp256k1] = - uECC_vli_add(result + 4, result + 4, right, num_words_secp256k1); -} -#elif uECC_WORD_SIZE == 4 -static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) { - /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ - uint32_t carry = 0; - wordcount_t k; - - for (k = 0; k < num_words_secp256k1; ++k) { - uint64_t p = (uint64_t)0x3D1 * right[k] + carry; - result[k] = (uint32_t) p; - carry = p >> 32; - } - result[num_words_secp256k1] = carry; - /* add the 2^32 multiple */ - result[1 + num_words_secp256k1] = - uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1); -} -#else -static void omega_mult_secp256k1(uint64_t * result, const uint64_t * right) { - uECC_word_t r0 = 0; - uECC_word_t r1 = 0; - uECC_word_t r2 = 0; - wordcount_t k; - - /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ - for (k = 0; k < num_words_secp256k1; ++k) { - muladd(0x1000003D1ull, right[k], &r0, &r1, &r2); - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - result[num_words_secp256k1] = r0; -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && && !asm_mmod_fast_secp256k1) */ - -#endif /* uECC_SUPPORTS_secp256k1 */ - -#endif /* _UECC_CURVE_SPECIFIC_H_ */ diff --git a/lib/micro-ecc/platform-specific.inc b/lib/micro-ecc/platform-specific.inc deleted file mode 100644 index 7e0373f505..0000000000 --- a/lib/micro-ecc/platform-specific.inc +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_PLATFORM_SPECIFIC_H_ -#define _UECC_PLATFORM_SPECIFIC_H_ - -#include "types.h" - -#if (defined(_WIN32) || defined(_WIN64)) -/* Windows */ - -// use pragma syntax to prevent tweaking the linker script for getting CryptXYZ function -#pragma comment(lib, "crypt32.lib") -#pragma comment(lib, "advapi32.lib") - -#define WIN32_LEAN_AND_MEAN -#include -#include - -static int default_RNG(uint8_t *dest, unsigned size) { - HCRYPTPROV prov; - if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - return 0; - } - - CryptGenRandom(prov, size, (BYTE *)dest); - CryptReleaseContext(prov, 0); - return 1; -} -#define default_RNG_defined 1 - -#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \ - (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX) - -/* Some POSIX-like system with /dev/urandom or /dev/random. */ -#include -#include -#include - -#ifndef O_CLOEXEC - #define O_CLOEXEC 0 -#endif - -static int default_RNG(uint8_t *dest, unsigned size) { - int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); - if (fd == -1) { - fd = open("/dev/random", O_RDONLY | O_CLOEXEC); - if (fd == -1) { - return 0; - } - } - - char *ptr = (char *)dest; - size_t left = size; - while (left > 0) { - ssize_t bytes_read = read(fd, ptr, left); - if (bytes_read <= 0) { // read failed - close(fd); - return 0; - } - left -= bytes_read; - ptr += bytes_read; - } - - close(fd); - return 1; -} -#define default_RNG_defined 1 - -#elif defined(RIOT_VERSION) - -#include - -static int default_RNG(uint8_t *dest, unsigned size) { - random_bytes(dest, size); - return 1; -} -#define default_RNG_defined 1 - -#elif defined(NRF52_SERIES) - -#include "app_error.h" -#include "nrf_crypto_rng.h" - -static int default_RNG(uint8_t *dest, unsigned size) -{ - // make sure to call nrf_crypto_init and nrf_crypto_rng_init first - ret_code_t ret_code = nrf_crypto_rng_vector_generate(dest, size); - return (ret_code == NRF_SUCCESS) ? 1 : 0; -} -#define default_RNG_defined 1 - -#endif /* platform */ - -#endif /* _UECC_PLATFORM_SPECIFIC_H_ */ diff --git a/lib/micro-ecc/types.h b/lib/micro-ecc/types.h deleted file mode 100644 index 9ee81438fa..0000000000 --- a/lib/micro-ecc/types.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_TYPES_H_ -#define _UECC_TYPES_H_ - -#ifndef uECC_PLATFORM - #if __AVR__ - #define uECC_PLATFORM uECC_avr - #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */ - #define uECC_PLATFORM uECC_arm_thumb2 - #elif defined(__thumb__) - #define uECC_PLATFORM uECC_arm_thumb - #elif defined(__arm__) || defined(_M_ARM) - #define uECC_PLATFORM uECC_arm - #elif defined(__aarch64__) - #define uECC_PLATFORM uECC_arm64 - #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__) - #define uECC_PLATFORM uECC_x86 - #elif defined(__amd64__) || defined(_M_X64) - #define uECC_PLATFORM uECC_x86_64 - #else - #define uECC_PLATFORM uECC_arch_other - #endif -#endif - -#ifndef uECC_ARM_USE_UMAAL - #if (uECC_PLATFORM == uECC_arm) && (__ARM_ARCH >= 6) - #define uECC_ARM_USE_UMAAL 1 - #elif (uECC_PLATFORM == uECC_arm_thumb2) && (__ARM_ARCH >= 6) && !__ARM_ARCH_7M__ - #define uECC_ARM_USE_UMAAL 1 - #else - #define uECC_ARM_USE_UMAAL 0 - #endif -#endif - -#ifndef uECC_WORD_SIZE - #if uECC_PLATFORM == uECC_avr - #define uECC_WORD_SIZE 1 - #elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64) - #define uECC_WORD_SIZE 8 - #else - #define uECC_WORD_SIZE 4 - #endif -#endif - -#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8) - #error "Unsupported value for uECC_WORD_SIZE" -#endif - -#if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1)) - #pragma message ("uECC_WORD_SIZE must be 1 for AVR") - #undef uECC_WORD_SIZE - #define uECC_WORD_SIZE 1 -#endif - -#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \ - uECC_PLATFORM == uECC_arm_thumb2) && \ - (uECC_WORD_SIZE != 4)) - #pragma message ("uECC_WORD_SIZE must be 4 for ARM") - #undef uECC_WORD_SIZE - #define uECC_WORD_SIZE 4 -#endif - -#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302) - #define SUPPORTS_INT128 1 -#else - #define SUPPORTS_INT128 0 -#endif - -typedef int8_t wordcount_t; -typedef int16_t bitcount_t; -typedef int8_t cmpresult_t; - -#if (uECC_WORD_SIZE == 1) - -typedef uint8_t uECC_word_t; -typedef uint16_t uECC_dword_t; - -#define HIGH_BIT_SET 0x80 -#define uECC_WORD_BITS 8 -#define uECC_WORD_BITS_SHIFT 3 -#define uECC_WORD_BITS_MASK 0x07 - -#elif (uECC_WORD_SIZE == 4) - -typedef uint32_t uECC_word_t; -typedef uint64_t uECC_dword_t; - -#define HIGH_BIT_SET 0x80000000 -#define uECC_WORD_BITS 32 -#define uECC_WORD_BITS_SHIFT 5 -#define uECC_WORD_BITS_MASK 0x01F - -#elif (uECC_WORD_SIZE == 8) - -typedef uint64_t uECC_word_t; -#if SUPPORTS_INT128 -typedef unsigned __int128 uECC_dword_t; -#endif - -#define HIGH_BIT_SET 0x8000000000000000ull -#define uECC_WORD_BITS 64 -#define uECC_WORD_BITS_SHIFT 6 -#define uECC_WORD_BITS_MASK 0x03F - -#endif /* uECC_WORD_SIZE */ - -#endif /* _UECC_TYPES_H_ */ diff --git a/lib/micro-ecc/uECC.c b/lib/micro-ecc/uECC.c deleted file mode 100644 index a3d502cf21..0000000000 --- a/lib/micro-ecc/uECC.c +++ /dev/null @@ -1,1669 +0,0 @@ -/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#include "uECC.h" -#include "uECC_vli.h" - -#ifndef uECC_RNG_MAX_TRIES - #define uECC_RNG_MAX_TRIES 64 -#endif - -#if uECC_ENABLE_VLI_API - #define uECC_VLI_API -#else - #define uECC_VLI_API static -#endif - -#if (uECC_PLATFORM == uECC_avr) || \ - (uECC_PLATFORM == uECC_arm) || \ - (uECC_PLATFORM == uECC_arm_thumb) || \ - (uECC_PLATFORM == uECC_arm_thumb2) - #define CONCATX(a, ...) a ## __VA_ARGS__ - #define CONCAT(a, ...) CONCATX(a, __VA_ARGS__) - - #define STRX(a) #a - #define STR(a) STRX(a) - - #define EVAL(...) EVAL1(EVAL1(EVAL1(EVAL1(__VA_ARGS__)))) - #define EVAL1(...) EVAL2(EVAL2(EVAL2(EVAL2(__VA_ARGS__)))) - #define EVAL2(...) EVAL3(EVAL3(EVAL3(EVAL3(__VA_ARGS__)))) - #define EVAL3(...) EVAL4(EVAL4(EVAL4(EVAL4(__VA_ARGS__)))) - #define EVAL4(...) __VA_ARGS__ - - #define DEC_1 0 - #define DEC_2 1 - #define DEC_3 2 - #define DEC_4 3 - #define DEC_5 4 - #define DEC_6 5 - #define DEC_7 6 - #define DEC_8 7 - #define DEC_9 8 - #define DEC_10 9 - #define DEC_11 10 - #define DEC_12 11 - #define DEC_13 12 - #define DEC_14 13 - #define DEC_15 14 - #define DEC_16 15 - #define DEC_17 16 - #define DEC_18 17 - #define DEC_19 18 - #define DEC_20 19 - #define DEC_21 20 - #define DEC_22 21 - #define DEC_23 22 - #define DEC_24 23 - #define DEC_25 24 - #define DEC_26 25 - #define DEC_27 26 - #define DEC_28 27 - #define DEC_29 28 - #define DEC_30 29 - #define DEC_31 30 - #define DEC_32 31 - - #define DEC(N) CONCAT(DEC_, N) - - #define SECOND_ARG(_, val, ...) val - #define SOME_CHECK_0 ~, 0 - #define GET_SECOND_ARG(...) SECOND_ARG(__VA_ARGS__, SOME,) - #define SOME_OR_0(N) GET_SECOND_ARG(CONCAT(SOME_CHECK_, N)) - - #define EMPTY(...) - #define DEFER(...) __VA_ARGS__ EMPTY() - - #define REPEAT_NAME_0() REPEAT_0 - #define REPEAT_NAME_SOME() REPEAT_SOME - #define REPEAT_0(...) - #define REPEAT_SOME(N, stuff) DEFER(CONCAT(REPEAT_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), stuff) stuff - #define REPEAT(N, stuff) EVAL(REPEAT_SOME(N, stuff)) - - #define REPEATM_NAME_0() REPEATM_0 - #define REPEATM_NAME_SOME() REPEATM_SOME - #define REPEATM_0(...) - #define REPEATM_SOME(N, macro) macro(N) \ - DEFER(CONCAT(REPEATM_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), macro) - #define REPEATM(N, macro) EVAL(REPEATM_SOME(N, macro)) -#endif - -#include "platform-specific.inc" - -#if (uECC_WORD_SIZE == 1) - #if uECC_SUPPORTS_secp160r1 - #define uECC_MAX_WORDS 21 /* Due to the size of curve_n. */ - #endif - #if uECC_SUPPORTS_secp192r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 24 - #endif - #if uECC_SUPPORTS_secp224r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 28 - #endif - #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 32 - #endif -#elif (uECC_WORD_SIZE == 4) - #if uECC_SUPPORTS_secp160r1 - #define uECC_MAX_WORDS 6 /* Due to the size of curve_n. */ - #endif - #if uECC_SUPPORTS_secp192r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 6 - #endif - #if uECC_SUPPORTS_secp224r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 7 - #endif - #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 8 - #endif -#elif (uECC_WORD_SIZE == 8) - #if uECC_SUPPORTS_secp160r1 - #define uECC_MAX_WORDS 3 - #endif - #if uECC_SUPPORTS_secp192r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 3 - #endif - #if uECC_SUPPORTS_secp224r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 4 - #endif - #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 4 - #endif -#endif /* uECC_WORD_SIZE */ - -#define BITS_TO_WORDS(num_bits) ((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8)) -#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8) - -struct uECC_Curve_t { - wordcount_t num_words; - wordcount_t num_bytes; - bitcount_t num_n_bits; - uECC_word_t p[uECC_MAX_WORDS]; - uECC_word_t n[uECC_MAX_WORDS]; - uECC_word_t G[uECC_MAX_WORDS * 2]; - uECC_word_t b[uECC_MAX_WORDS]; - void (*double_jacobian)(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * Z1, - uECC_Curve curve); -#if uECC_SUPPORT_COMPRESSED_POINT - void (*mod_sqrt)(uECC_word_t *a, uECC_Curve curve); -#endif - void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); -#if (uECC_OPTIMIZATION_LEVEL > 0) - void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product); -#endif -}; - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN -static void bcopy(uint8_t *dst, - const uint8_t *src, - unsigned num_bytes) { - while (0 != num_bytes) { - num_bytes--; - dst[num_bytes] = src[num_bytes]; - } -} -#endif - -static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -#if (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \ - uECC_PLATFORM == uECC_arm_thumb2) - #include "asm_arm.inc" -#endif - -#if (uECC_PLATFORM == uECC_avr) - #include "asm_avr.inc" -#endif - -#if default_RNG_defined -static uECC_RNG_Function g_rng_function = &default_RNG; -#else -static uECC_RNG_Function g_rng_function = 0; -#endif - -void uECC_set_rng(uECC_RNG_Function rng_function) { - g_rng_function = rng_function; -} - -uECC_RNG_Function uECC_get_rng(void) { - return g_rng_function; -} - -int uECC_curve_private_key_size(uECC_Curve curve) { - return BITS_TO_BYTES(curve->num_n_bits); -} - -int uECC_curve_public_key_size(uECC_Curve curve) { - return 2 * curve->num_bytes; -} - -#if !asm_clear -uECC_VLI_API void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) { - wordcount_t i; - for (i = 0; i < num_words; ++i) { - vli[i] = 0; - } -} -#endif /* !asm_clear */ - -/* Constant-time comparison to zero - secure way to compare long integers */ -/* Returns 1 if vli == 0, 0 otherwise. */ -uECC_VLI_API uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) { - uECC_word_t bits = 0; - wordcount_t i; - for (i = 0; i < num_words; ++i) { - bits |= vli[i]; - } - return (bits == 0); -} - -/* Returns nonzero if bit 'bit' of vli is set. */ -uECC_VLI_API uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) { - return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); -} - -/* Counts the number of words in vli. */ -static wordcount_t vli_numDigits(const uECC_word_t *vli, const wordcount_t max_words) { - wordcount_t i; - /* Search from the end until we find a non-zero digit. - We do it in reverse because we expect that most digits will be nonzero. */ - for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { - } - - return (i + 1); -} - -/* Counts the number of bits required to represent vli. */ -uECC_VLI_API bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words) { - uECC_word_t i; - uECC_word_t digit; - - wordcount_t num_digits = vli_numDigits(vli, max_words); - if (num_digits == 0) { - return 0; - } - - digit = vli[num_digits - 1]; - for (i = 0; digit; ++i) { - digit >>= 1; - } - - return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i); -} - -/* Sets dest = src. */ -#if !asm_set -uECC_VLI_API void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words) { - wordcount_t i; - for (i = 0; i < num_words; ++i) { - dest[i] = src[i]; - } -} -#endif /* !asm_set */ - -/* Returns sign of left - right. */ -static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - wordcount_t i; - for (i = num_words - 1; i >= 0; --i) { - if (left[i] > right[i]) { - return 1; - } else if (left[i] < right[i]) { - return -1; - } - } - return 0; -} - -/* Constant-time comparison function - secure way to compare long integers */ -/* Returns one if left == right, zero otherwise. */ -uECC_VLI_API uECC_word_t uECC_vli_equal(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t diff = 0; - wordcount_t i; - for (i = num_words - 1; i >= 0; --i) { - diff |= (left[i] ^ right[i]); - } - return (diff == 0); -} - -uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Returns sign of left - right, in constant time. */ -uECC_VLI_API cmpresult_t uECC_vli_cmp(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t tmp[uECC_MAX_WORDS]; - uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); - uECC_word_t equal = uECC_vli_isZero(tmp, num_words); - return (!equal - 2 * neg); -} - -/* Computes vli = vli >> 1. */ -#if !asm_rshift1 -uECC_VLI_API void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) { - uECC_word_t *end = vli; - uECC_word_t carry = 0; - - vli += num_words; - while (vli-- > end) { - uECC_word_t temp = *vli; - *vli = (temp >> 1) | carry; - carry = temp << (uECC_WORD_BITS - 1); - } -} -#endif /* !asm_rshift1 */ - -/* Computes result = left + right, returning carry. Can modify in place. */ -#if !asm_add -uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t carry = 0; - wordcount_t i; - for (i = 0; i < num_words; ++i) { - uECC_word_t sum = left[i] + right[i] + carry; - if (sum != left[i]) { - carry = (sum < left[i]); - } - result[i] = sum; - } - return carry; -} -#endif /* !asm_add */ - -/* Computes result = left - right, returning borrow. Can modify in place. */ -#if !asm_sub -uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t borrow = 0; - wordcount_t i; - for (i = 0; i < num_words; ++i) { - uECC_word_t diff = left[i] - right[i] - borrow; - if (diff != left[i]) { - borrow = (diff > left[i]); - } - result[i] = diff; - } - return borrow; -} -#endif /* !asm_sub */ - -#if !asm_mult || (uECC_SQUARE_FUNC && !asm_square) || \ - (uECC_SUPPORTS_secp256k1 && (uECC_OPTIMIZATION_LEVEL > 0) && \ - ((uECC_WORD_SIZE == 1) || (uECC_WORD_SIZE == 8))) -static void muladd(uECC_word_t a, - uECC_word_t b, - uECC_word_t *r0, - uECC_word_t *r1, - uECC_word_t *r2) { -#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128 - uint64_t a0 = a & 0xffffffffull; - uint64_t a1 = a >> 32; - uint64_t b0 = b & 0xffffffffull; - uint64_t b1 = b >> 32; - - uint64_t i0 = a0 * b0; - uint64_t i1 = a0 * b1; - uint64_t i2 = a1 * b0; - uint64_t i3 = a1 * b1; - - uint64_t p0, p1; - - i2 += (i0 >> 32); - i2 += i1; - if (i2 < i1) { /* overflow */ - i3 += 0x100000000ull; - } - - p0 = (i0 & 0xffffffffull) | (i2 << 32); - p1 = i3 + (i2 >> 32); - - *r0 += p0; - *r1 += (p1 + (*r0 < p0)); - *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0)); -#else - uECC_dword_t p = (uECC_dword_t)a * b; - uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; - r01 += p; - *r2 += (r01 < p); - *r1 = r01 >> uECC_WORD_BITS; - *r0 = (uECC_word_t)r01; -#endif -} -#endif /* muladd needed */ - -#if !asm_mult -uECC_VLI_API void uECC_vli_mult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t r0 = 0; - uECC_word_t r1 = 0; - uECC_word_t r2 = 0; - wordcount_t i, k; - - /* Compute each digit of result in sequence, maintaining the carries. */ - for (k = 0; k < num_words; ++k) { - for (i = 0; i <= k; ++i) { - muladd(left[i], right[k - i], &r0, &r1, &r2); - } - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - for (k = num_words; k < num_words * 2 - 1; ++k) { - for (i = (k + 1) - num_words; i < num_words; ++i) { - muladd(left[i], right[k - i], &r0, &r1, &r2); - } - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - result[num_words * 2 - 1] = r0; -} -#endif /* !asm_mult */ - -#if uECC_SQUARE_FUNC - -#if !asm_square -static void mul2add(uECC_word_t a, - uECC_word_t b, - uECC_word_t *r0, - uECC_word_t *r1, - uECC_word_t *r2) { -#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128 - uint64_t a0 = a & 0xffffffffull; - uint64_t a1 = a >> 32; - uint64_t b0 = b & 0xffffffffull; - uint64_t b1 = b >> 32; - - uint64_t i0 = a0 * b0; - uint64_t i1 = a0 * b1; - uint64_t i2 = a1 * b0; - uint64_t i3 = a1 * b1; - - uint64_t p0, p1; - - i2 += (i0 >> 32); - i2 += i1; - if (i2 < i1) - { /* overflow */ - i3 += 0x100000000ull; - } - - p0 = (i0 & 0xffffffffull) | (i2 << 32); - p1 = i3 + (i2 >> 32); - - *r2 += (p1 >> 63); - p1 = (p1 << 1) | (p0 >> 63); - p0 <<= 1; - - *r0 += p0; - *r1 += (p1 + (*r0 < p0)); - *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0)); -#else - uECC_dword_t p = (uECC_dword_t)a * b; - uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; - *r2 += (p >> (uECC_WORD_BITS * 2 - 1)); - p *= 2; - r01 += p; - *r2 += (r01 < p); - *r1 = r01 >> uECC_WORD_BITS; - *r0 = (uECC_word_t)r01; -#endif -} - -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { - uECC_word_t r0 = 0; - uECC_word_t r1 = 0; - uECC_word_t r2 = 0; - - wordcount_t i, k; - - for (k = 0; k < num_words * 2 - 1; ++k) { - uECC_word_t min = (k < num_words ? 0 : (k + 1) - num_words); - for (i = min; i <= k && i <= k - i; ++i) { - if (i < k-i) { - mul2add(left[i], left[k - i], &r0, &r1, &r2); - } else { - muladd(left[i], left[k - i], &r0, &r1, &r2); - } - } - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - - result[num_words * 2 - 1] = r0; -} -#endif /* !asm_square */ - -#else /* uECC_SQUARE_FUNC */ - -#if uECC_ENABLE_VLI_API -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { - uECC_vli_mult(result, left, left, num_words); -} -#endif /* uECC_ENABLE_VLI_API */ - -#endif /* uECC_SQUARE_FUNC */ - -/* Computes result = (left + right) % mod. - Assumes that left < mod and right < mod, and that result does not overlap mod. */ -uECC_VLI_API void uECC_vli_modAdd(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t carry = uECC_vli_add(result, left, right, num_words); - if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) { - /* result > mod (result = mod + remainder), so subtract mod to get remainder. */ - uECC_vli_sub(result, result, mod, num_words); - } -} - -/* Computes result = (left - right) % mod. - Assumes that left < mod and right < mod, and that result does not overlap mod. */ -uECC_VLI_API void uECC_vli_modSub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words); - if (l_borrow) { - /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x, - we can get the correct result from result + mod (with overflow). */ - uECC_vli_add(result, result, mod, num_words); - } -} - -/* Computes result = product % mod, where product is 2N words long. */ -/* Currently only designed to work for curve_p or curve_n. */ -uECC_VLI_API void uECC_vli_mmod(uECC_word_t *result, - uECC_word_t *product, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t mod_multiple[2 * uECC_MAX_WORDS]; - uECC_word_t tmp[2 * uECC_MAX_WORDS]; - uECC_word_t *v[2] = {tmp, product}; - uECC_word_t index; - - /* Shift mod so its highest set bit is at the maximum position. */ - bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - uECC_vli_numBits(mod, num_words); - wordcount_t word_shift = shift / uECC_WORD_BITS; - wordcount_t bit_shift = shift % uECC_WORD_BITS; - uECC_word_t carry = 0; - uECC_vli_clear(mod_multiple, word_shift); - if (bit_shift > 0) { - for(index = 0; index < (uECC_word_t)num_words; ++index) { - mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry; - carry = mod[index] >> (uECC_WORD_BITS - bit_shift); - } - } else { - uECC_vli_set(mod_multiple + word_shift, mod, num_words); - } - - for (index = 1; shift >= 0; --shift) { - uECC_word_t borrow = 0; - wordcount_t i; - for (i = 0; i < num_words * 2; ++i) { - uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; - if (diff != v[index][i]) { - borrow = (diff > v[index][i]); - } - v[1 - index][i] = diff; - } - index = !(index ^ borrow); /* Swap the index if there was no borrow */ - uECC_vli_rshift1(mod_multiple, num_words); - mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); - uECC_vli_rshift1(mod_multiple + num_words, num_words); - } - uECC_vli_set(result, v[index], num_words); -} - -/* Computes result = (left * right) % mod. */ -uECC_VLI_API void uECC_vli_modMult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t product[2 * uECC_MAX_WORDS]; - uECC_vli_mult(product, left, right, num_words); - uECC_vli_mmod(result, product, mod, num_words); -} - -uECC_VLI_API void uECC_vli_modMult_fast(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - uECC_Curve curve) { - uECC_word_t product[2 * uECC_MAX_WORDS]; - uECC_vli_mult(product, left, right, curve->num_words); -#if (uECC_OPTIMIZATION_LEVEL > 0) - curve->mmod_fast(result, product); -#else - uECC_vli_mmod(result, product, curve->p, curve->num_words); -#endif -} - -#if uECC_SQUARE_FUNC - -#if uECC_ENABLE_VLI_API -/* Computes result = left^2 % mod. */ -uECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t product[2 * uECC_MAX_WORDS]; - uECC_vli_square(product, left, num_words); - uECC_vli_mmod(result, product, mod, num_words); -} -#endif /* uECC_ENABLE_VLI_API */ - -uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result, - const uECC_word_t *left, - uECC_Curve curve) { - uECC_word_t product[2 * uECC_MAX_WORDS]; - uECC_vli_square(product, left, curve->num_words); -#if (uECC_OPTIMIZATION_LEVEL > 0) - curve->mmod_fast(result, product); -#else - uECC_vli_mmod(result, product, curve->p, curve->num_words); -#endif -} - -#else /* uECC_SQUARE_FUNC */ - -#if uECC_ENABLE_VLI_API -uECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_vli_modMult(result, left, left, mod, num_words); -} -#endif /* uECC_ENABLE_VLI_API */ - -uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result, - const uECC_word_t *left, - uECC_Curve curve) { - uECC_vli_modMult_fast(result, left, left, curve); -} - -#endif /* uECC_SQUARE_FUNC */ - -#define EVEN(vli) (!(vli[0] & 1)) -static void vli_modInv_update(uECC_word_t *uv, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t carry = 0; - if (!EVEN(uv)) { - carry = uECC_vli_add(uv, uv, mod, num_words); - } - uECC_vli_rshift1(uv, num_words); - if (carry) { - uv[num_words - 1] |= HIGH_BIT_SET; - } -} - -/* Computes result = (1 / input) % mod. All VLIs are the same size. - See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" */ -uECC_VLI_API void uECC_vli_modInv(uECC_word_t *result, - const uECC_word_t *input, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t a[uECC_MAX_WORDS], b[uECC_MAX_WORDS], u[uECC_MAX_WORDS], v[uECC_MAX_WORDS]; - cmpresult_t cmpResult; - - if (uECC_vli_isZero(input, num_words)) { - uECC_vli_clear(result, num_words); - return; - } - - uECC_vli_set(a, input, num_words); - uECC_vli_set(b, mod, num_words); - uECC_vli_clear(u, num_words); - u[0] = 1; - uECC_vli_clear(v, num_words); - while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) { - if (EVEN(a)) { - uECC_vli_rshift1(a, num_words); - vli_modInv_update(u, mod, num_words); - } else if (EVEN(b)) { - uECC_vli_rshift1(b, num_words); - vli_modInv_update(v, mod, num_words); - } else if (cmpResult > 0) { - uECC_vli_sub(a, a, b, num_words); - uECC_vli_rshift1(a, num_words); - if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) { - uECC_vli_add(u, u, mod, num_words); - } - uECC_vli_sub(u, u, v, num_words); - vli_modInv_update(u, mod, num_words); - } else { - uECC_vli_sub(b, b, a, num_words); - uECC_vli_rshift1(b, num_words); - if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) { - uECC_vli_add(v, v, mod, num_words); - } - uECC_vli_sub(v, v, u, num_words); - vli_modInv_update(v, mod, num_words); - } - } - uECC_vli_set(result, u, num_words); -} - -/* ------ Point operations ------ */ - -#include "curve-specific.inc" - -/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */ -#define EccPoint_isZero(point, curve) uECC_vli_isZero((point), (curve)->num_words * 2) - -/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates. -From http://eprint.iacr.org/2011/338.pdf -*/ - -/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ -static void apply_z(uECC_word_t * X1, - uECC_word_t * Y1, - const uECC_word_t * const Z, - uECC_Curve curve) { - uECC_word_t t1[uECC_MAX_WORDS]; - - uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */ - uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */ - uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */ - uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ -} - -/* P = (x1, y1) => 2P, (x2, y2) => P' */ -static void XYcZ_initial_double(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * X2, - uECC_word_t * Y2, - const uECC_word_t * const initial_Z, - uECC_Curve curve) { - uECC_word_t z[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - if (initial_Z) { - uECC_vli_set(z, initial_Z, num_words); - } else { - uECC_vli_clear(z, num_words); - z[0] = 1; - } - - uECC_vli_set(X2, X1, num_words); - uECC_vli_set(Y2, Y1, num_words); - - apply_z(X1, Y1, z, curve); - curve->double_jacobian(X1, Y1, z, curve); - apply_z(X2, Y2, z, curve); -} - -/* Input P = (x1, y1, Z), Q = (x2, y2, Z) - Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) - or P => P', Q => P + Q -*/ -static void XYcZ_add(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * X2, - uECC_word_t * Y2, - uECC_Curve curve) { - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uECC_word_t t5[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - - uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ - uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ - uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ - uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ - uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */ - - uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */ - uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */ - uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */ - uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */ - uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */ - uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */ - - uECC_vli_set(X2, t5, num_words); -} - -/* Input P = (x1, y1, Z), Q = (x2, y2, Z) - Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) - or P => P - Q, Q => P + Q -*/ -static void XYcZ_addC(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * X2, - uECC_word_t * Y2, - uECC_Curve curve) { - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uECC_word_t t5[uECC_MAX_WORDS]; - uECC_word_t t6[uECC_MAX_WORDS]; - uECC_word_t t7[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - - uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ - uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ - uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ - uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ - uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ - - uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */ - uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */ - uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */ - uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */ - uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */ - - uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */ - uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = (y2 - y1)*(B - x3) - E = y3 */ - - uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */ - uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */ - uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */ - uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */ - uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); /* t2 = (y2+y1)*(x3' - B) - E = y3' */ - - uECC_vli_set(X1, t7, num_words); -} - -/* result may overlap point. */ -static void EccPoint_mult(uECC_word_t * result, - const uECC_word_t * point, - const uECC_word_t * scalar, - const uECC_word_t * initial_Z, - bitcount_t num_bits, - uECC_Curve curve) { - /* R0 and R1 */ - uECC_word_t Rx[2][uECC_MAX_WORDS]; - uECC_word_t Ry[2][uECC_MAX_WORDS]; - uECC_word_t z[uECC_MAX_WORDS]; - bitcount_t i; - uECC_word_t nb; - wordcount_t num_words = curve->num_words; - - uECC_vli_set(Rx[1], point, num_words); - uECC_vli_set(Ry[1], point + num_words, num_words); - - XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve); - - for (i = num_bits - 2; i > 0; --i) { - nb = !uECC_vli_testBit(scalar, i); - XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); - XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); - } - - nb = !uECC_vli_testBit(scalar, 0); - XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); - - /* Find final 1/Z value. */ - uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ - uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */ - uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */ - uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0)) */ - /* yP / (xP * Yb * (X1 - X0)) */ - uECC_vli_modMult_fast(z, z, point + num_words, curve); - uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */ - /* End 1/Z calculation */ - - XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); - apply_z(Rx[0], Ry[0], z, curve); - - uECC_vli_set(result, Rx[0], num_words); - uECC_vli_set(result + num_words, Ry[0], num_words); -} - -static uECC_word_t regularize_k(const uECC_word_t * const k, - uECC_word_t *k0, - uECC_word_t *k1, - uECC_Curve curve) { - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; - uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || - (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && - uECC_vli_testBit(k0, num_n_bits)); - uECC_vli_add(k1, k0, curve->n, num_n_words); - return carry; -} - -/* Generates a random integer in the range 0 < random < top. - Both random and top have num_words words. */ -uECC_VLI_API int uECC_generate_random_int(uECC_word_t *random, - const uECC_word_t *top, - wordcount_t num_words) { - uECC_word_t mask = (uECC_word_t)-1; - uECC_word_t tries; - bitcount_t num_bits = uECC_vli_numBits(top, num_words); - - if (!g_rng_function) { - return 0; - } - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { - return 0; - } - random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); - if (!uECC_vli_isZero(random, num_words) && - uECC_vli_cmp(top, random, num_words) == 1) { - return 1; - } - } - return 0; -} - -static uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, - uECC_word_t *private_key, - uECC_Curve curve) { - uECC_word_t tmp1[uECC_MAX_WORDS]; - uECC_word_t tmp2[uECC_MAX_WORDS]; - uECC_word_t *p2[2] = {tmp1, tmp2}; - uECC_word_t *initial_Z = 0; - uECC_word_t carry; - - /* Regularize the bitcount for the private key so that attackers cannot use a side channel - attack to learn the number of leading zeros. */ - carry = regularize_k(private_key, tmp1, tmp2, curve); - - /* If an RNG function was specified, try to get a random initial Z value to improve - protection against side-channel attacks. */ - if (g_rng_function) { - if (!uECC_generate_random_int(p2[carry], curve->p, curve->num_words)) { - return 0; - } - initial_Z = p2[carry]; - } - EccPoint_mult(result, curve->G, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); - - if (EccPoint_isZero(result, curve)) { - return 0; - } - return 1; -} - -#if uECC_WORD_SIZE == 1 - -uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes, - int num_bytes, - const uint8_t *native) { - wordcount_t i; - for (i = 0; i < num_bytes; ++i) { - bytes[i] = native[(num_bytes - 1) - i]; - } -} - -uECC_VLI_API void uECC_vli_bytesToNative(uint8_t *native, - const uint8_t *bytes, - int num_bytes) { - uECC_vli_nativeToBytes(native, num_bytes, bytes); -} - -#else - -uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes, - int num_bytes, - const uECC_word_t *native) { - int i; - for (i = 0; i < num_bytes; ++i) { - unsigned b = num_bytes - 1 - i; - bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE)); - } -} - -uECC_VLI_API void uECC_vli_bytesToNative(uECC_word_t *native, - const uint8_t *bytes, - int num_bytes) { - int i; - uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); - for (i = 0; i < num_bytes; ++i) { - unsigned b = num_bytes - 1 - i; - native[b / uECC_WORD_SIZE] |= - (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); - } -} - -#endif /* uECC_WORD_SIZE */ - -int uECC_make_key(uint8_t *public_key, - uint8_t *private_key, - uECC_Curve curve) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *_private = (uECC_word_t *)private_key; - uECC_word_t *_public = (uECC_word_t *)public_key; -#else - uECC_word_t _private[uECC_MAX_WORDS]; - uECC_word_t _public[uECC_MAX_WORDS * 2]; -#endif - uECC_word_t tries; - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!uECC_generate_random_int(_private, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { - return 0; - } - - if (EccPoint_compute_public_key(_public, _private, curve)) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_nativeToBytes(private_key, BITS_TO_BYTES(curve->num_n_bits), _private); - uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); - uECC_vli_nativeToBytes( - public_key + curve->num_bytes, curve->num_bytes, _public + curve->num_words); -#endif - return 1; - } - } - return 0; -} - -int uECC_shared_secret(const uint8_t *public_key, - const uint8_t *private_key, - uint8_t *secret, - uECC_Curve curve) { - uECC_word_t _public[uECC_MAX_WORDS * 2]; - uECC_word_t _private[uECC_MAX_WORDS]; - - uECC_word_t tmp[uECC_MAX_WORDS]; - uECC_word_t *p2[2] = {_private, tmp}; - uECC_word_t *initial_Z = 0; - uECC_word_t carry; - wordcount_t num_words = curve->num_words; - wordcount_t num_bytes = curve->num_bytes; - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) _private, private_key, num_bytes); - bcopy((uint8_t *) _public, public_key, num_bytes*2); -#else - uECC_vli_bytesToNative(_private, private_key, BITS_TO_BYTES(curve->num_n_bits)); - uECC_vli_bytesToNative(_public, public_key, num_bytes); - uECC_vli_bytesToNative(_public + num_words, public_key + num_bytes, num_bytes); -#endif - - /* Regularize the bitcount for the private key so that attackers cannot use a side channel - attack to learn the number of leading zeros. */ - carry = regularize_k(_private, _private, tmp, curve); - - /* If an RNG function was specified, try to get a random initial Z value to improve - protection against side-channel attacks. */ - if (g_rng_function) { - if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { - return 0; - } - initial_Z = p2[carry]; - } - - EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) secret, (uint8_t *) _public, num_bytes); -#else - uECC_vli_nativeToBytes(secret, num_bytes, _public); -#endif - return !EccPoint_isZero(_public, curve); -} - -#if uECC_SUPPORT_COMPRESSED_POINT -void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve) { - wordcount_t i; - for (i = 0; i < curve->num_bytes; ++i) { - compressed[i+1] = public_key[i]; - } -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - compressed[0] = 2 + (public_key[curve->num_bytes] & 0x01); -#else - compressed[0] = 2 + (public_key[curve->num_bytes * 2 - 1] & 0x01); -#endif -} - -void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *point = (uECC_word_t *)public_key; -#else - uECC_word_t point[uECC_MAX_WORDS * 2]; -#endif - uECC_word_t *y = point + curve->num_words; -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy(public_key, compressed+1, curve->num_bytes); -#else - uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes); -#endif - curve->x_side(y, point, curve); - curve->mod_sqrt(y, curve); - - if ((y[0] & 0x01) != (compressed[0] & 0x01)) { - uECC_vli_sub(y, curve->p, y, curve->num_words); - } - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_nativeToBytes(public_key, curve->num_bytes, point); - uECC_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, y); -#endif -} -#endif /* uECC_SUPPORT_COMPRESSED_POINT */ - -uECC_VLI_API int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { - uECC_word_t tmp1[uECC_MAX_WORDS]; - uECC_word_t tmp2[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - - /* The point at infinity is invalid. */ - if (EccPoint_isZero(point, curve)) { - return 0; - } - - /* x and y must be smaller than p. */ - if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || - uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) { - return 0; - } - - uECC_vli_modSquare_fast(tmp1, point + num_words, curve); - curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ - - /* Make sure that y^2 == x^3 + ax + b */ - return (int)(uECC_vli_equal(tmp1, tmp2, num_words)); -} - -int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *_public = (uECC_word_t *)public_key; -#else - uECC_word_t _public[uECC_MAX_WORDS * 2]; -#endif - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); - uECC_vli_bytesToNative( - _public + curve->num_words, public_key + curve->num_bytes, curve->num_bytes); -#endif - return uECC_valid_point(_public, curve); -} - -int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *_private = (uECC_word_t *)private_key; - uECC_word_t *_public = (uECC_word_t *)public_key; -#else - uECC_word_t _private[uECC_MAX_WORDS]; - uECC_word_t _public[uECC_MAX_WORDS * 2]; -#endif - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_bytesToNative(_private, private_key, BITS_TO_BYTES(curve->num_n_bits)); -#endif - - /* Make sure the private key is in the range [1, n-1]. */ - if (uECC_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) { - return 0; - } - - if (uECC_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != 1) { - return 0; - } - - /* Compute public key. */ - if (!EccPoint_compute_public_key(_public, _private, curve)) { - return 0; - } - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); - uECC_vli_nativeToBytes( - public_key + curve->num_bytes, curve->num_bytes, _public + curve->num_words); -#endif - return 1; -} - - -/* -------- ECDSA code -------- */ - -static void bits2int(uECC_word_t *native, - const uint8_t *bits, - unsigned bits_size, - uECC_Curve curve) { - unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); - unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); - int shift; - uECC_word_t carry; - uECC_word_t *ptr; - - if (bits_size > num_n_bytes) { - bits_size = num_n_bytes; - } - - uECC_vli_clear(native, num_n_words); -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) native, bits, bits_size); -#else - uECC_vli_bytesToNative(native, bits, bits_size); -#endif - if (bits_size * 8 <= (unsigned)curve->num_n_bits) { - return; - } - shift = bits_size * 8 - curve->num_n_bits; - carry = 0; - ptr = native + num_n_words; - while (ptr-- > native) { - uECC_word_t temp = *ptr; - *ptr = (temp >> shift) | carry; - carry = temp << (uECC_WORD_BITS - shift); - } - - /* Reduce mod curve_n */ - if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) { - uECC_vli_sub(native, native, curve->n, num_n_words); - } -} - -static int uECC_sign_with_k_internal(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - uECC_word_t *k, - uint8_t *signature, - uECC_Curve curve) { - - uECC_word_t tmp[uECC_MAX_WORDS]; - uECC_word_t s[uECC_MAX_WORDS]; - uECC_word_t *k2[2] = {tmp, s}; - uECC_word_t *initial_Z = 0; -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *p = (uECC_word_t *)signature; -#else - uECC_word_t p[uECC_MAX_WORDS * 2]; -#endif - uECC_word_t carry; - wordcount_t num_words = curve->num_words; - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; - - /* Make sure 0 < k < curve_n */ - if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { - return 0; - } - - carry = regularize_k(k, tmp, s, curve); - /* If an RNG function was specified, try to get a random initial Z value to improve - protection against side-channel attacks. */ - if (g_rng_function) { - if (!uECC_generate_random_int(k2[carry], curve->p, num_words)) { - return 0; - } - initial_Z = k2[carry]; - } - EccPoint_mult(p, curve->G, k2[!carry], initial_Z, num_n_bits + 1, curve); - if (uECC_vli_isZero(p, num_words)) { - return 0; - } - - /* If an RNG function was specified, get a random number - to prevent side channel analysis of k. */ - if (!g_rng_function) { - uECC_vli_clear(tmp, num_n_words); - tmp[0] = 1; - } else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) { - return 0; - } - - /* Prevent side channel analysis of uECC_vli_modInv() to determine - bits of k / the private key by premultiplying by a random number */ - uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ - uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */ - uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */ - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */ -#endif - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); -#else - uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); /* tmp = d */ -#endif - - s[num_n_words - 1] = 0; - uECC_vli_set(s, p, num_words); - uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ - - bits2int(tmp, message_hash, hash_size, curve); - uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ - uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ - if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) { - return 0; - } -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) signature + curve->num_bytes, (uint8_t *) s, curve->num_bytes); -#else - uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s); -#endif - return 1; -} - -/* For testing - sign with an explicitly specified k value */ -int uECC_sign_with_k(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - const uint8_t *k, - uint8_t *signature, - uECC_Curve curve) { - uECC_word_t k2[uECC_MAX_WORDS]; - bits2int(k2, k, BITS_TO_BYTES(curve->num_n_bits), curve); - return uECC_sign_with_k_internal(private_key, message_hash, hash_size, k2, signature, curve); -} - -int uECC_sign(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - uint8_t *signature, - uECC_Curve curve) { - uECC_word_t k[uECC_MAX_WORDS]; - uECC_word_t tries; - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { - return 0; - } - - if (uECC_sign_with_k_internal(private_key, message_hash, hash_size, k, signature, curve)) { - return 1; - } - } - return 0; -} - -/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always - the same size as the hash result size. */ -static void HMAC_init(const uECC_HashContext *hash_context, const uint8_t *K) { - uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; - unsigned i; - for (i = 0; i < hash_context->result_size; ++i) - pad[i] = K[i] ^ 0x36; - for (; i < hash_context->block_size; ++i) - pad[i] = 0x36; - - hash_context->init_hash(hash_context); - hash_context->update_hash(hash_context, pad, hash_context->block_size); -} - -static void HMAC_update(const uECC_HashContext *hash_context, - const uint8_t *message, - unsigned message_size) { - hash_context->update_hash(hash_context, message, message_size); -} - -static void HMAC_finish(const uECC_HashContext *hash_context, - const uint8_t *K, - uint8_t *result) { - uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; - unsigned i; - for (i = 0; i < hash_context->result_size; ++i) - pad[i] = K[i] ^ 0x5c; - for (; i < hash_context->block_size; ++i) - pad[i] = 0x5c; - - hash_context->finish_hash(hash_context, result); - - hash_context->init_hash(hash_context); - hash_context->update_hash(hash_context, pad, hash_context->block_size); - hash_context->update_hash(hash_context, result, hash_context->result_size); - hash_context->finish_hash(hash_context, result); -} - -/* V = HMAC_K(V) */ -static void update_V(const uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) { - HMAC_init(hash_context, K); - HMAC_update(hash_context, V, hash_context->result_size); - HMAC_finish(hash_context, K, V); -} - -/* Deterministic signing, similar to RFC 6979. Differences are: - * We just use H(m) directly rather than bits2octets(H(m)) - (it is not reduced modulo curve_n). - * We generate a value for k (aka T) directly rather than converting endianness. - - Layout of hash_context->tmp: | | (1 byte overlapped 0x00 or 0x01) / */ -int uECC_sign_deterministic(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - const uECC_HashContext *hash_context, - uint8_t *signature, - uECC_Curve curve) { - uint8_t *K = hash_context->tmp; - uint8_t *V = K + hash_context->result_size; - wordcount_t num_bytes = curve->num_bytes; - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; - uECC_word_t tries; - unsigned i; - for (i = 0; i < hash_context->result_size; ++i) { - V[i] = 0x01; - K[i] = 0; - } - - /* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */ - HMAC_init(hash_context, K); - V[hash_context->result_size] = 0x00; - HMAC_update(hash_context, V, hash_context->result_size + 1); - HMAC_update(hash_context, private_key, num_bytes); - HMAC_update(hash_context, message_hash, hash_size); - HMAC_finish(hash_context, K, K); - - update_V(hash_context, K, V); - - /* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */ - HMAC_init(hash_context, K); - V[hash_context->result_size] = 0x01; - HMAC_update(hash_context, V, hash_context->result_size + 1); - HMAC_update(hash_context, private_key, num_bytes); - HMAC_update(hash_context, message_hash, hash_size); - HMAC_finish(hash_context, K, K); - - update_V(hash_context, K, V); - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - uECC_word_t T[uECC_MAX_WORDS]; - uint8_t *T_ptr = (uint8_t *)T; - wordcount_t T_bytes = 0; - for (;;) { - update_V(hash_context, K, V); - for (i = 0; i < hash_context->result_size; ++i) { - T_ptr[T_bytes++] = V[i]; - if (T_bytes >= num_n_words * uECC_WORD_SIZE) { - goto filled; - } - } - } - filled: - if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) { - uECC_word_t mask = (uECC_word_t)-1; - T[num_n_words - 1] &= - mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits)); - } - - if (uECC_sign_with_k_internal(private_key, message_hash, hash_size, T, signature, curve)) { - return 1; - } - - /* K = HMAC_K(V || 0x00) */ - HMAC_init(hash_context, K); - V[hash_context->result_size] = 0x00; - HMAC_update(hash_context, V, hash_context->result_size + 1); - HMAC_finish(hash_context, K, K); - - update_V(hash_context, K, V); - } - return 0; -} - -static bitcount_t smax(bitcount_t a, bitcount_t b) { - return (a > b ? a : b); -} - -int uECC_verify(const uint8_t *public_key, - const uint8_t *message_hash, - unsigned hash_size, - const uint8_t *signature, - uECC_Curve curve) { - uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS]; - uECC_word_t z[uECC_MAX_WORDS]; - uECC_word_t sum[uECC_MAX_WORDS * 2]; - uECC_word_t rx[uECC_MAX_WORDS]; - uECC_word_t ry[uECC_MAX_WORDS]; - uECC_word_t tx[uECC_MAX_WORDS]; - uECC_word_t ty[uECC_MAX_WORDS]; - uECC_word_t tz[uECC_MAX_WORDS]; - const uECC_word_t *points[4]; - const uECC_word_t *point; - bitcount_t num_bits; - bitcount_t i; -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *_public = (uECC_word_t *)public_key; -#else - uECC_word_t _public[uECC_MAX_WORDS * 2]; -#endif - uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - - rx[num_n_words - 1] = 0; - r[num_n_words - 1] = 0; - s[num_n_words - 1] = 0; - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) r, signature, curve->num_bytes); - bcopy((uint8_t *) s, signature + curve->num_bytes, curve->num_bytes); -#else - uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); - uECC_vli_bytesToNative( - _public + num_words, public_key + curve->num_bytes, curve->num_bytes); - uECC_vli_bytesToNative(r, signature, curve->num_bytes); - uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes); -#endif - - /* r, s must not be 0. */ - if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) { - return 0; - } - - /* r, s must be < n. */ - if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || - uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { - return 0; - } - - /* Calculate u1 and u2. */ - uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ - u1[num_n_words - 1] = 0; - bits2int(u1, message_hash, hash_size, curve); - uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ - uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ - - /* Calculate sum = G + Q. */ - uECC_vli_set(sum, _public, num_words); - uECC_vli_set(sum + num_words, _public + num_words, num_words); - uECC_vli_set(tx, curve->G, num_words); - uECC_vli_set(ty, curve->G + num_words, num_words); - uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */ - XYcZ_add(tx, ty, sum, sum + num_words, curve); - uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */ - apply_z(sum, sum + num_words, z, curve); - - /* Use Shamir's trick to calculate u1*G + u2*Q */ - points[0] = 0; - points[1] = curve->G; - points[2] = _public; - points[3] = sum; - num_bits = smax(uECC_vli_numBits(u1, num_n_words), - uECC_vli_numBits(u2, num_n_words)); - - point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | - ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; - uECC_vli_set(rx, point, num_words); - uECC_vli_set(ry, point + num_words, num_words); - uECC_vli_clear(z, num_words); - z[0] = 1; - - for (i = num_bits - 2; i >= 0; --i) { - uECC_word_t index; - curve->double_jacobian(rx, ry, z, curve); - - index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1); - point = points[index]; - if (point) { - uECC_vli_set(tx, point, num_words); - uECC_vli_set(ty, point + num_words, num_words); - apply_z(tx, ty, z, curve); - uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */ - XYcZ_add(tx, ty, rx, ry, curve); - uECC_vli_modMult_fast(z, z, tz, curve); - } - } - - uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */ - apply_z(rx, ry, z, curve); - - /* v = x1 (mod n) */ - if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) { - uECC_vli_sub(rx, rx, curve->n, num_n_words); - } - - /* Accept only if v == r. */ - return (int)(uECC_vli_equal(rx, r, num_words)); -} - -#if uECC_ENABLE_VLI_API - -unsigned uECC_curve_num_words(uECC_Curve curve) { - return curve->num_words; -} - -unsigned uECC_curve_num_bytes(uECC_Curve curve) { - return curve->num_bytes; -} - -unsigned uECC_curve_num_bits(uECC_Curve curve) { - return curve->num_bytes * 8; -} - -unsigned uECC_curve_num_n_words(uECC_Curve curve) { - return BITS_TO_WORDS(curve->num_n_bits); -} - -unsigned uECC_curve_num_n_bytes(uECC_Curve curve) { - return BITS_TO_BYTES(curve->num_n_bits); -} - -unsigned uECC_curve_num_n_bits(uECC_Curve curve) { - return curve->num_n_bits; -} - -const uECC_word_t *uECC_curve_p(uECC_Curve curve) { - return curve->p; -} - -const uECC_word_t *uECC_curve_n(uECC_Curve curve) { - return curve->n; -} - -const uECC_word_t *uECC_curve_G(uECC_Curve curve) { - return curve->G; -} - -const uECC_word_t *uECC_curve_b(uECC_Curve curve) { - return curve->b; -} - -#if uECC_SUPPORT_COMPRESSED_POINT -void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve) { - curve->mod_sqrt(a, curve); -} -#endif - -void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve) { -#if (uECC_OPTIMIZATION_LEVEL > 0) - curve->mmod_fast(result, product); -#else - uECC_vli_mmod(result, product, curve->p, curve->num_words); -#endif -} - -void uECC_point_mult(uECC_word_t *result, - const uECC_word_t *point, - const uECC_word_t *scalar, - uECC_Curve curve) { - uECC_word_t tmp1[uECC_MAX_WORDS]; - uECC_word_t tmp2[uECC_MAX_WORDS]; - uECC_word_t *p2[2] = {tmp1, tmp2}; - uECC_word_t carry = regularize_k(scalar, tmp1, tmp2, curve); - - EccPoint_mult(result, point, p2[!carry], 0, curve->num_n_bits + 1, curve); -} - -#endif /* uECC_ENABLE_VLI_API */ diff --git a/lib/micro-ecc/uECC.h b/lib/micro-ecc/uECC.h deleted file mode 100644 index dcbdbfa8b4..0000000000 --- a/lib/micro-ecc/uECC.h +++ /dev/null @@ -1,367 +0,0 @@ -/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_H_ -#define _UECC_H_ - -#include - -/* Platform selection options. -If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros. -Possible values for uECC_PLATFORM are defined below: */ -#define uECC_arch_other 0 -#define uECC_x86 1 -#define uECC_x86_64 2 -#define uECC_arm 3 -#define uECC_arm_thumb 4 -#define uECC_arm_thumb2 5 -#define uECC_arm64 6 -#define uECC_avr 7 - -/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes). -If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your -platform. */ - -/* Optimization level; trade speed for code size. - Larger values produce code that is faster but larger. - Currently supported values are 0 - 4; 0 is unusably slow for most applications. - Optimization level 4 currently only has an effect ARM platforms where more than one - curve is enabled. */ -#ifndef uECC_OPTIMIZATION_LEVEL - #define uECC_OPTIMIZATION_LEVEL 2 -#endif - -/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be -used for (scalar) squaring instead of the generic multiplication function. This can make things -faster somewhat faster, but increases the code size. */ -#ifndef uECC_SQUARE_FUNC - #define uECC_SQUARE_FUNC 0 -#endif - -/* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will switch to native -little-endian format for *all* arrays passed in and out of the public API. This includes public -and private keys, shared secrets, signatures and message hashes. -Using this switch reduces the amount of call stack memory used by uECC, since less intermediate -translations are required. -Note that this will *only* work on native little-endian processors and it will treat the uint8_t -arrays passed into the public API as word arrays, therefore requiring the provided byte arrays -to be word aligned on architectures that do not support unaligned accesses. -IMPORTANT: Keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible -with keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use -the same endianness. */ -#ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN - #define uECC_VLI_NATIVE_LITTLE_ENDIAN 0 -#endif - -/* Curve support selection. Set to 0 to remove that curve. */ -#ifndef uECC_SUPPORTS_secp160r1 - #define uECC_SUPPORTS_secp160r1 1 -#endif -#ifndef uECC_SUPPORTS_secp192r1 - #define uECC_SUPPORTS_secp192r1 1 -#endif -#ifndef uECC_SUPPORTS_secp224r1 - #define uECC_SUPPORTS_secp224r1 1 -#endif -#ifndef uECC_SUPPORTS_secp256r1 - #define uECC_SUPPORTS_secp256r1 1 -#endif -#ifndef uECC_SUPPORTS_secp256k1 - #define uECC_SUPPORTS_secp256k1 1 -#endif - -/* Specifies whether compressed point format is supported. - Set to 0 to disable point compression/decompression functions. */ -#ifndef uECC_SUPPORT_COMPRESSED_POINT - #define uECC_SUPPORT_COMPRESSED_POINT 1 -#endif - -struct uECC_Curve_t; -typedef const struct uECC_Curve_t * uECC_Curve; - -#ifdef __cplusplus -extern "C" -{ -#endif - -#if uECC_SUPPORTS_secp160r1 -uECC_Curve uECC_secp160r1(void); -#endif -#if uECC_SUPPORTS_secp192r1 -uECC_Curve uECC_secp192r1(void); -#endif -#if uECC_SUPPORTS_secp224r1 -uECC_Curve uECC_secp224r1(void); -#endif -#if uECC_SUPPORTS_secp256r1 -uECC_Curve uECC_secp256r1(void); -#endif -#if uECC_SUPPORTS_secp256k1 -uECC_Curve uECC_secp256k1(void); -#endif - -/* uECC_RNG_Function type -The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if -'dest' was filled with random data, or 0 if the random data could not be generated. -The filled-in values should be either truly random, or from a cryptographically-secure PRNG. - -A correctly functioning RNG function must be set (using uECC_set_rng()) before calling -uECC_make_key() or uECC_sign(). - -Setting a correctly functioning RNG function improves the resistance to side-channel attacks -for uECC_shared_secret() and uECC_sign_deterministic(). - -A correct RNG function is set by default when building for Windows, Linux, or OS X. -If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom, -you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined -RNG function; you must provide your own. -*/ -typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size); - -/* uECC_set_rng() function. -Set the function that will be used to generate random bytes. The RNG function should -return 1 if the random data was generated, or 0 if the random data could not be generated. - -On platforms where there is no predefined RNG function (eg embedded platforms), this must -be called before uECC_make_key() or uECC_sign() are used. - -Inputs: - rng_function - The function that will be used to generate random bytes. -*/ -void uECC_set_rng(uECC_RNG_Function rng_function); - -/* uECC_get_rng() function. - -Returns the function that will be used to generate random bytes. -*/ -uECC_RNG_Function uECC_get_rng(void); - -/* uECC_curve_private_key_size() function. - -Returns the size of a private key for the curve in bytes. -*/ -int uECC_curve_private_key_size(uECC_Curve curve); - -/* uECC_curve_public_key_size() function. - -Returns the size of a public key for the curve in bytes. -*/ -int uECC_curve_public_key_size(uECC_Curve curve); - -/* uECC_make_key() function. -Create a public/private key pair. - -Outputs: - public_key - Will be filled in with the public key. Must be at least 2 * the curve size - (in bytes) long. For example, if the curve is secp256r1, public_key must be 64 - bytes long. - private_key - Will be filled in with the private key. Must be as long as the curve order; this - is typically the same as the curve size, except for secp160r1. For example, if the - curve is secp256r1, private_key must be 32 bytes long. - - For secp160r1, private_key must be 21 bytes long! Note that the first byte will - almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero). - -Returns 1 if the key pair was generated successfully, 0 if an error occurred. -*/ -int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve); - -/* uECC_shared_secret() function. -Compute a shared secret given your secret key and someone else's public key. If the public key -is not from a trusted source and has not been previously verified, you should verify it first -using uECC_valid_public_key(). -Note: It is recommended that you hash the result of uECC_shared_secret() before using it for -symmetric encryption or HMAC. - -Inputs: - public_key - The public key of the remote party. - private_key - Your private key. - -Outputs: - secret - Will be filled in with the shared secret value. Must be the same size as the - curve size; for example, if the curve is secp256r1, secret must be 32 bytes long. - -Returns 1 if the shared secret was generated successfully, 0 if an error occurred. -*/ -int uECC_shared_secret(const uint8_t *public_key, - const uint8_t *private_key, - uint8_t *secret, - uECC_Curve curve); - -#if uECC_SUPPORT_COMPRESSED_POINT -/* uECC_compress() function. -Compress a public key. - -Inputs: - public_key - The public key to compress. - -Outputs: - compressed - Will be filled in with the compressed public key. Must be at least - (curve size + 1) bytes long; for example, if the curve is secp256r1, - compressed must be 33 bytes long. -*/ -void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve); - -/* uECC_decompress() function. -Decompress a compressed public key. - -Inputs: - compressed - The compressed public key. - -Outputs: - public_key - Will be filled in with the decompressed public key. -*/ -void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve); -#endif /* uECC_SUPPORT_COMPRESSED_POINT */ - -/* uECC_valid_public_key() function. -Check to see if a public key is valid. - -Note that you are not required to check for a valid public key before using any other uECC -functions. However, you may wish to avoid spending CPU time computing a shared secret or -verifying a signature using an invalid public key. - -Inputs: - public_key - The public key to check. - -Returns 1 if the public key is valid, 0 if it is invalid. -*/ -int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve); - -/* uECC_compute_public_key() function. -Compute the corresponding public key for a private key. - -Inputs: - private_key - The private key to compute the public key for - -Outputs: - public_key - Will be filled in with the corresponding public key - -Returns 1 if the key was computed successfully, 0 if an error occurred. -*/ -int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve); - -/* uECC_sign() function. -Generate an ECDSA signature for a given hash value. - -Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to -this function along with your private key. - -Inputs: - private_key - Your private key. - message_hash - The hash of the message to sign. - hash_size - The size of message_hash in bytes. - -Outputs: - signature - Will be filled in with the signature value. Must be at least 2 * curve size long. - For example, if the curve is secp256r1, signature must be 64 bytes long. - -Returns 1 if the signature generated successfully, 0 if an error occurred. -*/ -int uECC_sign(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - uint8_t *signature, - uECC_Curve curve); - -/* uECC_HashContext structure. -This is used to pass in an arbitrary hash function to uECC_sign_deterministic(). -The structure will be used for multiple hash computations; each time a new hash -is computed, init_hash() will be called, followed by one or more calls to -update_hash(), and finally a call to finish_hash() to produce the resulting hash. - -The intention is that you will create a structure that includes uECC_HashContext -followed by any hash-specific data. For example: - -typedef struct SHA256_HashContext { - uECC_HashContext uECC; - SHA256_CTX ctx; -} SHA256_HashContext; - -void init_SHA256(uECC_HashContext *base) { - SHA256_HashContext *context = (SHA256_HashContext *)base; - SHA256_Init(&context->ctx); -} - -void update_SHA256(uECC_HashContext *base, - const uint8_t *message, - unsigned message_size) { - SHA256_HashContext *context = (SHA256_HashContext *)base; - SHA256_Update(&context->ctx, message, message_size); -} - -void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) { - SHA256_HashContext *context = (SHA256_HashContext *)base; - SHA256_Final(hash_result, &context->ctx); -} - -... when signing ... -{ - uint8_t tmp[32 + 32 + 64]; - SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}}; - uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature); -} -*/ -typedef struct uECC_HashContext { - void (*init_hash)(const struct uECC_HashContext *context); - void (*update_hash)(const struct uECC_HashContext *context, - const uint8_t *message, - unsigned message_size); - void (*finish_hash)(const struct uECC_HashContext *context, uint8_t *hash_result); - unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ - unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ - uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */ -} uECC_HashContext; - -/* uECC_sign_deterministic() function. -Generate an ECDSA signature for a given hash value, using a deterministic algorithm -(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling -this function; however, if the RNG is defined it will improve resistance to side-channel -attacks. - -Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to -this function along with your private key and a hash context. Note that the message_hash -does not need to be computed with the same hash function used by hash_context. - -Inputs: - private_key - Your private key. - message_hash - The hash of the message to sign. - hash_size - The size of message_hash in bytes. - hash_context - A hash context to use. - -Outputs: - signature - Will be filled in with the signature value. - -Returns 1 if the signature generated successfully, 0 if an error occurred. -*/ -int uECC_sign_deterministic(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - const uECC_HashContext *hash_context, - uint8_t *signature, - uECC_Curve curve); - -/* uECC_verify() function. -Verify an ECDSA signature. - -Usage: Compute the hash of the signed data using the same hash as the signer and -pass it to this function along with the signer's public key and the signature values (r and s). - -Inputs: - public_key - The signer's public key. - message_hash - The hash of the signed data. - hash_size - The size of message_hash in bytes. - signature - The signature value. - -Returns 1 if the signature is valid, 0 if it is invalid. -*/ -int uECC_verify(const uint8_t *public_key, - const uint8_t *message_hash, - unsigned hash_size, - const uint8_t *signature, - uECC_Curve curve); - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif - -#endif /* _UECC_H_ */ diff --git a/lib/micro-ecc/uECC_vli.h b/lib/micro-ecc/uECC_vli.h deleted file mode 100644 index 864cc33356..0000000000 --- a/lib/micro-ecc/uECC_vli.h +++ /dev/null @@ -1,172 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_VLI_H_ -#define _UECC_VLI_H_ - -#include "uECC.h" -#include "types.h" - -/* Functions for raw large-integer manipulation. These are only available - if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */ -#ifndef uECC_ENABLE_VLI_API - #define uECC_ENABLE_VLI_API 0 -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -#if uECC_ENABLE_VLI_API - -void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words); - -/* Constant-time comparison to zero - secure way to compare long integers */ -/* Returns 1 if vli == 0, 0 otherwise. */ -uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words); - -/* Returns nonzero if bit 'bit' of vli is set. */ -uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit); - -/* Counts the number of bits required to represent vli. */ -bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words); - -/* Sets dest = src. */ -void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words); - -/* Constant-time comparison function - secure way to compare long integers */ -/* Returns one if left == right, zero otherwise */ -uECC_word_t uECC_vli_equal(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Constant-time comparison function - secure way to compare long integers */ -/* Returns sign of left - right, in constant time. */ -cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words); - -/* Computes vli = vli >> 1. */ -void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words); - -/* Computes result = left + right, returning carry. Can modify in place. */ -uECC_word_t uECC_vli_add(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Computes result = left - right, returning borrow. Can modify in place. */ -uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Computes result = left * right. Result must be 2 * num_words long. */ -void uECC_vli_mult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Computes result = left^2. Result must be 2 * num_words long. */ -void uECC_vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words); - -/* Computes result = (left + right) % mod. - Assumes that left < mod and right < mod, and that result does not overlap mod. */ -void uECC_vli_modAdd(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Computes result = (left - right) % mod. - Assumes that left < mod and right < mod, and that result does not overlap mod. */ -void uECC_vli_modSub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Computes result = product % mod, where product is 2N words long. - Currently only designed to work for mod == curve->p or curve_n. */ -void uECC_vli_mmod(uECC_word_t *result, - uECC_word_t *product, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Calculates result = product (mod curve->p), where product is up to - 2 * curve->num_words long. */ -void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve); - -/* Computes result = (left * right) % mod. - Currently only designed to work for mod == curve->p or curve_n. */ -void uECC_vli_modMult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Computes result = (left * right) % curve->p. */ -void uECC_vli_modMult_fast(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - uECC_Curve curve); - -/* Computes result = left^2 % mod. - Currently only designed to work for mod == curve->p or curve_n. */ -void uECC_vli_modSquare(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Computes result = left^2 % curve->p. */ -void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left, uECC_Curve curve); - -/* Computes result = (1 / input) % mod.*/ -void uECC_vli_modInv(uECC_word_t *result, - const uECC_word_t *input, - const uECC_word_t *mod, - wordcount_t num_words); - -#if uECC_SUPPORT_COMPRESSED_POINT -/* Calculates a = sqrt(a) (mod curve->p) */ -void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve); -#endif - -/* Converts an integer in uECC native format to big-endian bytes. */ -void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, const uECC_word_t *native); -/* Converts big-endian bytes to an integer in uECC native format. */ -void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes, int num_bytes); - -unsigned uECC_curve_num_words(uECC_Curve curve); -unsigned uECC_curve_num_bytes(uECC_Curve curve); -unsigned uECC_curve_num_bits(uECC_Curve curve); -unsigned uECC_curve_num_n_words(uECC_Curve curve); -unsigned uECC_curve_num_n_bytes(uECC_Curve curve); -unsigned uECC_curve_num_n_bits(uECC_Curve curve); - -const uECC_word_t *uECC_curve_p(uECC_Curve curve); -const uECC_word_t *uECC_curve_n(uECC_Curve curve); -const uECC_word_t *uECC_curve_G(uECC_Curve curve); -const uECC_word_t *uECC_curve_b(uECC_Curve curve); - -int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve); - -/* Multiplies a point by a scalar. Points are represented by the X coordinate followed by - the Y coordinate in the same array, both coordinates are curve->num_words long. Note - that scalar must be curve->num_n_words long (NOT curve->num_words). */ -void uECC_point_mult(uECC_word_t *result, - const uECC_word_t *point, - const uECC_word_t *scalar, - uECC_Curve curve); - -/* Generates a random integer in the range 0 < random < top. - Both random and top have num_words words. */ -int uECC_generate_random_int(uECC_word_t *random, - const uECC_word_t *top, - wordcount_t num_words); - -#endif /* uECC_ENABLE_VLI_API */ - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif - -#endif /* _UECC_VLI_H_ */ diff --git a/lib/microtar.scons b/lib/microtar.scons index 6ee36d403c..54949fb42b 100644 --- a/lib/microtar.scons +++ b/lib/microtar.scons @@ -14,7 +14,7 @@ libenv.Append( CPPDEFINES=["MICROTAR_DISABLE_API_CHECKS"], ) -sources = libenv.GlobRecursive("*.c", "microtar/src") +sources = [File("microtar/src/microtar.c")] lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/misc.scons b/lib/misc.scons deleted file mode 100644 index 92fa5a106f..0000000000 --- a/lib/misc.scons +++ /dev/null @@ -1,58 +0,0 @@ -from fbt.util import GLOB_FILE_EXCLUSION - -Import("env") - -env.Append( - CPPPATH=[ - "#/lib/fnv1a_hash", - "#/lib/heatshrink", - "#/lib/micro-ecc", - "#/lib/nanopb", - "#/lib/u8g2", - ], - CPPDEFINES=[ - "PB_ENABLE_MALLOC", - ], - SDK_HEADERS=[ - File("micro-ecc/uECC.h"), - File("nanopb/pb.h"), - File("nanopb/pb_decode.h"), - File("nanopb/pb_encode.h"), - ], -) - - -libenv = env.Clone(FW_LIB_NAME="misc") -libenv.ApplyLibFlags() - -sources = [] - -libs_recurse = [ - "micro-ecc", - "u8g2", - "update_util", -] - -for lib in libs_recurse: - sources += libenv.GlobRecursive("*.c*", lib) - -libs_plain = [ - "nanopb", -] - -for lib in libs_plain: - sources += Glob( - lib + "/*.c*", - exclude=GLOB_FILE_EXCLUSION, - source=True, - ) - -sources += Glob( - "heatshrink/heatshrink_*.c*", - exclude=GLOB_FILE_EXCLUSION, - source=True, -) - -lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) -libenv.Install("${LIB_DIST_DIR}", lib) -Return("lib") diff --git a/lib/mlib.scons b/lib/mlib.scons new file mode 100644 index 0000000000..2bdd372895 --- /dev/null +++ b/lib/mlib.scons @@ -0,0 +1,27 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/mlib", + ], + SDK_HEADERS=[ + *( + File(f"#/lib/mlib/m-{name}.h") + for name in ( + "algo", + "array", + "bptree", + "core", + "deque", + "dict", + "list", + "rbtree", + "tuple", + "variant", + ) + ), + ], + CPPDEFINES=[ + '"M_MEMORY_FULL(x)=abort()"', + ], +) diff --git a/lib/music_worker/SConscript b/lib/music_worker/SConscript index 36d01d8596..0439286ceb 100644 --- a/lib/music_worker/SConscript +++ b/lib/music_worker/SConscript @@ -7,6 +7,9 @@ env.Append( SDK_HEADERS=[ File("music_worker.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="music_worker") diff --git a/lib/nanopb.scons b/lib/nanopb.scons new file mode 100644 index 0000000000..43e828b85e --- /dev/null +++ b/lib/nanopb.scons @@ -0,0 +1,31 @@ +from fbt.util import GLOB_FILE_EXCLUSION + +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/nanopb", + ], + CPPDEFINES=[ + "PB_ENABLE_MALLOC", + ], + SDK_HEADERS=[ + File("nanopb/pb.h"), + File("nanopb/pb_decode.h"), + File("nanopb/pb_encode.h"), + ], +) + + +libenv = env.Clone(FW_LIB_NAME="nanopb") +libenv.ApplyLibFlags() + +sources = Glob( + "nanopb/*.c*", + exclude=GLOB_FILE_EXCLUSION, + source=True, +) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 605a8639dd..21f2fb49f6 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -4,6 +4,9 @@ env.Append( CPPPATH=[ "#/lib/nfc", ], + LINT_SOURCES=[ + Dir("."), + ], SDK_HEADERS=[ # Main File("nfc.h"), diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index 129dcdf5e1..8e65eca5a5 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -56,7 +56,7 @@ bool mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf) { } bool mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* buf) { - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint32_t bytes_free : 3 * BITS_IN_BYTE; } MfDesfireFreeMemoryLayout; @@ -74,7 +74,7 @@ bool mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* bu } bool mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf) { - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { bool is_master_key_changeable : 1; bool is_free_directory_list : 1; bool is_free_create_delete : 1; @@ -143,30 +143,30 @@ bool mf_desfire_file_id_parse(MfDesfireFileId* data, uint32_t index, const BitBu bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer* buf) { bool parsed = false; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint8_t type; uint8_t comm; uint16_t access_rights; } MfDesfireFileSettingsHeader; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint32_t size : 3 * BITS_IN_BYTE; } MfDesfireFileSettingsData; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint32_t lo_limit; uint32_t hi_limit; uint32_t limited_credit_value; uint8_t limited_credit_enabled; } MfDesfireFileSettingsValue; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint32_t size : 3 * BITS_IN_BYTE; uint32_t max : 3 * BITS_IN_BYTE; uint32_t cur : 3 * BITS_IN_BYTE; } MfDesfireFileSettingsRecord; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { MfDesfireFileSettingsHeader header; union { MfDesfireFileSettingsData data; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 747f5937ad..4786b18253 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -130,7 +130,7 @@ typedef enum { MfUltralightMirrorUidCounter, } MfUltralightMirrorConf; -typedef struct __attribute__((packed)) { +typedef struct FURI_PACKED { union { uint8_t value; struct { diff --git a/lib/print/SConscript b/lib/print/SConscript index f34c8152fa..819e60bf07 100644 --- a/lib/print/SConscript +++ b/lib/print/SConscript @@ -100,6 +100,9 @@ env.Append( SDK_HEADERS=[ File("wrappers.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="print") diff --git a/lib/pulse_reader/SConscript b/lib/pulse_reader/SConscript index f00851a20d..a134783798 100644 --- a/lib/pulse_reader/SConscript +++ b/lib/pulse_reader/SConscript @@ -7,6 +7,9 @@ env.Append( SDK_HEADERS=[ File("pulse_reader.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="pulse_reader") diff --git a/lib/qrcode/qrcode.c b/lib/qrcode/qrcode.c deleted file mode 100644 index fb5bd8a6e7..0000000000 --- a/lib/qrcode/qrcode.c +++ /dev/null @@ -1,975 +0,0 @@ -/** - * The MIT License (MIT) - * - * This library is written and maintained by Richard Moore. - * Major parts were derived from Project Nayuki's library. - * - * Copyright (c) 2017 Richard Moore (https://github.com/ricmoo/QRCode) - * Copyright (c) 2017 Project Nayuki (https://www.nayuki.io/page/qr-code-generator-library) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * Special thanks to Nayuki (https://www.nayuki.io/) from which this library was - * heavily inspired and compared against. - * - * See: https://github.com/nayuki/QR-Code-generator/tree/master/cpp - */ - -#include "qrcode.h" - -#include -#include - -#pragma mark - Error Correction Lookup tables - -#if LOCK_VERSION == 0 - -static const uint16_t NUM_ERROR_CORRECTION_CODEWORDS[4][40] = { - // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level - {10, 16, 26, 36, 48, 64, 72, 88, 110, 130, 150, 176, 198, 216, - 240, 280, 308, 338, 364, 416, 442, 476, 504, 560, 588, 644, 700, 728, - 784, 812, 868, 924, 980, 1036, 1064, 1120, 1204, 1260, 1316, 1372}, // Medium - {7, 10, 15, 20, 26, 36, 40, 48, 60, 72, 80, 96, 104, 120, - 132, 144, 168, 180, 196, 224, 224, 252, 270, 300, 312, 336, 360, 390, - 420, 450, 480, 510, 540, 570, 570, 600, 630, 660, 720, 750}, // Low - {17, 28, 44, 64, 88, 112, 130, 156, 192, 224, 264, 308, 352, 384, - 432, 480, 532, 588, 650, 700, 750, 816, 900, 960, 1050, 1110, 1200, 1260, - 1350, 1440, 1530, 1620, 1710, 1800, 1890, 1980, 2100, 2220, 2310, 2430}, // High - {13, 22, 36, 52, 72, 96, 108, 132, 160, 192, 224, 260, 288, 320, - 360, 408, 448, 504, 546, 600, 644, 690, 750, 810, 870, 952, 1020, 1050, - 1140, 1200, 1290, 1350, 1440, 1530, 1590, 1680, 1770, 1860, 1950, 2040}, // Quartile -}; - -static const uint8_t NUM_ERROR_CORRECTION_BLOCKS[4][40] = { - // Version: (note that index 0 is for padding, and is set to an illegal value) - // 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level - {1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, - 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium - {1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, - 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low - {1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, - 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High - {1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, - 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile -}; - -static const uint16_t NUM_RAW_DATA_MODULES[40] = { - // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 208, - 359, - 567, - 807, - 1079, - 1383, - 1568, - 1936, - 2336, - 2768, - 3232, - 3728, - 4256, - 4651, - 5243, - 5867, - 6523, - // 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 7211, - 7931, - 8683, - 9252, - 10068, - 10916, - 11796, - 12708, - 13652, - 14628, - 15371, - 16411, - 17483, - 18587, - // 32, 33, 34, 35, 36, 37, 38, 39, 40 - 19723, - 20891, - 22091, - 23008, - 24272, - 25568, - 26896, - 28256, - 29648}; - -// @TODO: Put other LOCK_VERSIONS here -#elif LOCK_VERSION == 3 - -static const int16_t NUM_ERROR_CORRECTION_CODEWORDS[4] = {26, 15, 44, 36}; - -static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4] = {1, 1, 2, 2}; - -static const uint16_t NUM_RAW_DATA_MODULES = 567; - -#else - -#error Unsupported LOCK_VERSION (add it...) - -#endif - -static int max(int a, int b) { - if(a > b) { - return a; - } - return b; -} - -/* -static int abs(int value) { - if (value < 0) { return -value; } - return value; -} -*/ - -#pragma mark - Mode testing and conversion - -static int8_t getAlphanumeric(char c) { - if(c >= '0' && c <= '9') { - return (c - '0'); - } - if(c >= 'A' && c <= 'Z') { - return (c - 'A' + 10); - } - - switch(c) { - case ' ': - return 36; - case '$': - return 37; - case '%': - return 38; - case '*': - return 39; - case '+': - return 40; - case '-': - return 41; - case '.': - return 42; - case '/': - return 43; - case ':': - return 44; - } - - return -1; -} - -static bool isAlphanumeric(const char* text, uint16_t length) { - while(length != 0) { - if(getAlphanumeric(text[--length]) == -1) { - return false; - } - } - return true; -} - -static bool isNumeric(const char* text, uint16_t length) { - while(length != 0) { - char c = text[--length]; - if(c < '0' || c > '9') { - return false; - } - } - return true; -} - -#pragma mark - Counting - -// We store the following tightly packed (less 8) in modeInfo -// <=9 <=26 <= 40 -// NUMERIC ( 10, 12, 14); -// ALPHANUMERIC ( 9, 11, 13); -// BYTE ( 8, 16, 16); -static char getModeBits(uint8_t version, uint8_t mode) { - // Note: We use 15 instead of 16; since 15 doesn't exist and we cannot store 16 (8 + 8) in 3 bits - // hex(int("".join(reversed([('00' + bin(x - 8)[2:])[-3:] for x in [10, 9, 8, 12, 11, 15, 14, 13, 15]])), 2)) - unsigned int modeInfo = 0x7bbb80a; - -#if LOCK_VERSION == 0 || LOCK_VERSION > 9 - if(version > 9) { - modeInfo >>= 9; - } -#endif - -#if LOCK_VERSION == 0 || LOCK_VERSION > 26 - if(version > 26) { - modeInfo >>= 9; - } -#endif - - char result = 8 + ((modeInfo >> (3 * mode)) & 0x07); - if(result == 15) { - result = 16; - } - - return result; -} - -#pragma mark - BitBucket - -typedef struct BitBucket { - uint32_t bitOffsetOrWidth; - uint16_t capacityBytes; - uint8_t* data; -} BitBucket; - -/* -void bb_dump(BitBucket *bitBuffer) { - printf("Buffer: "); - for (uint32_t i = 0; i < bitBuffer->capacityBytes; i++) { - printf("%02x", bitBuffer->data[i]); - if ((i % 4) == 3) { printf(" "); } - } - printf("\n"); -} -*/ - -static uint16_t bb_getGridSizeBytes(uint8_t size) { - return (((size * size) + 7) / 8); -} - -static uint16_t bb_getBufferSizeBytes(uint32_t bits) { - return ((bits + 7) / 8); -} - -static void bb_initBuffer(BitBucket* bitBuffer, uint8_t* data, int32_t capacityBytes) { - bitBuffer->bitOffsetOrWidth = 0; - bitBuffer->capacityBytes = capacityBytes; - bitBuffer->data = data; - - memset(data, 0, bitBuffer->capacityBytes); -} - -static void bb_initGrid(BitBucket* bitGrid, uint8_t* data, uint8_t size) { - bitGrid->bitOffsetOrWidth = size; - bitGrid->capacityBytes = bb_getGridSizeBytes(size); - bitGrid->data = data; - - memset(data, 0, bitGrid->capacityBytes); -} - -static void bb_appendBits(BitBucket* bitBuffer, uint32_t val, uint8_t length) { - uint32_t offset = bitBuffer->bitOffsetOrWidth; - for(int8_t i = length - 1; i >= 0; i--, offset++) { - bitBuffer->data[offset >> 3] |= ((val >> i) & 1) << (7 - (offset & 7)); - } - bitBuffer->bitOffsetOrWidth = offset; -} -/* -void bb_setBits(BitBucket *bitBuffer, uint32_t val, int offset, uint8_t length) { - for (int8_t i = length - 1; i >= 0; i--, offset++) { - bitBuffer->data[offset >> 3] |= ((val >> i) & 1) << (7 - (offset & 7)); - } -} -*/ -static void bb_setBit(BitBucket* bitGrid, uint8_t x, uint8_t y, bool on) { - uint32_t offset = y * bitGrid->bitOffsetOrWidth + x; - uint8_t mask = 1 << (7 - (offset & 0x07)); - if(on) { - bitGrid->data[offset >> 3] |= mask; - } else { - bitGrid->data[offset >> 3] &= ~mask; - } -} - -static void bb_invertBit(BitBucket* bitGrid, uint8_t x, uint8_t y, bool invert) { - uint32_t offset = y * bitGrid->bitOffsetOrWidth + x; - uint8_t mask = 1 << (7 - (offset & 0x07)); - bool on = ((bitGrid->data[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0); - if(on ^ invert) { - bitGrid->data[offset >> 3] |= mask; - } else { - bitGrid->data[offset >> 3] &= ~mask; - } -} - -static bool bb_getBit(BitBucket* bitGrid, uint8_t x, uint8_t y) { - uint32_t offset = y * bitGrid->bitOffsetOrWidth + x; - return (bitGrid->data[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0; -} - -#pragma mark - Drawing Patterns - -// XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical -// properties, calling applyMask(m) twice with the same value is equivalent to no change at all. -// This means it is possible to apply a mask, undo it, and try another mask. Note that a final -// well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.). -static void applyMask(BitBucket* modules, BitBucket* isFunction, uint8_t mask) { - uint8_t size = modules->bitOffsetOrWidth; - - for(uint8_t y = 0; y < size; y++) { - for(uint8_t x = 0; x < size; x++) { - if(bb_getBit(isFunction, x, y)) { - continue; - } - - bool invert = 0; - switch(mask) { - case 0: - invert = (x + y) % 2 == 0; - break; - case 1: - invert = y % 2 == 0; - break; - case 2: - invert = x % 3 == 0; - break; - case 3: - invert = (x + y) % 3 == 0; - break; - case 4: - invert = (x / 3 + y / 2) % 2 == 0; - break; - case 5: - invert = x * y % 2 + x * y % 3 == 0; - break; - case 6: - invert = (x * y % 2 + x * y % 3) % 2 == 0; - break; - case 7: - invert = ((x + y) % 2 + x * y % 3) % 2 == 0; - break; - } - bb_invertBit(modules, x, y, invert); - } - } -} - -static void - setFunctionModule(BitBucket* modules, BitBucket* isFunction, uint8_t x, uint8_t y, bool on) { - bb_setBit(modules, x, y, on); - bb_setBit(isFunction, x, y, true); -} - -// Draws a 9*9 finder pattern including the border separator, with the center module at (x, y). -static void drawFinderPattern(BitBucket* modules, BitBucket* isFunction, uint8_t x, uint8_t y) { - uint8_t size = modules->bitOffsetOrWidth; - - for(int8_t i = -4; i <= 4; i++) { - for(int8_t j = -4; j <= 4; j++) { - uint8_t dist = max(abs(i), abs(j)); // Chebyshev/infinity norm - int16_t xx = x + j, yy = y + i; - if(0 <= xx && xx < size && 0 <= yy && yy < size) { - setFunctionModule(modules, isFunction, xx, yy, dist != 2 && dist != 4); - } - } - } -} - -// Draws a 5*5 alignment pattern, with the center module at (x, y). -static void drawAlignmentPattern(BitBucket* modules, BitBucket* isFunction, uint8_t x, uint8_t y) { - for(int8_t i = -2; i <= 2; i++) { - for(int8_t j = -2; j <= 2; j++) { - setFunctionModule(modules, isFunction, x + j, y + i, max(abs(i), abs(j)) != 1); - } - } -} - -// Draws two copies of the format bits (with its own error correction code) -// based on the given mask and this object's error correction level field. -static void drawFormatBits(BitBucket* modules, BitBucket* isFunction, uint8_t ecc, uint8_t mask) { - uint8_t size = modules->bitOffsetOrWidth; - - // Calculate error correction code and pack bits - uint32_t data = ecc << 3 | mask; // errCorrLvl is uint2, mask is uint3 - uint32_t rem = data; - for(int i = 0; i < 10; i++) { - rem = (rem << 1) ^ ((rem >> 9) * 0x537); - } - - data = data << 10 | rem; - data ^= 0x5412; // uint15 - - // Draw first copy - for(uint8_t i = 0; i <= 5; i++) { - setFunctionModule(modules, isFunction, 8, i, ((data >> i) & 1) != 0); - } - - setFunctionModule(modules, isFunction, 8, 7, ((data >> 6) & 1) != 0); - setFunctionModule(modules, isFunction, 8, 8, ((data >> 7) & 1) != 0); - setFunctionModule(modules, isFunction, 7, 8, ((data >> 8) & 1) != 0); - - for(int8_t i = 9; i < 15; i++) { - setFunctionModule(modules, isFunction, 14 - i, 8, ((data >> i) & 1) != 0); - } - - // Draw second copy - for(int8_t i = 0; i <= 7; i++) { - setFunctionModule(modules, isFunction, size - 1 - i, 8, ((data >> i) & 1) != 0); - } - - for(int8_t i = 8; i < 15; i++) { - setFunctionModule(modules, isFunction, 8, size - 15 + i, ((data >> i) & 1) != 0); - } - - setFunctionModule(modules, isFunction, 8, size - 8, true); -} - -// Draws two copies of the version bits (with its own error correction code), -// based on this object's version field (which only has an effect for 7 <= version <= 40). -static void drawVersion(BitBucket* modules, BitBucket* isFunction, uint8_t version) { - int8_t size = modules->bitOffsetOrWidth; - -#if LOCK_VERSION != 0 && LOCK_VERSION < 7 - return; - -#else - if(version < 7) { - return; - } - - // Calculate error correction code and pack bits - uint32_t rem = version; // version is uint6, in the range [7, 40] - for(uint8_t i = 0; i < 12; i++) { - rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); - } - - uint32_t data = version << 12 | rem; // uint18 - - // Draw two copies - for(uint8_t i = 0; i < 18; i++) { - bool bit = ((data >> i) & 1) != 0; - uint8_t a = size - 11 + i % 3, b = i / 3; - setFunctionModule(modules, isFunction, a, b, bit); - setFunctionModule(modules, isFunction, b, a, bit); - } - -#endif -} - -static void - drawFunctionPatterns(BitBucket* modules, BitBucket* isFunction, uint8_t version, uint8_t ecc) { - uint8_t size = modules->bitOffsetOrWidth; - - // Draw the horizontal and vertical timing patterns - for(uint8_t i = 0; i < size; i++) { - setFunctionModule(modules, isFunction, 6, i, i % 2 == 0); - setFunctionModule(modules, isFunction, i, 6, i % 2 == 0); - } - - // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) - drawFinderPattern(modules, isFunction, 3, 3); - drawFinderPattern(modules, isFunction, size - 4, 3); - drawFinderPattern(modules, isFunction, 3, size - 4); - -#if LOCK_VERSION == 0 || LOCK_VERSION > 1 - - if(version > 1) { - // Draw the numerous alignment patterns - - uint8_t alignCount = version / 7 + 2; - uint8_t step; - if(version != 32) { - step = (version * 4 + alignCount * 2 + 1) / (2 * alignCount - 2) * - 2; // ceil((size - 13) / (2*numAlign - 2)) * 2 - } else { // C-C-C-Combo breaker! - step = 26; - } - - uint8_t alignPositionIndex = alignCount - 1; - uint8_t alignPosition[alignCount]; - - alignPosition[0] = 6; - - uint8_t size = version * 4 + 17; - for(uint8_t i = 0, pos = size - 7; i < alignCount - 1; i++, pos -= step) { - alignPosition[alignPositionIndex--] = pos; - } - - for(uint8_t i = 0; i < alignCount; i++) { - for(uint8_t j = 0; j < alignCount; j++) { - if((i == 0 && j == 0) || (i == 0 && j == alignCount - 1) || - (i == alignCount - 1 && j == 0)) { - continue; // Skip the three finder corners - } else { - drawAlignmentPattern(modules, isFunction, alignPosition[i], alignPosition[j]); - } - } - } - } - -#endif - - // Draw configuration data - drawFormatBits( - modules, isFunction, ecc, 0); // Dummy mask value; overwritten later in the constructor - drawVersion(modules, isFunction, version); -} - -// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire -// data area of this QR Code symbol. Function modules need to be marked off before this is called. -static void drawCodewords(BitBucket* modules, BitBucket* isFunction, BitBucket* codewords) { - uint32_t bitLength = codewords->bitOffsetOrWidth; - uint8_t* data = codewords->data; - - uint8_t size = modules->bitOffsetOrWidth; - - // Bit index into the data - uint32_t i = 0; - - // Do the funny zigzag scan - for(int16_t right = size - 1; right >= 1; - right -= 2) { // Index of right column in each column pair - if(right == 6) { - right = 5; - } - - for(uint8_t vert = 0; vert < size; vert++) { // Vertical counter - for(int j = 0; j < 2; j++) { - uint8_t x = right - j; // Actual x coordinate - bool upwards = ((right & 2) == 0) ^ (x < 6); - uint8_t y = upwards ? size - 1 - vert : vert; // Actual y coordinate - if(!bb_getBit(isFunction, x, y) && i < bitLength) { - bb_setBit(modules, x, y, ((data[i >> 3] >> (7 - (i & 7))) & 1) != 0); - i++; - } - // If there are any remainder bits (0 to 7), they are already - // set to 0/false/white when the grid of modules was initialized - } - } - } -} - -#pragma mark - Penalty Calculation - -#define PENALTY_N1 3 -#define PENALTY_N2 3 -#define PENALTY_N3 40 -#define PENALTY_N4 10 - -// Calculates and returns the penalty score based on state of this QR Code's current modules. -// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. -// @TODO: This can be optimized by working with the bytes instead of bits. -static uint32_t getPenaltyScore(BitBucket* modules) { - uint32_t result = 0; - - uint8_t size = modules->bitOffsetOrWidth; - - // Adjacent modules in row having same color - for(uint8_t y = 0; y < size; y++) { - bool colorX = bb_getBit(modules, 0, y); - for(uint8_t x = 1, runX = 1; x < size; x++) { - bool cx = bb_getBit(modules, x, y); - if(cx != colorX) { - colorX = cx; - runX = 1; - - } else { - runX++; - if(runX == 5) { - result += PENALTY_N1; - } else if(runX > 5) { - result++; - } - } - } - } - - // Adjacent modules in column having same color - for(uint8_t x = 0; x < size; x++) { - bool colorY = bb_getBit(modules, x, 0); - for(uint8_t y = 1, runY = 1; y < size; y++) { - bool cy = bb_getBit(modules, x, y); - if(cy != colorY) { - colorY = cy; - runY = 1; - } else { - runY++; - if(runY == 5) { - result += PENALTY_N1; - } else if(runY > 5) { - result++; - } - } - } - } - - uint16_t black = 0; - for(uint8_t y = 0; y < size; y++) { - uint16_t bitsRow = 0, bitsCol = 0; - for(uint8_t x = 0; x < size; x++) { - bool color = bb_getBit(modules, x, y); - - // 2*2 blocks of modules having same color - if(x > 0 && y > 0) { - bool colorUL = bb_getBit(modules, x - 1, y - 1); - bool colorUR = bb_getBit(modules, x, y - 1); - bool colorL = bb_getBit(modules, x - 1, y); - if(color == colorUL && color == colorUR && color == colorL) { - result += PENALTY_N2; - } - } - - // Finder-like pattern in rows and columns - bitsRow = ((bitsRow << 1) & 0x7FF) | color; - bitsCol = ((bitsCol << 1) & 0x7FF) | bb_getBit(modules, y, x); - - // Needs 11 bits accumulated - if(x >= 10) { - if(bitsRow == 0x05D || bitsRow == 0x5D0) { - result += PENALTY_N3; - } - if(bitsCol == 0x05D || bitsCol == 0x5D0) { - result += PENALTY_N3; - } - } - - // Balance of black and white modules - if(color) { - black++; - } - } - } - - // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)% - uint16_t total = size * size; - for(uint16_t k = 0; black * 20 < (9 - k) * total || black * 20 > (11 + k) * total; k++) { - result += PENALTY_N4; - } - - return result; -} - -#pragma mark - Reed-Solomon Generator - -static uint8_t rs_multiply(uint8_t x, uint8_t y) { - // Russian peasant multiplication - // See: https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication - uint16_t z = 0; - for(int8_t i = 7; i >= 0; i--) { - z = (z << 1) ^ ((z >> 7) * 0x11D); - z ^= ((y >> i) & 1) * x; - } - return z; -} - -static void rs_init(uint8_t degree, uint8_t* coeff) { - memset(coeff, 0, degree); - coeff[degree - 1] = 1; - - // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), - // drop the highest term, and store the rest of the coefficients in order of descending powers. - // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). - uint16_t root = 1; - for(uint8_t i = 0; i < degree; i++) { - // Multiply the current product by (x - r^i) - for(uint8_t j = 0; j < degree; j++) { - coeff[j] = rs_multiply(coeff[j], root); - if(j + 1 < degree) { - coeff[j] ^= coeff[j + 1]; - } - } - root = (root << 1) ^ ((root >> 7) * 0x11D); // Multiply by 0x02 mod GF(2^8/0x11D) - } -} - -static void rs_getRemainder( - uint8_t degree, - uint8_t* coeff, - uint8_t* data, - uint8_t length, - uint8_t* result, - uint8_t stride) { - // Compute the remainder by performing polynomial division - - //for (uint8_t i = 0; i < degree; i++) { result[] = 0; } - //memset(result, 0, degree); - - for(uint8_t i = 0; i < length; i++) { - uint8_t factor = data[i] ^ result[0]; - for(uint8_t j = 1; j < degree; j++) { - result[(j - 1) * stride] = result[j * stride]; - } - result[(degree - 1) * stride] = 0; - - for(uint8_t j = 0; j < degree; j++) { - result[j * stride] ^= rs_multiply(coeff[j], factor); - } - } -} - -#pragma mark - QrCode - -static int8_t encodeDataCodewords( - BitBucket* dataCodewords, - const uint8_t* text, - uint16_t length, - uint8_t version) { - int8_t mode = MODE_BYTE; - - if(isNumeric((char*)text, length)) { - mode = MODE_NUMERIC; - bb_appendBits(dataCodewords, 1 << MODE_NUMERIC, 4); - bb_appendBits(dataCodewords, length, getModeBits(version, MODE_NUMERIC)); - - uint16_t accumData = 0; - uint8_t accumCount = 0; - for(uint16_t i = 0; i < length; i++) { - accumData = accumData * 10 + ((char)(text[i]) - '0'); - accumCount++; - if(accumCount == 3) { - bb_appendBits(dataCodewords, accumData, 10); - accumData = 0; - accumCount = 0; - } - } - - // 1 or 2 digits remaining - if(accumCount > 0) { - bb_appendBits(dataCodewords, accumData, accumCount * 3 + 1); - } - - } else if(isAlphanumeric((char*)text, length)) { - mode = MODE_ALPHANUMERIC; - bb_appendBits(dataCodewords, 1 << MODE_ALPHANUMERIC, 4); - bb_appendBits(dataCodewords, length, getModeBits(version, MODE_ALPHANUMERIC)); - - uint16_t accumData = 0; - uint8_t accumCount = 0; - for(uint16_t i = 0; i < length; i++) { - accumData = accumData * 45 + getAlphanumeric((char)(text[i])); - accumCount++; - if(accumCount == 2) { - bb_appendBits(dataCodewords, accumData, 11); - accumData = 0; - accumCount = 0; - } - } - - // 1 character remaining - if(accumCount > 0) { - bb_appendBits(dataCodewords, accumData, 6); - } - - } else { - bb_appendBits(dataCodewords, 1 << MODE_BYTE, 4); - bb_appendBits(dataCodewords, length, getModeBits(version, MODE_BYTE)); - for(uint16_t i = 0; i < length; i++) { - bb_appendBits(dataCodewords, (char)(text[i]), 8); - } - } - - //bb_setBits(dataCodewords, length, 4, getModeBits(version, mode)); - - return mode; -} - -static void performErrorCorrection(uint8_t version, uint8_t ecc, BitBucket* data) { - // See: http://www.thonky.com/qr-code-tutorial/structure-final-message - -#if LOCK_VERSION == 0 - uint8_t numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecc][version - 1]; - uint16_t totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[ecc][version - 1]; - uint16_t moduleCount = NUM_RAW_DATA_MODULES[version - 1]; -#else - uint8_t numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecc]; - uint16_t totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[ecc]; - uint16_t moduleCount = NUM_RAW_DATA_MODULES; -#endif - - uint8_t blockEccLen = totalEcc / numBlocks; - uint8_t numShortBlocks = numBlocks - moduleCount / 8 % numBlocks; - uint8_t shortBlockLen = moduleCount / 8 / numBlocks; - - uint8_t shortDataBlockLen = shortBlockLen - blockEccLen; - - uint8_t result[data->capacityBytes]; - memset(result, 0, sizeof(result)); - - uint8_t coeff[blockEccLen]; - rs_init(blockEccLen, coeff); - - uint16_t offset = 0; - uint8_t* dataBytes = data->data; - - // Interleave all short blocks - for(uint8_t i = 0; i < shortDataBlockLen; i++) { - uint16_t index = i; - uint8_t stride = shortDataBlockLen; - for(uint8_t blockNum = 0; blockNum < numBlocks; blockNum++) { - result[offset++] = dataBytes[index]; - -#if LOCK_VERSION == 0 || LOCK_VERSION >= 5 - if(blockNum == numShortBlocks) { - stride++; - } -#endif - index += stride; - } - } - - // Version less than 5 only have short blocks -#if LOCK_VERSION == 0 || LOCK_VERSION >= 5 - { - // Interleave long blocks - uint16_t index = shortDataBlockLen * (numShortBlocks + 1); - uint8_t stride = shortDataBlockLen; - for(uint8_t blockNum = 0; blockNum < numBlocks - numShortBlocks; blockNum++) { - result[offset++] = dataBytes[index]; - - if(blockNum == 0) { - stride++; - } - index += stride; - } - } -#endif - - // Add all ecc blocks, interleaved - uint8_t blockSize = shortDataBlockLen; - for(uint8_t blockNum = 0; blockNum < numBlocks; blockNum++) { -#if LOCK_VERSION == 0 || LOCK_VERSION >= 5 - if(blockNum == numShortBlocks) { - blockSize++; - } -#endif - rs_getRemainder( - blockEccLen, coeff, dataBytes, blockSize, &result[offset + blockNum], numBlocks); - dataBytes += blockSize; - } - - memcpy(data->data, result, data->capacityBytes); - data->bitOffsetOrWidth = moduleCount; -} - -// We store the Format bits tightly packed into a single byte (each of the 4 modes is 2 bits) -// The format bits can be determined by ECC_FORMAT_BITS >> (2 * ecc) -static const uint8_t ECC_FORMAT_BITS = (0x02 << 6) | (0x03 << 4) | (0x00 << 2) | (0x01 << 0); - -#pragma mark - Public QRCode functions - -uint16_t qrcode_getBufferSize(uint8_t version) { - return bb_getGridSizeBytes(4 * version + 17); -} - -// @TODO: Return error if data is too big. -int8_t qrcode_initBytes( - QRCode* qrcode, - uint8_t* modules, - uint8_t version, - uint8_t ecc, - uint8_t* data, - uint16_t length) { - uint8_t size = version * 4 + 17; - qrcode->version = version; - qrcode->size = size; - qrcode->ecc = ecc; - qrcode->modules = modules; - - uint8_t eccFormatBits = (ECC_FORMAT_BITS >> (2 * ecc)) & 0x03; - -#if LOCK_VERSION == 0 - uint16_t moduleCount = NUM_RAW_DATA_MODULES[version - 1]; - uint16_t dataCapacity = - moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits][version - 1]; -#else - version = LOCK_VERSION; - uint16_t moduleCount = NUM_RAW_DATA_MODULES; - uint16_t dataCapacity = moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits]; -#endif - - struct BitBucket codewords; - uint8_t codewordBytes[bb_getBufferSizeBytes(moduleCount)]; - bb_initBuffer(&codewords, codewordBytes, (int32_t)sizeof(codewordBytes)); - - // Place the data code words into the buffer - int8_t mode = encodeDataCodewords(&codewords, data, length, version); - - if(mode < 0) { - return -1; - } - qrcode->mode = mode; - - // Add terminator and pad up to a byte if applicable - uint32_t padding = (dataCapacity * 8) - codewords.bitOffsetOrWidth; - if(padding > 4) { - padding = 4; - } - bb_appendBits(&codewords, 0, padding); - bb_appendBits(&codewords, 0, (8 - codewords.bitOffsetOrWidth % 8) % 8); - - // Pad with alternate bytes until data capacity is reached - for(uint8_t padByte = 0xEC; codewords.bitOffsetOrWidth < (dataCapacity * 8); - padByte ^= 0xEC ^ 0x11) { - bb_appendBits(&codewords, padByte, 8); - } - - BitBucket modulesGrid; - bb_initGrid(&modulesGrid, modules, size); - - BitBucket isFunctionGrid; - uint8_t isFunctionGridBytes[bb_getGridSizeBytes(size)]; - bb_initGrid(&isFunctionGrid, isFunctionGridBytes, size); - - // Draw function patterns, draw all codewords, do masking - drawFunctionPatterns(&modulesGrid, &isFunctionGrid, version, eccFormatBits); - performErrorCorrection(version, eccFormatBits, &codewords); - drawCodewords(&modulesGrid, &isFunctionGrid, &codewords); - - // Find the best (lowest penalty) mask - uint8_t mask = 0; - int32_t minPenalty = INT32_MAX; - for(uint8_t i = 0; i < 8; i++) { - drawFormatBits(&modulesGrid, &isFunctionGrid, eccFormatBits, i); - applyMask(&modulesGrid, &isFunctionGrid, i); - int penalty = getPenaltyScore(&modulesGrid); - if(penalty < minPenalty) { - mask = i; - minPenalty = penalty; - } - applyMask(&modulesGrid, &isFunctionGrid, i); // Undoes the mask due to XOR - } - - qrcode->mask = mask; - - // Overwrite old format bits - drawFormatBits(&modulesGrid, &isFunctionGrid, eccFormatBits, mask); - - // Apply the final choice of mask - applyMask(&modulesGrid, &isFunctionGrid, mask); - - return 0; -} - -int8_t qrcode_initText( - QRCode* qrcode, - uint8_t* modules, - uint8_t version, - uint8_t ecc, - const char* data) { - return qrcode_initBytes(qrcode, modules, version, ecc, (uint8_t*)data, strlen(data)); -} - -bool qrcode_getModule(QRCode* qrcode, uint8_t x, uint8_t y) { - if(x < 0 || x >= qrcode->size || y < 0 || y >= qrcode->size) { - return false; - } - - uint32_t offset = y * qrcode->size + x; - return (qrcode->modules[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0; -} diff --git a/lib/qrcode/qrcode.h b/lib/qrcode/qrcode.h deleted file mode 100644 index 6d637ba04d..0000000000 --- a/lib/qrcode/qrcode.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * The MIT License (MIT) - * - * This library is written and maintained by Richard Moore. - * Major parts were derived from Project Nayuki's library. - * - * Copyright (c) 2017 Richard Moore (https://github.com/ricmoo/QRCode) - * Copyright (c) 2017 Project Nayuki (https://www.nayuki.io/page/qr-code-generator-library) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * Special thanks to Nayuki (https://www.nayuki.io/) from which this library was - * heavily inspired and compared against. - * - * See: https://github.com/nayuki/QR-Code-generator/tree/master/cpp - */ - -#ifndef __QRCODE_H_ -#define __QRCODE_H_ - -#ifndef __cplusplus -typedef unsigned char bool; -static const bool false = 0; -static const bool true = 1; -#endif - -#include - -// QR Code Format Encoding -#define MODE_NUMERIC 0 -#define MODE_ALPHANUMERIC 1 -#define MODE_BYTE 2 - -// Error Correction Code Levels -#define ECC_LOW 0 -#define ECC_MEDIUM 1 -#define ECC_QUARTILE 2 -#define ECC_HIGH 3 - -// If set to non-zero, this library can ONLY produce QR codes at that version -// This saves a lot of dynamic memory, as the codeword tables are skipped -#ifndef LOCK_VERSION -#define LOCK_VERSION 0 -#endif - -typedef struct QRCode { - uint8_t version; - uint8_t size; - uint8_t ecc; - uint8_t mode; - uint8_t mask; - uint8_t* modules; -} QRCode; - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -uint16_t qrcode_getBufferSize(uint8_t version); - -int8_t qrcode_initText( - QRCode* qrcode, - uint8_t* modules, - uint8_t version, - uint8_t ecc, - const char* data); -int8_t qrcode_initBytes( - QRCode* qrcode, - uint8_t* modules, - uint8_t version, - uint8_t ecc, - uint8_t* data, - uint16_t length); - -bool qrcode_getModule(QRCode* qrcode, uint8_t x, uint8_t y); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __QRCODE_H_ */ diff --git a/lib/signal_reader/SConscript b/lib/signal_reader/SConscript index ea73144201..386e3419d7 100644 --- a/lib/signal_reader/SConscript +++ b/lib/signal_reader/SConscript @@ -7,11 +7,14 @@ env.Append( SDK_HEADERS=[ File("signal_reader.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="signal_reader") libenv.ApplyLibFlags() -libenv.Append(CCFLAGS=["-O3", "-funroll-loops", "-Ofast"]) +libenv.AppendUnique(CCFLAGS=["-O3", "-funroll-loops", "-Ofast"]) sources = libenv.GlobRecursive("*.c*") diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 35850aa83e..d0bc2a2543 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -4,6 +4,9 @@ env.Append( CPPPATH=[ "#/lib/subghz", ], + LINT_SOURCES=[ + Dir("."), + ], SDK_HEADERS=[ File("environment.h"), File("receiver.h"), diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index de77f0ccf2..14f8de0646 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -7,6 +7,9 @@ env.Append( CPPPATH=[ "#/lib/toolbox", ], + LINT_SOURCES=[ + Dir("."), + ], SDK_HEADERS=[ File("api_lock.h"), File("compress.h"), @@ -14,10 +17,8 @@ env.Append( File("manchester_encoder.h"), File("path.h"), File("name_generator.h"), - File("sha256.h"), File("crc32_calc.h"), File("dir_walk.h"), - File("md5.h"), File("args.h"), File("saved_struct.h"), File("version.h"), diff --git a/lib/toolbox/md5.c b/lib/toolbox/md5.c deleted file mode 100644 index a907d52e3b..0000000000 --- a/lib/toolbox/md5.c +++ /dev/null @@ -1,299 +0,0 @@ -/******************************************************************************* -* Portions COPYRIGHT 2015 STMicroelectronics * -* Portions Copyright (C) 2006-2013, Brainspark B.V. * -*******************************************************************************/ - -/* - * RFC 1321 compliant MD5 implementation - * - * Copyright (C) 2006-2013, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * The MD5 algorithm was designed by Ron Rivest in 1991. - * - * http://www.ietf.org/rfc/rfc1321.txt - */ - -/** - ****************************************************************************** - * @file md5.c - * @author MCD Application Team - * @brief This file has been modified to support the hardware Cryptographic and - * Hash processors embedded in STM32F415xx/417xx/437xx/439xx/756xx devices. - * This support is activated by defining the "USE_STM32F4XX_HW_CRYPTO" - * or "USE_STM32F7XX_HW_CRYPTO" macro in PolarSSL config.h file. - ****************************************************************************** - * @attention - * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -#include "md5.h" - -/* - * 32-bit integer manipulation macros (little endian) - */ -#ifndef GET_UINT32_LE -#define GET_UINT32_LE(n, b, i) \ - { \ - (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | \ - ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \ - } -#endif - -#ifndef PUT_UINT32_LE -#define PUT_UINT32_LE(n, b, i) \ - { \ - (b)[(i)] = (unsigned char)((n)); \ - (b)[(i) + 1] = (unsigned char)((n) >> 8); \ - (b)[(i) + 2] = (unsigned char)((n) >> 16); \ - (b)[(i) + 3] = (unsigned char)((n) >> 24); \ - } -#endif - -/* - * MD5 context setup - */ -void md5_starts(md5_context* ctx) { - ctx->total[0] = 0; - ctx->total[1] = 0; - - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; -} - -void md5_process(md5_context* ctx, const unsigned char data[64]) { - uint32_t X[16], A, B, C, D; - - GET_UINT32_LE(X[0], data, 0); - GET_UINT32_LE(X[1], data, 4); - GET_UINT32_LE(X[2], data, 8); - GET_UINT32_LE(X[3], data, 12); - GET_UINT32_LE(X[4], data, 16); - GET_UINT32_LE(X[5], data, 20); - GET_UINT32_LE(X[6], data, 24); - GET_UINT32_LE(X[7], data, 28); - GET_UINT32_LE(X[8], data, 32); - GET_UINT32_LE(X[9], data, 36); - GET_UINT32_LE(X[10], data, 40); - GET_UINT32_LE(X[11], data, 44); - GET_UINT32_LE(X[12], data, 48); - GET_UINT32_LE(X[13], data, 52); - GET_UINT32_LE(X[14], data, 56); - GET_UINT32_LE(X[15], data, 60); - -#define S(x, n) (((x) << (n)) | (((x)&0xFFFFFFFF) >> (32 - (n)))) - -#define P(a, b, c, d, k, s, t) \ - { \ - a += F(b, c, d) + X[k] + t; \ - a = S(a, s) + b; \ - } - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) - - P(A, B, C, D, 0, 7, 0xD76AA478); - P(D, A, B, C, 1, 12, 0xE8C7B756); - P(C, D, A, B, 2, 17, 0x242070DB); - P(B, C, D, A, 3, 22, 0xC1BDCEEE); - P(A, B, C, D, 4, 7, 0xF57C0FAF); - P(D, A, B, C, 5, 12, 0x4787C62A); - P(C, D, A, B, 6, 17, 0xA8304613); - P(B, C, D, A, 7, 22, 0xFD469501); - P(A, B, C, D, 8, 7, 0x698098D8); - P(D, A, B, C, 9, 12, 0x8B44F7AF); - P(C, D, A, B, 10, 17, 0xFFFF5BB1); - P(B, C, D, A, 11, 22, 0x895CD7BE); - P(A, B, C, D, 12, 7, 0x6B901122); - P(D, A, B, C, 13, 12, 0xFD987193); - P(C, D, A, B, 14, 17, 0xA679438E); - P(B, C, D, A, 15, 22, 0x49B40821); - -#undef F - -#define F(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) - - P(A, B, C, D, 1, 5, 0xF61E2562); - P(D, A, B, C, 6, 9, 0xC040B340); - P(C, D, A, B, 11, 14, 0x265E5A51); - P(B, C, D, A, 0, 20, 0xE9B6C7AA); - P(A, B, C, D, 5, 5, 0xD62F105D); - P(D, A, B, C, 10, 9, 0x02441453); - P(C, D, A, B, 15, 14, 0xD8A1E681); - P(B, C, D, A, 4, 20, 0xE7D3FBC8); - P(A, B, C, D, 9, 5, 0x21E1CDE6); - P(D, A, B, C, 14, 9, 0xC33707D6); - P(C, D, A, B, 3, 14, 0xF4D50D87); - P(B, C, D, A, 8, 20, 0x455A14ED); - P(A, B, C, D, 13, 5, 0xA9E3E905); - P(D, A, B, C, 2, 9, 0xFCEFA3F8); - P(C, D, A, B, 7, 14, 0x676F02D9); - P(B, C, D, A, 12, 20, 0x8D2A4C8A); - -#undef F - -#define F(x, y, z) ((x) ^ (y) ^ (z)) - - P(A, B, C, D, 5, 4, 0xFFFA3942); - P(D, A, B, C, 8, 11, 0x8771F681); - P(C, D, A, B, 11, 16, 0x6D9D6122); - P(B, C, D, A, 14, 23, 0xFDE5380C); - P(A, B, C, D, 1, 4, 0xA4BEEA44); - P(D, A, B, C, 4, 11, 0x4BDECFA9); - P(C, D, A, B, 7, 16, 0xF6BB4B60); - P(B, C, D, A, 10, 23, 0xBEBFBC70); - P(A, B, C, D, 13, 4, 0x289B7EC6); - P(D, A, B, C, 0, 11, 0xEAA127FA); - P(C, D, A, B, 3, 16, 0xD4EF3085); - P(B, C, D, A, 6, 23, 0x04881D05); - P(A, B, C, D, 9, 4, 0xD9D4D039); - P(D, A, B, C, 12, 11, 0xE6DB99E5); - P(C, D, A, B, 15, 16, 0x1FA27CF8); - P(B, C, D, A, 2, 23, 0xC4AC5665); - -#undef F - -#define F(x, y, z) ((y) ^ ((x) | ~(z))) - - P(A, B, C, D, 0, 6, 0xF4292244); - P(D, A, B, C, 7, 10, 0x432AFF97); - P(C, D, A, B, 14, 15, 0xAB9423A7); - P(B, C, D, A, 5, 21, 0xFC93A039); - P(A, B, C, D, 12, 6, 0x655B59C3); - P(D, A, B, C, 3, 10, 0x8F0CCC92); - P(C, D, A, B, 10, 15, 0xFFEFF47D); - P(B, C, D, A, 1, 21, 0x85845DD1); - P(A, B, C, D, 8, 6, 0x6FA87E4F); - P(D, A, B, C, 15, 10, 0xFE2CE6E0); - P(C, D, A, B, 6, 15, 0xA3014314); - P(B, C, D, A, 13, 21, 0x4E0811A1); - P(A, B, C, D, 4, 6, 0xF7537E82); - P(D, A, B, C, 11, 10, 0xBD3AF235); - P(C, D, A, B, 2, 15, 0x2AD7D2BB); - P(B, C, D, A, 9, 21, 0xEB86D391); - -#undef F - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; -} - -/* - * MD5 process buffer - */ -void md5_update(md5_context* ctx, const unsigned char* input, size_t ilen) { - size_t fill; - uint32_t left; - - if(ilen <= 0) return; - - left = ctx->total[0] & 0x3F; - fill = 64 - left; - - ctx->total[0] += (uint32_t)ilen; - ctx->total[0] &= 0xFFFFFFFF; - - if(ctx->total[0] < (uint32_t)ilen) ctx->total[1]++; - - if(left && ilen >= fill) { - memcpy((void*)(ctx->buffer + left), input, fill); - md5_process(ctx, ctx->buffer); - input += fill; - ilen -= fill; - left = 0; - } - - while(ilen >= 64) { - md5_process(ctx, input); - input += 64; - ilen -= 64; - } - - if(ilen > 0) { - memcpy((void*)(ctx->buffer + left), input, ilen); - } -} - -static const unsigned char md5_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -/* - * MD5 final digest - */ -void md5_finish(md5_context* ctx, unsigned char output[16]) { - uint32_t last, padn; - uint32_t high, low; - unsigned char msglen[8]; - - high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); - low = (ctx->total[0] << 3); - - PUT_UINT32_LE(low, msglen, 0); - PUT_UINT32_LE(high, msglen, 4); - - last = ctx->total[0] & 0x3F; - padn = (last < 56) ? (56 - last) : (120 - last); - - md5_update(ctx, md5_padding, padn); - md5_update(ctx, msglen, 8); - - PUT_UINT32_LE(ctx->state[0], output, 0); - PUT_UINT32_LE(ctx->state[1], output, 4); - PUT_UINT32_LE(ctx->state[2], output, 8); - PUT_UINT32_LE(ctx->state[3], output, 12); -} - -/* - * output = MD5( input buffer ) - */ -void md5(const unsigned char* input, size_t ilen, unsigned char output[16]) { - md5_context ctx; - - md5_starts(&ctx); - md5_update(&ctx, input, ilen); - md5_finish(&ctx, output); - - memset(&ctx, 0, sizeof(md5_context)); //-V597 -} diff --git a/lib/toolbox/md5.h b/lib/toolbox/md5.h deleted file mode 100644 index fe53db8d3e..0000000000 --- a/lib/toolbox/md5.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - * \file md5.h - * - * \brief MD5 message digest algorithm (hash function) - * - * Copyright (C) 2006-2013, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include - -/** - * \brief MD5 context structure - */ -typedef struct { - uint32_t total[2]; /*!< number of bytes processed */ - uint32_t state[4]; /*!< intermediate digest state */ - unsigned char buffer[64]; /*!< data block being processed */ -} md5_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief MD5 context setup - * - * \param ctx context to be initialized - */ -void md5_starts(md5_context* ctx); - -/** - * \brief MD5 process buffer - * - * \param ctx MD5 context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void md5_update(md5_context* ctx, const unsigned char* input, size_t ilen); - -/** - * \brief MD5 final digest - * - * \param ctx MD5 context - * \param output MD5 checksum result - */ -void md5_finish(md5_context* ctx, unsigned char output[16]); - -/* Internal use */ -void md5_process(md5_context* ctx, const unsigned char data[64]); - -/** - * \brief Output = MD5( input buffer ) - * - * \param input buffer holding the data - * \param ilen length of the input data - * \param output MD5 checksum result - */ -void md5(const unsigned char* input, size_t ilen, unsigned char output[16]); - -#ifdef __cplusplus -} -#endif diff --git a/lib/toolbox/md5_calc.c b/lib/toolbox/md5_calc.c index 7f335a33f2..59c9403e81 100644 --- a/lib/toolbox/md5_calc.c +++ b/lib/toolbox/md5_calc.c @@ -1,25 +1,39 @@ -#include "md5.h" #include "md5_calc.h" +#include +#include +#include + bool md5_calc_file(File* file, const char* path, unsigned char output[16], FS_Error* file_error) { - bool result = storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING); - - if(result) { - const size_t size_to_read = 512; - uint8_t* data = malloc(size_to_read); - md5_context* md5_ctx = malloc(sizeof(md5_context)); - - md5_starts(md5_ctx); - while(true) { - size_t read_size = storage_file_read(file, data, size_to_read); - if(read_size == 0) break; - md5_update(md5_ctx, data, read_size); + if(!storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) { + if(file_error != NULL) { + *file_error = storage_file_get_error(file); } - md5_finish(md5_ctx, output); - free(md5_ctx); - free(data); + return false; } + const size_t size_to_read = 512; + uint8_t* data = malloc(size_to_read); + bool result = true; + + mbedtls_md5_context* md5_ctx = malloc(sizeof(mbedtls_md5_context)); + mbedtls_md5_init(md5_ctx); + mbedtls_md5_starts(md5_ctx); + while(true) { + size_t read_size = storage_file_read(file, data, size_to_read); + if(storage_file_get_error(file) != FSE_OK) { + result = false; + break; + } + if(read_size == 0) { + break; + } + mbedtls_md5_update(md5_ctx, data, read_size); + } + mbedtls_md5_finish(md5_ctx, output); + free(md5_ctx); + free(data); + if(file_error != NULL) { *file_error = storage_file_get_error(file); } diff --git a/lib/toolbox/sha256.c b/lib/toolbox/sha256.c deleted file mode 100644 index ff4984439d..0000000000 --- a/lib/toolbox/sha256.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * sha256.c -- Compute SHA-256 hash - * - * Just for little endian architecture. - * - * Code taken from: - * http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php - * - * File names are sha2.c, sha2.h, brg_types.h, brg_endian.h - * in the archive sha2-07-01-07.zip. - * - * Code is modified in the style of PolarSSL API. - * - * See original copyright notice below. - */ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 01/08/2005 -*/ - -#include -#include -#include -#include "sha256.h" - -#define SHA256_MASK (SHA256_BLOCK_SIZE - 1) - -static void memcpy_output_bswap32(unsigned char* dst, const uint32_t* p) { - int i; - uint32_t q = 0; - - for(i = 0; i < 32; i++) { - if((i & 3) == 0) q = __builtin_bswap32(p[i >> 2]); /* bswap32 is GCC extention */ - dst[i] = q >> ((i & 3) * 8); - } -} - -#define rotr32(x, n) (((x) >> n) | ((x) << (32 - (n)))) - -#define ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define maj(x, y, z) (((x) & (y)) | ((z) & ((x) ^ (y)))) - -/* round transforms for SHA256 compression functions */ -#define vf(n, i) v[((n) - (i)) & 7] - -#define hf(i) (p[(i)&15] += g_1(p[((i) + 14) & 15]) + p[((i) + 9) & 15] + g_0(p[((i) + 1) & 15])) - -#define v_cycle0(i) \ - p[i] = __builtin_bswap32(p[i]); \ - vf(7, i) += p[i] + k_0[i] + s_1(vf(4, i)) + ch(vf(4, i), vf(5, i), vf(6, i)); \ - vf(3, i) += vf(7, i); \ - vf(7, i) += s_0(vf(0, i)) + maj(vf(0, i), vf(1, i), vf(2, i)) - -#define v_cycle(i, j) \ - vf(7, i) += hf(i) + k_0[i + j] + s_1(vf(4, i)) + ch(vf(4, i), vf(5, i), vf(6, i)); \ - vf(3, i) += vf(7, i); \ - vf(7, i) += s_0(vf(0, i)) + maj(vf(0, i), vf(1, i), vf(2, i)) - -#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22)) -#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25)) -#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3)) -#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) -#define k_0 k256 - -static const uint32_t k256[64] = { - 0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5, 0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5, - 0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3, 0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174, - 0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC, 0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA, - 0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7, 0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967, - 0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13, 0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85, - 0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3, 0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070, - 0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5, 0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3, - 0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208, 0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2, -}; - -void sha256_process(sha256_context* ctx) { - uint32_t i; - uint32_t* p = ctx->wbuf; - uint32_t v[8]; - - memcpy(v, ctx->state, 8 * sizeof(uint32_t)); - - v_cycle0(0); - v_cycle0(1); - v_cycle0(2); - v_cycle0(3); - v_cycle0(4); - v_cycle0(5); - v_cycle0(6); - v_cycle0(7); - v_cycle0(8); - v_cycle0(9); - v_cycle0(10); - v_cycle0(11); - v_cycle0(12); - v_cycle0(13); - v_cycle0(14); - v_cycle0(15); - - for(i = 16; i < 64; i += 16) { - v_cycle(0, i); - v_cycle(1, i); - v_cycle(2, i); - v_cycle(3, i); - v_cycle(4, i); - v_cycle(5, i); - v_cycle(6, i); - v_cycle(7, i); - v_cycle(8, i); - v_cycle(9, i); - v_cycle(10, i); - v_cycle(11, i); - v_cycle(12, i); - v_cycle(13, i); - v_cycle(14, i); - v_cycle(15, i); - } - - ctx->state[0] += v[0]; - ctx->state[1] += v[1]; - ctx->state[2] += v[2]; - ctx->state[3] += v[3]; - ctx->state[4] += v[4]; - ctx->state[5] += v[5]; - ctx->state[6] += v[6]; - ctx->state[7] += v[7]; -} - -void sha256_update(sha256_context* ctx, const unsigned char* input, unsigned int ilen) { - uint32_t left = (ctx->total[0] & SHA256_MASK); - uint32_t fill = SHA256_BLOCK_SIZE - left; - - ctx->total[0] += ilen; - if(ctx->total[0] < ilen) ctx->total[1]++; - - while(ilen >= fill) { - memcpy(((unsigned char*)ctx->wbuf) + left, input, fill); - sha256_process(ctx); - input += fill; - ilen -= fill; - left = 0; - fill = SHA256_BLOCK_SIZE; - } - - memcpy(((unsigned char*)ctx->wbuf) + left, input, ilen); -} - -void sha256_finish(sha256_context* ctx, unsigned char output[32]) { - uint32_t last = (ctx->total[0] & SHA256_MASK); - - ctx->wbuf[last >> 2] = __builtin_bswap32(ctx->wbuf[last >> 2]); - ctx->wbuf[last >> 2] &= 0xffffff80UL << (8 * (~last & 3)); - ctx->wbuf[last >> 2] |= 0x00000080UL << (8 * (~last & 3)); - ctx->wbuf[last >> 2] = __builtin_bswap32(ctx->wbuf[last >> 2]); - - if(last > SHA256_BLOCK_SIZE - 9) { - if(last < 60) ctx->wbuf[15] = 0; - sha256_process(ctx); - last = 0; - } else - last = (last >> 2) + 1; - - while(last < 14) ctx->wbuf[last++] = 0; - - ctx->wbuf[14] = __builtin_bswap32((ctx->total[0] >> 29) | (ctx->total[1] << 3)); - ctx->wbuf[15] = __builtin_bswap32(ctx->total[0] << 3); - sha256_process(ctx); - - memcpy_output_bswap32(output, ctx->state); - memset(ctx, 0, sizeof(sha256_context)); -} - -static const uint32_t initial_state[8] = { - 0x6a09e667, - 0xbb67ae85, - 0x3c6ef372, - 0xa54ff53a, - 0x510e527f, - 0x9b05688c, - 0x1f83d9ab, - 0x5be0cd19}; - -void sha256_start(sha256_context* ctx) { - ctx->total[0] = ctx->total[1] = 0; - memcpy(ctx->state, initial_state, 8 * sizeof(uint32_t)); -} - -void sha256(const unsigned char* input, unsigned int ilen, unsigned char output[32]) { - sha256_context ctx; - - sha256_start(&ctx); - sha256_update(&ctx, input, ilen); - sha256_finish(&ctx, output); -} diff --git a/lib/toolbox/sha256.h b/lib/toolbox/sha256.h deleted file mode 100644 index c544d3ebb1..0000000000 --- a/lib/toolbox/sha256.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#define SHA256_DIGEST_SIZE 32 -#define SHA256_BLOCK_SIZE 64 - -typedef struct { - uint32_t total[2]; - uint32_t state[8]; - uint32_t wbuf[16]; -} sha256_context; - -void sha256(const unsigned char* input, unsigned int ilen, unsigned char output[32]); -void sha256_start(sha256_context* ctx); -void sha256_finish(sha256_context* ctx, unsigned char output[32]); -void sha256_update(sha256_context* ctx, const unsigned char* input, unsigned int ilen); -void sha256_process(sha256_context* ctx); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/lib/u8g2/SConscript b/lib/u8g2/SConscript new file mode 100644 index 0000000000..dacdfbacb4 --- /dev/null +++ b/lib/u8g2/SConscript @@ -0,0 +1,20 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/u8g2", + ], + LINT_SOURCES=[ + Dir("."), + ], +) + + +libenv = env.Clone(FW_LIB_NAME="u8g2") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/update_util/SConscript b/lib/update_util/SConscript new file mode 100644 index 0000000000..c818973d97 --- /dev/null +++ b/lib/update_util/SConscript @@ -0,0 +1,16 @@ +Import("env") + +env.Append( + LINT_SOURCES=[ + Dir("."), + ], +) + +libenv = env.Clone(FW_LIB_NAME="update_util") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index dadf6dc0c8..7e0aec5ea6 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -125,7 +125,6 @@ def LoadAppManifest(env, entry): app_manifest_file_path = manifest_glob[0].rfile().abspath env["APPMGR"].load_manifest(app_manifest_file_path, entry) - env.Append(PY_LINT_SOURCES=[app_manifest_file_path]) except FlipperManifestException as e: if not GetOption("silent"): warn(WarningOnByDefault, str(e)) diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index e64167b3dc..0dd5d0feb9 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -32,9 +32,9 @@ def generate(env): "${TARGET.dir.posix}", "--dir", "${ROOT_DIR}", - "${VERSIONCOMSTR}", ] - ] + ], + "${VERSIONCOMSTR}", ), emitter=_version_emitter, ), diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 7835718def..cd89b554af 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,47.0,, +Version,+,48.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -77,8 +77,13 @@ Header,+,lib/libusb_stm32/inc/usb_std.h,, Header,+,lib/libusb_stm32/inc/usb_tmc.h,, Header,+,lib/libusb_stm32/inc/usbd_core.h,, Header,+,lib/mbedtls/include/mbedtls/des.h,, +Header,+,lib/mbedtls/include/mbedtls/ecdh.h,, +Header,+,lib/mbedtls/include/mbedtls/ecdsa.h,, +Header,+,lib/mbedtls/include/mbedtls/ecp.h,, +Header,+,lib/mbedtls/include/mbedtls/md.h,, +Header,+,lib/mbedtls/include/mbedtls/md5.h,, Header,+,lib/mbedtls/include/mbedtls/sha1.h,, -Header,+,lib/micro-ecc/uECC.h,, +Header,+,lib/mbedtls/include/mbedtls/sha256.h,, Header,+,lib/mlib/m-algo.h,, Header,+,lib/mlib/m-array.h,, Header,+,lib/mlib/m-bptree.h,, @@ -136,13 +141,11 @@ Header,+,lib/toolbox/float_tools.h,, Header,+,lib/toolbox/hex.h,, Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, -Header,+,lib/toolbox/md5.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/saved_struct.h,, -Header,+,lib/toolbox/sha256.h,, Header,+,lib/toolbox/simple_array.h,, Header,+,lib/toolbox/stream/buffered_file_stream.h,, Header,+,lib/toolbox/stream/file_stream.h,, @@ -452,7 +455,6 @@ Function,-,_system_r,int,"_reent*, const char*" Function,-,_tempnam_r,char*,"_reent*, const char*, const char*" Function,-,_tmpfile_r,FILE*,_reent* Function,-,_tmpnam_r,char*,"_reent*, char*" -Function,-,_tzset_r,void,_reent* Function,-,_ungetc_r,int,"_reent*, int, FILE*" Function,-,_unsetenv_r,int,"_reent*, const char*" Function,-,_vasiprintf_r,int,"_reent*, char**, const char*, __gnuc_va_list" @@ -499,8 +501,6 @@ Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t" Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*" Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*" Function,+,args_read_string_and_trim,_Bool,"FuriString*, FuriString*" -Function,-,asctime,char*,const tm* -Function,-,asctime_r,char*,"const tm*, char*" Function,-,asin,double,double Function,-,asinf,float,float Function,-,asinh,double,double @@ -611,7 +611,7 @@ Function,+,byte_input_get_view,View*,ByteInput* Function,+,byte_input_set_header_text,void,"ByteInput*, const char*" Function,+,byte_input_set_result_callback,void,"ByteInput*, ByteInputCallback, ByteChangedCallback, void*, uint8_t*, uint8_t" Function,-,bzero,void,"void*, size_t" -Function,-,calloc,void*,"size_t, size_t" +Function,+,calloc,void*,"size_t, size_t" Function,+,canvas_clear,void,Canvas* Function,+,canvas_commit,void,Canvas* Function,+,canvas_current_font_height,uint8_t,const Canvas* @@ -665,7 +665,6 @@ Function,+,cli_read_timeout,size_t,"Cli*, uint8_t*, size_t, uint32_t" Function,+,cli_session_close,void,Cli* Function,+,cli_session_open,void,"Cli*, void*" Function,+,cli_write,void,"Cli*, const uint8_t*, size_t" -Function,-,clock,clock_t, Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiInterface*" Function,+,composite_api_resolver_alloc,CompositeApiResolver*, Function,+,composite_api_resolver_free,void,CompositeApiResolver* @@ -689,8 +688,6 @@ Function,-,cosl,long double,long double Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" Function,-,ctermid,char*,char* -Function,-,ctime,char*,const time_t* -Function,-,ctime_r,char*,"const time_t*, char*" Function,-,cuserid,char*,char* Function,+,dialog_ex_alloc,DialogEx*, Function,+,dialog_ex_disable_extended_events,void,DialogEx* @@ -716,7 +713,6 @@ Function,+,dialog_message_set_icon,void,"DialogMessage*, const Icon*, uint8_t, u Function,+,dialog_message_set_text,void,"DialogMessage*, const char*, uint8_t, uint8_t, Align, Align" Function,+,dialog_message_show,DialogMessageButton,"DialogsApp*, const DialogMessage*" Function,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*" -Function,-,difftime,double,"time_t, time_t" Function,+,digital_sequence_add_signal,void,"DigitalSequence*, uint8_t" Function,-,digital_sequence_alloc,DigitalSequence*,"uint32_t, const GpioPin*" Function,-,digital_sequence_clear,void,DigitalSequence* @@ -1518,8 +1514,6 @@ Function,-,getenv,char*,const char* Function,-,gets,char*,char* Function,-,getsubopt,int,"char**, char**, char**" Function,-,getw,int,FILE* -Function,-,gmtime,tm*,const time_t* -Function,-,gmtime_r,tm*,"const time_t*, tm*" Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer" Function,+,gui_direct_draw_acquire,Canvas*,Gui* @@ -1637,8 +1631,6 @@ Function,+,locale_get_time_format,LocaleTimeFormat, Function,+,locale_set_date_format,void,LocaleDateFormat Function,+,locale_set_measurement_unit,void,LocaleMeasurementUnits Function,+,locale_set_time_format,void,LocaleTimeFormat -Function,-,localtime,tm*,const time_t* -Function,-,localtime_r,tm*,"const time_t*, tm*" Function,-,log,double,double Function,-,log10,double,double Function,-,log10f,float,float @@ -1682,29 +1674,167 @@ Function,-,mbedtls_des_init,void,mbedtls_des_context* Function,-,mbedtls_des_key_check_key_parity,int,const unsigned char[8] Function,-,mbedtls_des_key_check_weak,int,const unsigned char[8] Function,-,mbedtls_des_key_set_parity,void,unsigned char[8] -Function,-,mbedtls_des_self_test,int,int Function,-,mbedtls_des_setkey,void,"uint32_t[32], const unsigned char[8]" Function,-,mbedtls_des_setkey_dec,int,"mbedtls_des_context*, const unsigned char[8]" Function,-,mbedtls_des_setkey_enc,int,"mbedtls_des_context*, const unsigned char[8]" +Function,-,mbedtls_ecdh_calc_secret,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_can_do,int,mbedtls_ecp_group_id +Function,-,mbedtls_ecdh_compute_shared,int,"mbedtls_ecp_group*, mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_free,void,mbedtls_ecdh_context* +Function,-,mbedtls_ecdh_gen_public,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_get_params,int,"mbedtls_ecdh_context*, const mbedtls_ecp_keypair*, mbedtls_ecdh_side" +Function,-,mbedtls_ecdh_init,void,mbedtls_ecdh_context* +Function,-,mbedtls_ecdh_make_params,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_make_public,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_read_params,int,"mbedtls_ecdh_context*, const unsigned char**, const unsigned char*" +Function,-,mbedtls_ecdh_read_public,int,"mbedtls_ecdh_context*, const unsigned char*, size_t" +Function,-,mbedtls_ecdh_setup,int,"mbedtls_ecdh_context*, mbedtls_ecp_group_id" +Function,-,mbedtls_ecdsa_can_do,int,mbedtls_ecp_group_id +Function,-,mbedtls_ecdsa_free,void,mbedtls_ecdsa_context* +Function,-,mbedtls_ecdsa_from_keypair,int,"mbedtls_ecdsa_context*, const mbedtls_ecp_keypair*" +Function,-,mbedtls_ecdsa_genkey,int,"mbedtls_ecdsa_context*, mbedtls_ecp_group_id, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_init,void,mbedtls_ecdsa_context* +Function,-,mbedtls_ecdsa_read_signature,int,"mbedtls_ecdsa_context*, const unsigned char*, size_t, const unsigned char*, size_t" +Function,-,mbedtls_ecdsa_read_signature_restartable,int,"mbedtls_ecdsa_context*, const unsigned char*, size_t, const unsigned char*, size_t, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_sign,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_sign_restartable,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_verify,int,"mbedtls_ecp_group*, const unsigned char*, size_t, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_ecdsa_verify_restartable,int,"mbedtls_ecp_group*, const unsigned char*, size_t, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_mpi*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_write_signature,int,"mbedtls_ecdsa_context*, mbedtls_md_type_t, const unsigned char*, size_t, unsigned char*, size_t, size_t*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_write_signature_restartable,int,"mbedtls_ecdsa_context*, mbedtls_md_type_t, const unsigned char*, size_t, unsigned char*, size_t, size_t*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecp_check_privkey,int,"const mbedtls_ecp_group*, const mbedtls_mpi*" +Function,-,mbedtls_ecp_check_pub_priv,int,"const mbedtls_ecp_keypair*, const mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_check_pubkey,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_copy,int,"mbedtls_ecp_point*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_curve_info_from_grp_id,const mbedtls_ecp_curve_info*,mbedtls_ecp_group_id +Function,-,mbedtls_ecp_curve_info_from_name,const mbedtls_ecp_curve_info*,const char* +Function,-,mbedtls_ecp_curve_info_from_tls_id,const mbedtls_ecp_curve_info*,uint16_t +Function,-,mbedtls_ecp_curve_list,const mbedtls_ecp_curve_info*, +Function,-,mbedtls_ecp_export,int,"const mbedtls_ecp_keypair*, mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*" +Function,-,mbedtls_ecp_gen_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_keypair,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_keypair_base,int,"mbedtls_ecp_group*, const mbedtls_ecp_point*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_privkey,int,"const mbedtls_ecp_group*, mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_get_type,mbedtls_ecp_curve_type,const mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_copy,int,"mbedtls_ecp_group*, const mbedtls_ecp_group*" +Function,-,mbedtls_ecp_group_free,void,mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_init,void,mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_load,int,"mbedtls_ecp_group*, mbedtls_ecp_group_id" +Function,-,mbedtls_ecp_grp_id_list,const mbedtls_ecp_group_id*, +Function,-,mbedtls_ecp_is_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_keypair_free,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_keypair_init,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_mul,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_mul_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecp_restart_ctx*" +Function,-,mbedtls_ecp_muladd,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_muladd_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, mbedtls_ecp_restart_ctx*" +Function,-,mbedtls_ecp_point_cmp,int,"const mbedtls_ecp_point*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_point_free,void,mbedtls_ecp_point* +Function,-,mbedtls_ecp_point_init,void,mbedtls_ecp_point* +Function,-,mbedtls_ecp_point_read_binary,int,"const mbedtls_ecp_group*, mbedtls_ecp_point*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_point_read_string,int,"mbedtls_ecp_point*, int, const char*, const char*" +Function,-,mbedtls_ecp_point_write_binary,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_read_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_set_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_tls_read_group,int,"mbedtls_ecp_group*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_read_group_id,int,"mbedtls_ecp_group_id*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_read_point,int,"const mbedtls_ecp_group*, mbedtls_ecp_point*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_write_group,int,"const mbedtls_ecp_group*, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_tls_write_point,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_write_key,int,"mbedtls_ecp_keypair*, unsigned char*, size_t" +Function,-,mbedtls_internal_md5_process,int,"mbedtls_md5_context*, const unsigned char[64]" Function,-,mbedtls_internal_sha1_process,int,"mbedtls_sha1_context*, const unsigned char[64]" -Function,-,mbedtls_platform_gmtime_r,tm*,"const mbedtls_time_t*, tm*" +Function,-,mbedtls_internal_sha256_process,int,"mbedtls_sha256_context*, const unsigned char[64]" +Function,-,mbedtls_md,int,"const mbedtls_md_info_t*, const unsigned char*, size_t, unsigned char*" +Function,-,mbedtls_md5,int,"const unsigned char*, size_t, unsigned char[16]" +Function,-,mbedtls_md5_clone,void,"mbedtls_md5_context*, const mbedtls_md5_context*" +Function,-,mbedtls_md5_finish,int,"mbedtls_md5_context*, unsigned char[16]" +Function,-,mbedtls_md5_free,void,mbedtls_md5_context* +Function,-,mbedtls_md5_init,void,mbedtls_md5_context* +Function,-,mbedtls_md5_starts,int,mbedtls_md5_context* +Function,-,mbedtls_md5_update,int,"mbedtls_md5_context*, const unsigned char*, size_t" +Function,-,mbedtls_md_clone,int,"mbedtls_md_context_t*, const mbedtls_md_context_t*" +Function,-,mbedtls_md_finish,int,"mbedtls_md_context_t*, unsigned char*" +Function,-,mbedtls_md_free,void,mbedtls_md_context_t* +Function,-,mbedtls_md_get_name,const char*,const mbedtls_md_info_t* +Function,-,mbedtls_md_get_size,unsigned char,const mbedtls_md_info_t* +Function,-,mbedtls_md_get_type,mbedtls_md_type_t,const mbedtls_md_info_t* +Function,-,mbedtls_md_hmac,int,"const mbedtls_md_info_t*, const unsigned char*, size_t, const unsigned char*, size_t, unsigned char*" +Function,-,mbedtls_md_hmac_finish,int,"mbedtls_md_context_t*, unsigned char*" +Function,-,mbedtls_md_hmac_reset,int,mbedtls_md_context_t* +Function,-,mbedtls_md_hmac_starts,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_md_hmac_update,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_md_info_from_ctx,const mbedtls_md_info_t*,const mbedtls_md_context_t* +Function,-,mbedtls_md_info_from_string,const mbedtls_md_info_t*,const char* +Function,-,mbedtls_md_info_from_type,const mbedtls_md_info_t*,mbedtls_md_type_t +Function,-,mbedtls_md_init,void,mbedtls_md_context_t* +Function,-,mbedtls_md_list,const int*, +Function,-,mbedtls_md_setup,int,"mbedtls_md_context_t*, const mbedtls_md_info_t*, int" +Function,-,mbedtls_md_starts,int,mbedtls_md_context_t* +Function,-,mbedtls_md_update,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_add_abs,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_add_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_add_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_bitlen,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_cmp_abs,int,"const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_cmp_int,int,"const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_cmp_mpi,int,"const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_copy,int,"mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_div_int,int,"mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_div_mpi,int,"mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_exp_mod,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi*" +Function,-,mbedtls_mpi_fill_random,int,"mbedtls_mpi*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_free,void,mbedtls_mpi* +Function,-,mbedtls_mpi_gcd,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_gen_prime,int,"mbedtls_mpi*, size_t, int, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_get_bit,int,"const mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_grow,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_init,void,mbedtls_mpi* +Function,-,mbedtls_mpi_inv_mod,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_is_prime_ext,int,"const mbedtls_mpi*, int, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_lsb,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_lset,int,"mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_lt_mpi_ct,int,"const mbedtls_mpi*, const mbedtls_mpi*, unsigned*" +Function,-,mbedtls_mpi_mod_int,int,"mbedtls_mpi_uint*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_mod_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_mul_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_uint" +Function,-,mbedtls_mpi_mul_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_random,int,"mbedtls_mpi*, mbedtls_mpi_sint, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_read_binary,int,"mbedtls_mpi*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_read_binary_le,int,"mbedtls_mpi*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_read_string,int,"mbedtls_mpi*, int, const char*" +Function,-,mbedtls_mpi_safe_cond_assign,int,"mbedtls_mpi*, const mbedtls_mpi*, unsigned char" +Function,-,mbedtls_mpi_safe_cond_swap,int,"mbedtls_mpi*, mbedtls_mpi*, unsigned char" +Function,-,mbedtls_mpi_set_bit,int,"mbedtls_mpi*, size_t, unsigned char" +Function,-,mbedtls_mpi_shift_l,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_shift_r,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_shrink,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_size,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_sub_abs,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_sub_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_sub_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_swap,void,"mbedtls_mpi*, mbedtls_mpi*" +Function,-,mbedtls_mpi_write_binary,int,"const mbedtls_mpi*, unsigned char*, size_t" +Function,-,mbedtls_mpi_write_binary_le,int,"const mbedtls_mpi*, unsigned char*, size_t" +Function,-,mbedtls_mpi_write_string,int,"const mbedtls_mpi*, int, char*, size_t, size_t*" Function,-,mbedtls_platform_zeroize,void,"void*, size_t" Function,-,mbedtls_sha1,int,"const unsigned char*, size_t, unsigned char[20]" Function,-,mbedtls_sha1_clone,void,"mbedtls_sha1_context*, const mbedtls_sha1_context*" Function,-,mbedtls_sha1_finish,int,"mbedtls_sha1_context*, unsigned char[20]" Function,-,mbedtls_sha1_free,void,mbedtls_sha1_context* Function,-,mbedtls_sha1_init,void,mbedtls_sha1_context* -Function,-,mbedtls_sha1_self_test,int,int Function,-,mbedtls_sha1_starts,int,mbedtls_sha1_context* Function,-,mbedtls_sha1_update,int,"mbedtls_sha1_context*, const unsigned char*, size_t" +Function,-,mbedtls_sha256,int,"const unsigned char*, size_t, unsigned char*, int" +Function,-,mbedtls_sha256_clone,void,"mbedtls_sha256_context*, const mbedtls_sha256_context*" +Function,-,mbedtls_sha256_finish,int,"mbedtls_sha256_context*, unsigned char*" +Function,-,mbedtls_sha256_free,void,mbedtls_sha256_context* +Function,-,mbedtls_sha256_init,void,mbedtls_sha256_context* +Function,-,mbedtls_sha256_starts,int,"mbedtls_sha256_context*, int" +Function,-,mbedtls_sha256_update,int,"mbedtls_sha256_context*, const unsigned char*, size_t" 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,void,"const unsigned char*, size_t, unsigned char[16]" -Function,+,md5_finish,void,"md5_context*, unsigned char[16]" -Function,+,md5_process,void,"md5_context*, const unsigned char[64]" -Function,+,md5_starts,void,md5_context* -Function,+,md5_update,void,"md5_context*, const unsigned char*, size_t" 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" @@ -1737,7 +1867,6 @@ Function,-,mkostemps,int,"char*, int, int" Function,-,mkstemp,int,char* Function,-,mkstemps,int,"char*, int" Function,-,mktemp,char*,char* -Function,-,mktime,time_t,tm* Function,-,modf,double,"double, double*" Function,-,modff,float,"float, float*" Function,-,modfl,long double,"long double, long double*" @@ -2003,11 +2132,6 @@ Function,-,setkey,void,const char* Function,-,setlinebuf,int,FILE* Function,-,setstate,char*,char* Function,-,setvbuf,int,"FILE*, char*, int, size_t" -Function,+,sha256,void,"const unsigned char*, unsigned int, unsigned char[32]" -Function,+,sha256_finish,void,"sha256_context*, unsigned char[32]" -Function,+,sha256_process,void,sha256_context* -Function,+,sha256_start,void,sha256_context* -Function,+,sha256_update,void,"sha256_context*, const unsigned char*, unsigned int" Function,+,signal_reader_alloc,SignalReader*,"const GpioPin*, uint32_t" Function,+,signal_reader_free,void,SignalReader* Function,+,signal_reader_set_polarity,void,"SignalReader*, SignalReaderPolarity" @@ -2171,8 +2295,6 @@ Function,+,stream_write_vaformat,size_t,"Stream*, const char*, va_list" Function,-,strerror,char*,int Function,-,strerror_l,char*,"int, locale_t" Function,-,strerror_r,char*,"int, char*, size_t" -Function,-,strftime,size_t,"char*, size_t, const char*, const tm*" -Function,-,strftime_l,size_t,"char*, size_t, const char*, const tm*, locale_t" Function,+,string_stream_alloc,Stream*, Function,-,strlcat,size_t,"char*, const char*, size_t" Function,+,strlcpy,size_t,"char*, const char*, size_t" @@ -2187,8 +2309,6 @@ Function,-,strndup,char*,"const char*, size_t" Function,-,strnlen,size_t,"const char*, size_t" Function,-,strnstr,char*,"const char*, const char*, size_t" Function,-,strpbrk,char*,"const char*, const char*" -Function,-,strptime,char*,"const char*, const char*, tm*" -Function,-,strptime_l,char*,"const char*, const char*, tm*, locale_t" Function,+,strrchr,char*,"const char*, int" Function,-,strsep,char*,"char**, const char*" Function,-,strsignal,char*,int @@ -2263,7 +2383,6 @@ Function,+,text_input_set_validator,void,"TextInput*, TextInputValidatorCallback Function,-,tgamma,double,double Function,-,tgammaf,float,float Function,-,tgammal,long double,long double -Function,-,time,time_t,time_t* Function,-,timingsafe_bcmp,int,"const void*, const void*, size_t" Function,-,timingsafe_memcmp,int,"const void*, const void*, size_t" Function,-,tmpfile,FILE*, @@ -2277,25 +2396,6 @@ Function,-,toupper_l,int,"int, locale_t" Function,-,trunc,double,double Function,-,truncf,float,float Function,-,truncl,long double,long double -Function,-,tzset,void, -Function,-,uECC_compress,void,"const uint8_t*, uint8_t*, uECC_Curve" -Function,+,uECC_compute_public_key,int,"const uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_curve_private_key_size,int,uECC_Curve -Function,-,uECC_curve_public_key_size,int,uECC_Curve -Function,-,uECC_decompress,void,"const uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_get_rng,uECC_RNG_Function, -Function,-,uECC_make_key,int,"uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_secp160r1,uECC_Curve, -Function,-,uECC_secp192r1,uECC_Curve, -Function,-,uECC_secp224r1,uECC_Curve, -Function,-,uECC_secp256k1,uECC_Curve, -Function,+,uECC_secp256r1,uECC_Curve, -Function,+,uECC_set_rng,void,uECC_RNG_Function -Function,-,uECC_shared_secret,int,"const uint8_t*, const uint8_t*, uint8_t*, uECC_Curve" -Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uECC_Curve" -Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve" -Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve" -Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve" Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int" Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* @@ -2428,13 +2528,10 @@ Variable,-,MSIRangeTable,const uint32_t[16], Variable,-,SmpsPrescalerTable,const uint32_t[4][6], Variable,+,SystemCoreClock,uint32_t, Variable,+,_ctype_,const char[], -Variable,-,_daylight,int, Variable,+,_global_impure_ptr,_reent*, Variable,+,_impure_ptr,_reent*, Variable,-,_sys_errlist,const char*[], Variable,-,_sys_nerr,int, -Variable,-,_timezone,long, -Variable,-,_tzname,char*[2], Variable,+,cli_vcp,CliSession, Variable,+,firmware_api_interface,const ElfApiInterface*, Variable,+,furi_hal_i2c_bus_external,FuriHalI2cBus, diff --git a/targets/f18/target.json b/targets/f18/target.json index 19de9dd615..e021a5b229 100644 --- a/targets/f18/target.json +++ b/targets/f18/target.json @@ -18,7 +18,6 @@ "hwdrivers", "fatfs", "littlefs", - "flipperformat", "toolbox", "digital_signal", "signal_reader", @@ -28,12 +27,15 @@ "assets", "one_wire", "music_worker", - "misc", + "mbedtls", "flipper_application", - "flipperformat", "toolbox", + "u8g2", + "nanopb", + "update_util", + "heatshrink", + "flipperformat", "flipper18" - ], "excluded_sources": [ "furi_hal_infrared.c", @@ -63,4 +65,4 @@ "ibutton", "infrared" ] -} +} \ No newline at end of file diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index f31349f9c9..45c98ae1a5 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,47.0,, +Version,+,48.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -90,8 +90,13 @@ Header,+,lib/libusb_stm32/inc/usb_std.h,, Header,+,lib/libusb_stm32/inc/usb_tmc.h,, Header,+,lib/libusb_stm32/inc/usbd_core.h,, Header,+,lib/mbedtls/include/mbedtls/des.h,, +Header,+,lib/mbedtls/include/mbedtls/ecdh.h,, +Header,+,lib/mbedtls/include/mbedtls/ecdsa.h,, +Header,+,lib/mbedtls/include/mbedtls/ecp.h,, +Header,+,lib/mbedtls/include/mbedtls/md.h,, +Header,+,lib/mbedtls/include/mbedtls/md5.h,, Header,+,lib/mbedtls/include/mbedtls/sha1.h,, -Header,+,lib/micro-ecc/uECC.h,, +Header,+,lib/mbedtls/include/mbedtls/sha256.h,, Header,+,lib/mlib/m-algo.h,, Header,+,lib/mlib/m-array.h,, Header,+,lib/mlib/m-bptree.h,, @@ -200,13 +205,11 @@ Header,+,lib/toolbox/float_tools.h,, Header,+,lib/toolbox/hex.h,, Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, -Header,+,lib/toolbox/md5.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/saved_struct.h,, -Header,+,lib/toolbox/sha256.h,, Header,+,lib/toolbox/simple_array.h,, Header,+,lib/toolbox/stream/buffered_file_stream.h,, Header,+,lib/toolbox/stream/file_stream.h,, @@ -521,7 +524,6 @@ Function,-,_system_r,int,"_reent*, const char*" Function,-,_tempnam_r,char*,"_reent*, const char*, const char*" Function,-,_tmpfile_r,FILE*,_reent* Function,-,_tmpnam_r,char*,"_reent*, char*" -Function,-,_tzset_r,void,_reent* Function,-,_ungetc_r,int,"_reent*, int, FILE*" Function,-,_unsetenv_r,int,"_reent*, const char*" Function,-,_vasiprintf_r,int,"_reent*, char**, const char*, __gnuc_va_list" @@ -568,8 +570,6 @@ Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t" Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*" Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*" Function,+,args_read_string_and_trim,_Bool,"FuriString*, FuriString*" -Function,-,asctime,char*,const tm* -Function,-,asctime_r,char*,"const tm*, char*" Function,-,asin,double,double Function,-,asinf,float,float Function,-,asinh,double,double @@ -700,7 +700,7 @@ Function,+,byte_input_get_view,View*,ByteInput* Function,+,byte_input_set_header_text,void,"ByteInput*, const char*" Function,+,byte_input_set_result_callback,void,"ByteInput*, ByteInputCallback, ByteChangedCallback, void*, uint8_t*, uint8_t" Function,-,bzero,void,"void*, size_t" -Function,-,calloc,void*,"size_t, size_t" +Function,+,calloc,void*,"size_t, size_t" Function,+,canvas_clear,void,Canvas* Function,+,canvas_commit,void,Canvas* Function,+,canvas_current_font_height,uint8_t,const Canvas* @@ -754,7 +754,6 @@ Function,+,cli_read_timeout,size_t,"Cli*, uint8_t*, size_t, uint32_t" Function,+,cli_session_close,void,Cli* Function,+,cli_session_open,void,"Cli*, void*" Function,+,cli_write,void,"Cli*, const uint8_t*, size_t" -Function,-,clock,clock_t, Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiInterface*" Function,+,composite_api_resolver_alloc,CompositeApiResolver*, Function,+,composite_api_resolver_free,void,CompositeApiResolver* @@ -778,8 +777,6 @@ Function,-,cosl,long double,long double Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" Function,-,ctermid,char*,char* -Function,-,ctime,char*,const time_t* -Function,-,ctime_r,char*,"const time_t*, char*" Function,-,cuserid,char*,char* Function,+,dialog_ex_alloc,DialogEx*, Function,+,dialog_ex_disable_extended_events,void,DialogEx* @@ -805,7 +802,6 @@ Function,+,dialog_message_set_icon,void,"DialogMessage*, const Icon*, uint8_t, u Function,+,dialog_message_set_text,void,"DialogMessage*, const char*, uint8_t, uint8_t, Align, Align" Function,+,dialog_message_show,DialogMessageButton,"DialogsApp*, const DialogMessage*" Function,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*" -Function,-,difftime,double,"time_t, time_t" Function,+,digital_sequence_add_signal,void,"DigitalSequence*, uint8_t" Function,-,digital_sequence_alloc,DigitalSequence*,"uint32_t, const GpioPin*" Function,-,digital_sequence_clear,void,DigitalSequence* @@ -1714,8 +1710,6 @@ Function,-,getenv,char*,const char* Function,-,gets,char*,char* Function,-,getsubopt,int,"char**, char**, char**" Function,-,getw,int,FILE* -Function,-,gmtime,tm*,const time_t* -Function,-,gmtime_r,tm*,"const time_t*, tm*" Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer" Function,+,gui_direct_draw_acquire,Canvas*,Gui* @@ -2036,8 +2030,6 @@ Function,+,locale_get_time_format,LocaleTimeFormat, Function,+,locale_set_date_format,void,LocaleDateFormat Function,+,locale_set_measurement_unit,void,LocaleMeasurementUnits Function,+,locale_set_time_format,void,LocaleTimeFormat -Function,-,localtime,tm*,const time_t* -Function,-,localtime_r,tm*,"const time_t*, tm*" Function,-,log,double,double Function,-,log10,double,double Function,-,log10f,float,float @@ -2081,29 +2073,167 @@ Function,-,mbedtls_des_init,void,mbedtls_des_context* Function,-,mbedtls_des_key_check_key_parity,int,const unsigned char[8] Function,-,mbedtls_des_key_check_weak,int,const unsigned char[8] Function,-,mbedtls_des_key_set_parity,void,unsigned char[8] -Function,-,mbedtls_des_self_test,int,int Function,-,mbedtls_des_setkey,void,"uint32_t[32], const unsigned char[8]" Function,-,mbedtls_des_setkey_dec,int,"mbedtls_des_context*, const unsigned char[8]" Function,-,mbedtls_des_setkey_enc,int,"mbedtls_des_context*, const unsigned char[8]" +Function,-,mbedtls_ecdh_calc_secret,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_can_do,int,mbedtls_ecp_group_id +Function,-,mbedtls_ecdh_compute_shared,int,"mbedtls_ecp_group*, mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_free,void,mbedtls_ecdh_context* +Function,-,mbedtls_ecdh_gen_public,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_get_params,int,"mbedtls_ecdh_context*, const mbedtls_ecp_keypair*, mbedtls_ecdh_side" +Function,-,mbedtls_ecdh_init,void,mbedtls_ecdh_context* +Function,-,mbedtls_ecdh_make_params,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_make_public,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_read_params,int,"mbedtls_ecdh_context*, const unsigned char**, const unsigned char*" +Function,-,mbedtls_ecdh_read_public,int,"mbedtls_ecdh_context*, const unsigned char*, size_t" +Function,-,mbedtls_ecdh_setup,int,"mbedtls_ecdh_context*, mbedtls_ecp_group_id" +Function,-,mbedtls_ecdsa_can_do,int,mbedtls_ecp_group_id +Function,-,mbedtls_ecdsa_free,void,mbedtls_ecdsa_context* +Function,-,mbedtls_ecdsa_from_keypair,int,"mbedtls_ecdsa_context*, const mbedtls_ecp_keypair*" +Function,-,mbedtls_ecdsa_genkey,int,"mbedtls_ecdsa_context*, mbedtls_ecp_group_id, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_init,void,mbedtls_ecdsa_context* +Function,-,mbedtls_ecdsa_read_signature,int,"mbedtls_ecdsa_context*, const unsigned char*, size_t, const unsigned char*, size_t" +Function,-,mbedtls_ecdsa_read_signature_restartable,int,"mbedtls_ecdsa_context*, const unsigned char*, size_t, const unsigned char*, size_t, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_sign,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_sign_restartable,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_verify,int,"mbedtls_ecp_group*, const unsigned char*, size_t, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_ecdsa_verify_restartable,int,"mbedtls_ecp_group*, const unsigned char*, size_t, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_mpi*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_write_signature,int,"mbedtls_ecdsa_context*, mbedtls_md_type_t, const unsigned char*, size_t, unsigned char*, size_t, size_t*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_write_signature_restartable,int,"mbedtls_ecdsa_context*, mbedtls_md_type_t, const unsigned char*, size_t, unsigned char*, size_t, size_t*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecp_check_privkey,int,"const mbedtls_ecp_group*, const mbedtls_mpi*" +Function,-,mbedtls_ecp_check_pub_priv,int,"const mbedtls_ecp_keypair*, const mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_check_pubkey,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_copy,int,"mbedtls_ecp_point*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_curve_info_from_grp_id,const mbedtls_ecp_curve_info*,mbedtls_ecp_group_id +Function,-,mbedtls_ecp_curve_info_from_name,const mbedtls_ecp_curve_info*,const char* +Function,-,mbedtls_ecp_curve_info_from_tls_id,const mbedtls_ecp_curve_info*,uint16_t +Function,-,mbedtls_ecp_curve_list,const mbedtls_ecp_curve_info*, +Function,-,mbedtls_ecp_export,int,"const mbedtls_ecp_keypair*, mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*" +Function,-,mbedtls_ecp_gen_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_keypair,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_keypair_base,int,"mbedtls_ecp_group*, const mbedtls_ecp_point*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_privkey,int,"const mbedtls_ecp_group*, mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_get_type,mbedtls_ecp_curve_type,const mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_copy,int,"mbedtls_ecp_group*, const mbedtls_ecp_group*" +Function,-,mbedtls_ecp_group_free,void,mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_init,void,mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_load,int,"mbedtls_ecp_group*, mbedtls_ecp_group_id" +Function,-,mbedtls_ecp_grp_id_list,const mbedtls_ecp_group_id*, +Function,-,mbedtls_ecp_is_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_keypair_free,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_keypair_init,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_mul,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_mul_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecp_restart_ctx*" +Function,-,mbedtls_ecp_muladd,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_muladd_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, mbedtls_ecp_restart_ctx*" +Function,-,mbedtls_ecp_point_cmp,int,"const mbedtls_ecp_point*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_point_free,void,mbedtls_ecp_point* +Function,-,mbedtls_ecp_point_init,void,mbedtls_ecp_point* +Function,-,mbedtls_ecp_point_read_binary,int,"const mbedtls_ecp_group*, mbedtls_ecp_point*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_point_read_string,int,"mbedtls_ecp_point*, int, const char*, const char*" +Function,-,mbedtls_ecp_point_write_binary,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_read_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_set_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_tls_read_group,int,"mbedtls_ecp_group*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_read_group_id,int,"mbedtls_ecp_group_id*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_read_point,int,"const mbedtls_ecp_group*, mbedtls_ecp_point*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_write_group,int,"const mbedtls_ecp_group*, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_tls_write_point,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_write_key,int,"mbedtls_ecp_keypair*, unsigned char*, size_t" +Function,-,mbedtls_internal_md5_process,int,"mbedtls_md5_context*, const unsigned char[64]" Function,-,mbedtls_internal_sha1_process,int,"mbedtls_sha1_context*, const unsigned char[64]" -Function,-,mbedtls_platform_gmtime_r,tm*,"const mbedtls_time_t*, tm*" +Function,-,mbedtls_internal_sha256_process,int,"mbedtls_sha256_context*, const unsigned char[64]" +Function,-,mbedtls_md,int,"const mbedtls_md_info_t*, const unsigned char*, size_t, unsigned char*" +Function,-,mbedtls_md5,int,"const unsigned char*, size_t, unsigned char[16]" +Function,-,mbedtls_md5_clone,void,"mbedtls_md5_context*, const mbedtls_md5_context*" +Function,-,mbedtls_md5_finish,int,"mbedtls_md5_context*, unsigned char[16]" +Function,-,mbedtls_md5_free,void,mbedtls_md5_context* +Function,-,mbedtls_md5_init,void,mbedtls_md5_context* +Function,-,mbedtls_md5_starts,int,mbedtls_md5_context* +Function,-,mbedtls_md5_update,int,"mbedtls_md5_context*, const unsigned char*, size_t" +Function,-,mbedtls_md_clone,int,"mbedtls_md_context_t*, const mbedtls_md_context_t*" +Function,-,mbedtls_md_finish,int,"mbedtls_md_context_t*, unsigned char*" +Function,-,mbedtls_md_free,void,mbedtls_md_context_t* +Function,-,mbedtls_md_get_name,const char*,const mbedtls_md_info_t* +Function,-,mbedtls_md_get_size,unsigned char,const mbedtls_md_info_t* +Function,-,mbedtls_md_get_type,mbedtls_md_type_t,const mbedtls_md_info_t* +Function,-,mbedtls_md_hmac,int,"const mbedtls_md_info_t*, const unsigned char*, size_t, const unsigned char*, size_t, unsigned char*" +Function,-,mbedtls_md_hmac_finish,int,"mbedtls_md_context_t*, unsigned char*" +Function,-,mbedtls_md_hmac_reset,int,mbedtls_md_context_t* +Function,-,mbedtls_md_hmac_starts,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_md_hmac_update,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_md_info_from_ctx,const mbedtls_md_info_t*,const mbedtls_md_context_t* +Function,-,mbedtls_md_info_from_string,const mbedtls_md_info_t*,const char* +Function,-,mbedtls_md_info_from_type,const mbedtls_md_info_t*,mbedtls_md_type_t +Function,-,mbedtls_md_init,void,mbedtls_md_context_t* +Function,-,mbedtls_md_list,const int*, +Function,-,mbedtls_md_setup,int,"mbedtls_md_context_t*, const mbedtls_md_info_t*, int" +Function,-,mbedtls_md_starts,int,mbedtls_md_context_t* +Function,-,mbedtls_md_update,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_add_abs,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_add_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_add_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_bitlen,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_cmp_abs,int,"const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_cmp_int,int,"const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_cmp_mpi,int,"const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_copy,int,"mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_div_int,int,"mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_div_mpi,int,"mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_exp_mod,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi*" +Function,-,mbedtls_mpi_fill_random,int,"mbedtls_mpi*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_free,void,mbedtls_mpi* +Function,-,mbedtls_mpi_gcd,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_gen_prime,int,"mbedtls_mpi*, size_t, int, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_get_bit,int,"const mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_grow,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_init,void,mbedtls_mpi* +Function,-,mbedtls_mpi_inv_mod,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_is_prime_ext,int,"const mbedtls_mpi*, int, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_lsb,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_lset,int,"mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_lt_mpi_ct,int,"const mbedtls_mpi*, const mbedtls_mpi*, unsigned*" +Function,-,mbedtls_mpi_mod_int,int,"mbedtls_mpi_uint*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_mod_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_mul_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_uint" +Function,-,mbedtls_mpi_mul_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_random,int,"mbedtls_mpi*, mbedtls_mpi_sint, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_read_binary,int,"mbedtls_mpi*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_read_binary_le,int,"mbedtls_mpi*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_read_string,int,"mbedtls_mpi*, int, const char*" +Function,-,mbedtls_mpi_safe_cond_assign,int,"mbedtls_mpi*, const mbedtls_mpi*, unsigned char" +Function,-,mbedtls_mpi_safe_cond_swap,int,"mbedtls_mpi*, mbedtls_mpi*, unsigned char" +Function,-,mbedtls_mpi_set_bit,int,"mbedtls_mpi*, size_t, unsigned char" +Function,-,mbedtls_mpi_shift_l,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_shift_r,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_shrink,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_size,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_sub_abs,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_sub_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_sub_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_swap,void,"mbedtls_mpi*, mbedtls_mpi*" +Function,-,mbedtls_mpi_write_binary,int,"const mbedtls_mpi*, unsigned char*, size_t" +Function,-,mbedtls_mpi_write_binary_le,int,"const mbedtls_mpi*, unsigned char*, size_t" +Function,-,mbedtls_mpi_write_string,int,"const mbedtls_mpi*, int, char*, size_t, size_t*" Function,-,mbedtls_platform_zeroize,void,"void*, size_t" -Function,+,mbedtls_sha1,int,"const unsigned char*, size_t, unsigned char[20]" +Function,-,mbedtls_sha1,int,"const unsigned char*, size_t, unsigned char[20]" Function,-,mbedtls_sha1_clone,void,"mbedtls_sha1_context*, const mbedtls_sha1_context*" Function,-,mbedtls_sha1_finish,int,"mbedtls_sha1_context*, unsigned char[20]" Function,-,mbedtls_sha1_free,void,mbedtls_sha1_context* Function,-,mbedtls_sha1_init,void,mbedtls_sha1_context* -Function,-,mbedtls_sha1_self_test,int,int Function,-,mbedtls_sha1_starts,int,mbedtls_sha1_context* Function,-,mbedtls_sha1_update,int,"mbedtls_sha1_context*, const unsigned char*, size_t" +Function,-,mbedtls_sha256,int,"const unsigned char*, size_t, unsigned char*, int" +Function,-,mbedtls_sha256_clone,void,"mbedtls_sha256_context*, const mbedtls_sha256_context*" +Function,-,mbedtls_sha256_finish,int,"mbedtls_sha256_context*, unsigned char*" +Function,-,mbedtls_sha256_free,void,mbedtls_sha256_context* +Function,-,mbedtls_sha256_init,void,mbedtls_sha256_context* +Function,-,mbedtls_sha256_starts,int,"mbedtls_sha256_context*, int" +Function,-,mbedtls_sha256_update,int,"mbedtls_sha256_context*, const unsigned char*, size_t" 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,void,"const unsigned char*, size_t, unsigned char[16]" -Function,+,md5_finish,void,"md5_context*, unsigned char[16]" -Function,+,md5_process,void,"md5_context*, const unsigned char[64]" -Function,+,md5_starts,void,md5_context* -Function,+,md5_update,void,"md5_context*, const unsigned char*, size_t" 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" @@ -2255,7 +2385,6 @@ Function,-,mkostemps,int,"char*, int, int" Function,-,mkstemp,int,char* Function,-,mkstemps,int,"char*, int" Function,-,mktemp,char*,char* -Function,-,mktime,time_t,tm* Function,-,modf,double,"double, double*" Function,-,modff,float,"float, float*" Function,-,modfl,long double,"long double, long double*" @@ -2593,11 +2722,6 @@ Function,-,setkey,void,const char* Function,-,setlinebuf,int,FILE* Function,-,setstate,char*,char* Function,-,setvbuf,int,"FILE*, char*, int, size_t" -Function,+,sha256,void,"const unsigned char*, unsigned int, unsigned char[32]" -Function,+,sha256_finish,void,"sha256_context*, unsigned char[32]" -Function,+,sha256_process,void,sha256_context* -Function,+,sha256_start,void,sha256_context* -Function,+,sha256_update,void,"sha256_context*, const unsigned char*, unsigned int" Function,+,signal_reader_alloc,SignalReader*,"const GpioPin*, uint32_t" Function,+,signal_reader_free,void,SignalReader* Function,+,signal_reader_set_polarity,void,"SignalReader*, SignalReaderPolarity" @@ -2800,8 +2924,6 @@ Function,+,stream_write_vaformat,size_t,"Stream*, const char*, va_list" Function,-,strerror,char*,int Function,-,strerror_l,char*,"int, locale_t" Function,-,strerror_r,char*,"int, char*, size_t" -Function,-,strftime,size_t,"char*, size_t, const char*, const tm*" -Function,-,strftime_l,size_t,"char*, size_t, const char*, const tm*, locale_t" Function,+,string_stream_alloc,Stream*, Function,-,strlcat,size_t,"char*, const char*, size_t" Function,+,strlcpy,size_t,"char*, const char*, size_t" @@ -2816,8 +2938,6 @@ Function,-,strndup,char*,"const char*, size_t" Function,-,strnlen,size_t,"const char*, size_t" Function,-,strnstr,char*,"const char*, const char*, size_t" Function,-,strpbrk,char*,"const char*, const char*" -Function,-,strptime,char*,"const char*, const char*, tm*" -Function,-,strptime_l,char*,"const char*, const char*, tm*, locale_t" Function,+,strrchr,char*,"const char*, int" Function,-,strsep,char*,"char**, const char*" Function,-,strsignal,char*,int @@ -3047,7 +3167,6 @@ Function,+,text_input_set_validator,void,"TextInput*, TextInputValidatorCallback Function,-,tgamma,double,double Function,-,tgammaf,float,float Function,-,tgammal,long double,long double -Function,-,time,time_t,time_t* Function,-,timingsafe_bcmp,int,"const void*, const void*, size_t" Function,-,timingsafe_memcmp,int,"const void*, const void*, size_t" Function,-,tmpfile,FILE*, @@ -3061,25 +3180,6 @@ Function,-,toupper_l,int,"int, locale_t" Function,-,trunc,double,double Function,-,truncf,float,float Function,-,truncl,long double,long double -Function,-,tzset,void, -Function,-,uECC_compress,void,"const uint8_t*, uint8_t*, uECC_Curve" -Function,+,uECC_compute_public_key,int,"const uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_curve_private_key_size,int,uECC_Curve -Function,-,uECC_curve_public_key_size,int,uECC_Curve -Function,-,uECC_decompress,void,"const uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_get_rng,uECC_RNG_Function, -Function,-,uECC_make_key,int,"uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_secp160r1,uECC_Curve, -Function,-,uECC_secp192r1,uECC_Curve, -Function,-,uECC_secp224r1,uECC_Curve, -Function,-,uECC_secp256k1,uECC_Curve, -Function,+,uECC_secp256r1,uECC_Curve, -Function,+,uECC_set_rng,void,uECC_RNG_Function -Function,-,uECC_shared_secret,int,"const uint8_t*, const uint8_t*, uint8_t*, uECC_Curve" -Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uECC_Curve" -Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve" -Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve" -Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve" Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int" Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* @@ -3212,13 +3312,10 @@ Variable,-,MSIRangeTable,const uint32_t[16], Variable,-,SmpsPrescalerTable,const uint32_t[4][6], Variable,+,SystemCoreClock,uint32_t, Variable,+,_ctype_,const char[], -Variable,-,_daylight,int, Variable,+,_global_impure_ptr,_reent*, Variable,+,_impure_ptr,_reent*, Variable,-,_sys_errlist,const char*[], Variable,-,_sys_nerr,int, -Variable,-,_timezone,long, -Variable,-,_tzname,char*[2], Variable,+,cli_vcp,CliSession, Variable,+,firmware_api_interface,const ElfApiInterface*, Variable,+,furi_hal_i2c_bus_external,FuriHalI2cBus, diff --git a/targets/f7/furi_hal/furi_hal_usb_ccid.c b/targets/f7/furi_hal/furi_hal_usb_ccid.c index 5c35c69f88..e24713ced5 100644 --- a/targets/f7/furi_hal/furi_hal_usb_ccid.c +++ b/targets/f7/furi_hal/furi_hal_usb_ccid.c @@ -39,12 +39,12 @@ struct CcidIntfDescriptor { struct usb_ccid_descriptor ccid_desc; struct usb_endpoint_descriptor ccid_bulk_in; struct usb_endpoint_descriptor ccid_bulk_out; -} __attribute__((packed)); +} FURI_PACKED; struct CcidConfigDescriptor { struct usb_config_descriptor config; struct CcidIntfDescriptor intf_0; -} __attribute__((packed)); +} FURI_PACKED; enum CCID_Features_Auto_t { CCID_Features_Auto_None = 0x0, @@ -255,7 +255,7 @@ typedef struct ccid_bulk_message_header { uint32_t dwLength; uint8_t bSlot; uint8_t bSeq; -} __attribute__((packed)) ccid_bulk_message_header_t; +} FURI_PACKED ccid_bulk_message_header_t; uint8_t SendBuffer[sizeof(ccid_bulk_message_header_t) + CCID_DATABLOCK_SIZE]; diff --git a/targets/f7/furi_hal/furi_hal_usb_cdc.c b/targets/f7/furi_hal/furi_hal_usb_cdc.c index 4c4f727bad..e9cb51e203 100644 --- a/targets/f7/furi_hal/furi_hal_usb_cdc.c +++ b/targets/f7/furi_hal/furi_hal_usb_cdc.c @@ -35,13 +35,13 @@ struct CdcIadDescriptor { struct CdcConfigDescriptorSingle { struct usb_config_descriptor config; struct CdcIadDescriptor iad_0; -} __attribute__((packed)); +} FURI_PACKED; struct CdcConfigDescriptorDual { struct usb_config_descriptor config; struct CdcIadDescriptor iad_0; struct CdcIadDescriptor iad_1; -} __attribute__((packed)); +} FURI_PACKED; static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); diff --git a/targets/f7/furi_hal/furi_hal_usb_hid.c b/targets/f7/furi_hal/furi_hal_usb_hid.c index 334aa01026..b744e5ef72 100644 --- a/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -24,7 +24,7 @@ struct HidIntfDescriptor { struct HidConfigDescriptor { struct usb_config_descriptor config; struct HidIntfDescriptor intf_0; -} __attribute__((packed)); +} FURI_PACKED; enum HidReportId { ReportIdKeyboard = 1, @@ -199,7 +199,7 @@ struct HidReportMouse { int8_t x; int8_t y; int8_t wheel; -} __attribute__((packed)); +} FURI_PACKED; struct HidReportKB { uint8_t report_id; @@ -208,23 +208,23 @@ struct HidReportKB { uint8_t reserved; uint8_t btn[HID_KB_MAX_KEYS]; } boot; -} __attribute__((packed)); +} FURI_PACKED; struct HidReportConsumer { uint8_t report_id; uint16_t btn[HID_CONSUMER_MAX_KEYS]; -} __attribute__((packed)); +} FURI_PACKED; struct HidReportLED { uint8_t report_id; uint8_t led_state; -} __attribute__((packed)); +} FURI_PACKED; static struct HidReport { struct HidReportKB keyboard; struct HidReportMouse mouse; struct HidReportConsumer consumer; -} __attribute__((packed)) hid_report; +} FURI_PACKED hid_report; static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx); static void hid_deinit(usbd_device* dev); diff --git a/targets/f7/furi_hal/furi_hal_usb_u2f.c b/targets/f7/furi_hal/furi_hal_usb_u2f.c index fe711512a1..cc7e23b77e 100644 --- a/targets/f7/furi_hal/furi_hal_usb_u2f.c +++ b/targets/f7/furi_hal/furi_hal_usb_u2f.c @@ -25,7 +25,7 @@ struct HidIadDescriptor { struct HidConfigDescriptor { struct usb_config_descriptor config; struct HidIadDescriptor iad_0; -} __attribute__((packed)); +} FURI_PACKED; /* HID report: FIDO U2F */ static const uint8_t hid_u2f_report_desc[] = { diff --git a/targets/f7/target.json b/targets/f7/target.json index 63b5cdb927..7a816828c7 100644 --- a/targets/f7/target.json +++ b/targets/f7/target.json @@ -25,7 +25,6 @@ "fatfs", "littlefs", "subghz", - "flipperformat", "toolbox", "nfc", "digital_signal", @@ -39,12 +38,15 @@ "one_wire", "ibutton", "music_worker", - "misc", "mbedtls", "lfrfid", "flipper_application", - "flipperformat", "toolbox", + "u8g2", + "nanopb", + "update_util", + "heatshrink", + "flipperformat", "flipper7" ] } \ No newline at end of file From c1e0d02afc8131e782aa3f2e5c1bbd6f43890790 Mon Sep 17 00:00:00 2001 From: Augusto Zanellato Date: Fri, 1 Dec 2023 10:42:00 +0100 Subject: [PATCH 33/40] ST25TB poller refining + write support (#3239) * nfc: st25tb: rework async poller * nfc: st25tb: introduce sync poller * nfc: st25tb: add write support * nfc: st25tb: rewrite poller to use better states * nfc: st25tb: move to mode request state after success * nfc: st25tb: minor bug fixes * type wasn't properly set on ready event * sending NfcCustomEventPollerFailure on St25tbPollerEventTypeFailure caused poller to being freed and ultimately resulted in a thread crash Co-authored-by: Aleksandr Kutuzov --- .../helpers/protocol_support/st25tb/st25tb.c | 4 +- lib/nfc/SConscript | 1 + lib/nfc/protocols/st25tb/st25tb.c | 20 ++ lib/nfc/protocols/st25tb/st25tb.h | 5 +- lib/nfc/protocols/st25tb/st25tb_poller.c | 154 +++++++++++-- lib/nfc/protocols/st25tb/st25tb_poller.h | 40 +++- lib/nfc/protocols/st25tb/st25tb_poller_i.c | 194 ++++++++-------- lib/nfc/protocols/st25tb/st25tb_poller_i.h | 33 ++- lib/nfc/protocols/st25tb/st25tb_poller_sync.c | 211 ++++++++++++++++++ lib/nfc/protocols/st25tb/st25tb_poller_sync.h | 20 ++ targets/f18/api_symbols.csv | 2 +- targets/f7/api_symbols.csv | 11 +- 12 files changed, 566 insertions(+), 129 deletions(-) create mode 100644 lib/nfc/protocols/st25tb/st25tb_poller_sync.c create mode 100644 lib/nfc/protocols/st25tb/st25tb_poller_sync.h diff --git a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c index 32b2f47757..e22af48b34 100644 --- a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c +++ b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c @@ -29,7 +29,9 @@ static NfcCommand nfc_scene_read_poller_callback_st25tb(NfcGenericEvent event, v NfcApp* instance = context; const St25tbPollerEvent* st25tb_event = event.event_data; - if(st25tb_event->type == St25tbPollerEventTypeReady) { + if(st25tb_event->type == St25tbPollerEventTypeRequestMode) { + st25tb_event->data->mode_request.mode = St25tbPollerModeRead; + } else if(st25tb_event->type == St25tbPollerEventTypeSuccess) { nfc_device_set_data( instance->nfc_device, NfcProtocolSt25tb, nfc_poller_get_data(instance->poller)); view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 21f2fb49f6..d2cfbe2fb6 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -42,6 +42,7 @@ env.Append( File("protocols/iso14443_3a/iso14443_3a_poller_sync.h"), File("protocols/mf_ultralight/mf_ultralight_poller_sync.h"), File("protocols/mf_classic/mf_classic_poller_sync.h"), + File("protocols/st25tb/st25tb_poller_sync.h"), # Misc File("helpers/nfc_util.h"), File("helpers/iso14443_crc.h"), diff --git a/lib/nfc/protocols/st25tb/st25tb.c b/lib/nfc/protocols/st25tb/st25tb.c index d3fac7eeac..785cf831d9 100644 --- a/lib/nfc/protocols/st25tb/st25tb.c +++ b/lib/nfc/protocols/st25tb/st25tb.c @@ -232,3 +232,23 @@ St25tbData* st25tb_get_base_data(const St25tbData* data) { UNUSED(data); furi_crash("No base data"); } + +St25tbType st25tb_get_type_from_uid(const uint8_t* uid) { + switch(uid[2] >> 2) { + case 0x0: + case 0x3: + return St25tbTypeX4k; + case 0x4: + return St25tbTypeX512; + case 0x6: + return St25tbType512Ac; + case 0x7: + return St25tbType04k; + case 0xc: + return St25tbType512At; + case 0xf: + return St25tbType02k; + default: + furi_crash("unsupported st25tb type"); + } +} diff --git a/lib/nfc/protocols/st25tb/st25tb.h b/lib/nfc/protocols/st25tb/st25tb.h index 1edb296ca1..ed02dc2b20 100644 --- a/lib/nfc/protocols/st25tb/st25tb.h +++ b/lib/nfc/protocols/st25tb/st25tb.h @@ -1,6 +1,5 @@ #pragma once -#include #include #ifdef __cplusplus @@ -27,6 +26,7 @@ typedef enum { St25tbErrorFieldOff, St25tbErrorWrongCrc, St25tbErrorTimeout, + St25tbErrorWriteFailed, } St25tbError; typedef enum { @@ -44,7 +44,6 @@ typedef struct { St25tbType type; uint32_t blocks[ST25TB_MAX_BLOCKS]; uint32_t system_otp_block; - uint8_t chip_id; } St25tbData; extern const NfcDeviceBase nfc_device_st25tb; @@ -75,6 +74,8 @@ bool st25tb_set_uid(St25tbData* data, const uint8_t* uid, size_t uid_len); St25tbData* st25tb_get_base_data(const St25tbData* data); +St25tbType st25tb_get_type_from_uid(const uint8_t* uid); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/st25tb/st25tb_poller.c b/lib/nfc/protocols/st25tb/st25tb_poller.c index 2bc5dd9410..fd6dc4f09f 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller.c +++ b/lib/nfc/protocols/st25tb/st25tb_poller.c @@ -1,13 +1,12 @@ -#include "protocols/nfc_protocol.h" -#include "protocols/st25tb/st25tb.h" +#include "st25tb_poller.h" #include "st25tb_poller_i.h" #include -#include - #define TAG "ST25TBPoller" +typedef NfcCommand (*St25tbPollerStateHandler)(St25tbPoller* instance); + const St25tbData* st25tb_poller_get_data(St25tbPoller* instance) { furi_assert(instance); furi_assert(instance->data); @@ -20,6 +19,7 @@ static St25tbPoller* st25tb_poller_alloc(Nfc* nfc) { St25tbPoller* instance = malloc(sizeof(St25tbPoller)); instance->nfc = nfc; + instance->state = St25tbPollerStateSelect; instance->tx_buffer = bit_buffer_alloc(ST25TB_POLLER_MAX_BUFFER_SIZE); instance->rx_buffer = bit_buffer_alloc(ST25TB_POLLER_MAX_BUFFER_SIZE); @@ -60,6 +60,128 @@ static void instance->context = context; } +static NfcCommand st25tb_poller_select_handler(St25tbPoller* instance) { + NfcCommand command = NfcCommandContinue; + + do { + St25tbError error = st25tb_poller_select(instance, NULL); + if(error != St25tbErrorNone) { + instance->state = St25tbPollerStateFailure; + instance->st25tb_event_data.error = error; + break; + } + + instance->st25tb_event.type = St25tbPollerEventTypeReady; + instance->st25tb_event.data->ready.type = instance->data->type; + command = instance->callback(instance->general_event, instance->context); + instance->state = St25tbPollerStateRequestMode; + } while(false); + + return command; +} + +static NfcCommand st25tb_poller_request_mode_handler(St25tbPoller* instance) { + NfcCommand command = NfcCommandContinue; + instance->st25tb_event.type = St25tbPollerEventTypeRequestMode; + command = instance->callback(instance->general_event, instance->context); + + St25tbPollerEventDataModeRequest* mode_request_data = + &instance->st25tb_event_data.mode_request; + + furi_assert(mode_request_data->mode < St25tbPollerModeNum); + + if(mode_request_data->mode == St25tbPollerModeRead) { + instance->state = St25tbPollerStateRead; + instance->poller_ctx.read.current_block = 0; + } else { + instance->state = St25tbPollerStateWrite; + instance->poller_ctx.write.block_number = + mode_request_data->params.write_params.block_number; + instance->poller_ctx.write.block_data = mode_request_data->params.write_params.block_data; + } + + return command; +} + +static NfcCommand st25tb_poller_read_handler(St25tbPoller* instance) { + St25tbError error = St25tbErrorNone; + + do { + uint8_t total_blocks = st25tb_get_block_count(instance->data->type); + uint8_t* current_block = &instance->poller_ctx.read.current_block; + if(*current_block == total_blocks) { + error = st25tb_poller_read_block( + instance, &instance->data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); + if(error != St25tbErrorNone) { + FURI_LOG_E(TAG, "Failed to read OTP block"); + instance->state = St25tbPollerStateFailure; + instance->st25tb_event_data.error = error; + break; + } else { + instance->state = St25tbPollerStateSuccess; + break; + } + } else { + error = st25tb_poller_read_block( + instance, &instance->data->blocks[*current_block], *current_block); + if(error != St25tbErrorNone) { + FURI_LOG_E(TAG, "Failed to read block %d", *current_block); + instance->state = St25tbPollerStateFailure; + instance->st25tb_event_data.error = error; + break; + } + + *current_block += 1; + } + } while(false); + + return NfcCommandContinue; +} + +static NfcCommand st25tb_poller_write_handler(St25tbPoller* instance) { + St25tbPollerWriteContext* write_ctx = &instance->poller_ctx.write; + St25tbError error = + st25tb_poller_write_block(instance, write_ctx->block_data, write_ctx->block_number); + + if(error == St25tbErrorNone) { + instance->state = St25tbPollerStateSuccess; + } else { + instance->state = St25tbPollerStateFailure; + instance->st25tb_event_data.error = error; + } + + return NfcCommandContinue; +} + +NfcCommand st25tb_poller_success_handler(St25tbPoller* instance) { + NfcCommand command = NfcCommandContinue; + instance->st25tb_event.type = St25tbPollerEventTypeSuccess; + command = instance->callback(instance->general_event, instance->context); + furi_delay_ms(100); + instance->state = St25tbPollerStateRequestMode; + + return command; +} + +NfcCommand st25tb_poller_failure_handler(St25tbPoller* instance) { + NfcCommand command = NfcCommandContinue; + instance->st25tb_event.type = St25tbPollerEventTypeFailure; + command = instance->callback(instance->general_event, instance->context); + furi_delay_ms(100); + instance->state = St25tbPollerStateSelect; + + return command; +} + +static St25tbPollerStateHandler st25tb_poller_state_handlers[St25tbPollerStateNum] = { + [St25tbPollerStateSelect] = st25tb_poller_select_handler, + [St25tbPollerStateRequestMode] = st25tb_poller_request_mode_handler, + [St25tbPollerStateRead] = st25tb_poller_read_handler, + [St25tbPollerStateWrite] = st25tb_poller_write_handler, + [St25tbPollerStateSuccess] = st25tb_poller_success_handler, + [St25tbPollerStateFailure] = st25tb_poller_failure_handler, +}; + static NfcCommand st25tb_poller_run(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.protocol == NfcProtocolInvalid); @@ -69,26 +191,10 @@ static NfcCommand st25tb_poller_run(NfcGenericEvent event, void* context) { NfcEvent* nfc_event = event.event_data; NfcCommand command = NfcCommandContinue; - if(nfc_event->type == NfcEventTypePollerReady) { - if(instance->state != St25tbPollerStateActivated) { - St25tbError error = st25tb_poller_activate(instance, instance->data); + furi_assert(instance->state < St25tbPollerStateNum); - if(error == St25tbErrorNone) { - instance->st25tb_event.type = St25tbPollerEventTypeReady; - instance->st25tb_event_data.error = error; - command = instance->callback(instance->general_event, instance->context); - } else { - instance->st25tb_event.type = St25tbPollerEventTypeError; - instance->st25tb_event_data.error = error; - command = instance->callback(instance->general_event, instance->context); - // Add delay to switch context - furi_delay_ms(100); - } - } else { - instance->st25tb_event.type = St25tbPollerEventTypeReady; - instance->st25tb_event_data.error = St25tbErrorNone; - command = instance->callback(instance->general_event, instance->context); - } + if(nfc_event->type == NfcEventTypePollerReady) { + command = st25tb_poller_state_handlers[instance->state](instance); } return command; @@ -103,7 +209,7 @@ static bool st25tb_poller_detect(NfcGenericEvent event, void* context) { bool protocol_detected = false; St25tbPoller* instance = context; NfcEvent* nfc_event = event.event_data; - furi_assert(instance->state == St25tbPollerStateIdle); + furi_assert(instance->state == St25tbPollerStateSelect); if(nfc_event->type == NfcEventTypePollerReady) { St25tbError error = st25tb_poller_initiate(instance, NULL); diff --git a/lib/nfc/protocols/st25tb/st25tb_poller.h b/lib/nfc/protocols/st25tb/st25tb_poller.h index d3b85e3066..87687b7eba 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller.h +++ b/lib/nfc/protocols/st25tb/st25tb_poller.h @@ -3,8 +3,6 @@ #include "st25tb.h" #include -#include - #ifdef __cplusplus extern "C" { #endif @@ -12,11 +10,40 @@ extern "C" { typedef struct St25tbPoller St25tbPoller; typedef enum { - St25tbPollerEventTypeError, St25tbPollerEventTypeReady, + St25tbPollerEventTypeRequestMode, + St25tbPollerEventTypeFailure, + St25tbPollerEventTypeSuccess, } St25tbPollerEventType; typedef struct { + St25tbType type; +} St25tbPollerReadyData; + +typedef enum { + St25tbPollerModeRead, + St25tbPollerModeWrite, + + St25tbPollerModeNum, +} St25tbPollerMode; + +typedef struct { + uint8_t block_number; + uint32_t block_data; +} St25tbPollerEventDataModeRequestWriteParams; + +typedef union { + St25tbPollerEventDataModeRequestWriteParams write_params; +} St25tbPollerEventDataModeRequestParams; + +typedef struct { + St25tbPollerMode mode; + St25tbPollerEventDataModeRequestParams params; +} St25tbPollerEventDataModeRequest; + +typedef union { + St25tbPollerReadyData ready; + St25tbPollerEventDataModeRequest mode_request; St25tbError error; } St25tbPollerEventData; @@ -31,15 +58,18 @@ St25tbError st25tb_poller_send_frame( BitBuffer* rx_buffer, uint32_t fwt); -St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id); +St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id_ptr); -St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data); +St25tbError st25tb_poller_select(St25tbPoller* instance, uint8_t* chip_id_ptr); St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid); St25tbError st25tb_poller_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number); +St25tbError + st25tb_poller_write_block(St25tbPoller* instance, uint32_t block, uint8_t block_number); + St25tbError st25tb_poller_halt(St25tbPoller* instance); #ifdef __cplusplus diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_i.c b/lib/nfc/protocols/st25tb/st25tb_poller_i.c index 76c9a8b1fa..adb8626a30 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller_i.c +++ b/lib/nfc/protocols/st25tb/st25tb_poller_i.c @@ -1,8 +1,5 @@ #include "st25tb_poller_i.h" -#include "bit_buffer.h" -#include "core/core_defines.h" -#include "protocols/st25tb/st25tb.h" #include #define TAG "ST25TBPoller" @@ -18,17 +15,7 @@ static St25tbError st25tb_poller_process_error(NfcError error) { } } -static St25tbError st25tb_poller_prepare_trx(St25tbPoller* instance) { - furi_assert(instance); - - if(instance->state == St25tbPollerStateIdle) { - return st25tb_poller_activate(instance, NULL); - } - - return St25tbErrorNone; -} - -static St25tbError st25tb_poller_frame_exchange( +St25tbError st25tb_poller_send_frame( St25tbPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, @@ -48,7 +35,7 @@ static St25tbError st25tb_poller_frame_exchange( NfcError error = nfc_poller_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcErrorNone) { - FURI_LOG_D(TAG, "error during trx: %d", error); + FURI_LOG_T(TAG, "error during trx: %d", error); ret = st25tb_poller_process_error(error); break; } @@ -65,32 +52,11 @@ static St25tbError st25tb_poller_frame_exchange( return ret; } -St25tbType st25tb_get_type_from_uid(const uint8_t uid[ST25TB_UID_SIZE]) { - switch(uid[2] >> 2) { - case 0x0: - case 0x3: - return St25tbTypeX4k; - case 0x4: - return St25tbTypeX512; - case 0x6: - return St25tbType512Ac; - case 0x7: - return St25tbType04k; - case 0xc: - return St25tbType512At; - case 0xf: - return St25tbType02k; - default: - furi_crash("unsupported st25tb type"); - } -} - -St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id) { +St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id_ptr) { // Send Initiate() furi_assert(instance); furi_assert(instance->nfc); - instance->state = St25tbPollerStateInitiateInProgress; bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); bit_buffer_append_byte(instance->tx_buffer, 0x06); @@ -98,77 +64,90 @@ St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id) { St25tbError ret; do { - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); if(ret != St25tbErrorNone) { break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { - FURI_LOG_D(TAG, "Unexpected Initiate response size"); + FURI_LOG_E(TAG, "Unexpected Initiate response size"); ret = St25tbErrorCommunication; break; } - if(chip_id) { - *chip_id = bit_buffer_get_byte(instance->rx_buffer, 0); + uint8_t chip_id = bit_buffer_get_byte(instance->rx_buffer, 0); + FURI_LOG_D(TAG, "Got chip_id=0x%02X", chip_id); + if(chip_id_ptr) { + *chip_id_ptr = bit_buffer_get_byte(instance->rx_buffer, 0); } } while(false); return ret; } -St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data) { +St25tbError st25tb_poller_select(St25tbPoller* instance, uint8_t* chip_id_ptr) { furi_assert(instance); furi_assert(instance->nfc); - st25tb_reset(data); - St25tbError ret; do { - ret = st25tb_poller_initiate(instance, &data->chip_id); - if(ret != St25tbErrorNone) { - break; - } + uint8_t chip_id; - instance->state = St25tbPollerStateActivationInProgress; + if(chip_id_ptr != NULL) { + chip_id = *chip_id_ptr; + } else { + ret = st25tb_poller_initiate(instance, &chip_id); + if(ret != St25tbErrorNone) { + break; + } + } bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); // Send Select(Chip_ID), let's just assume that collisions won't ever happen :D bit_buffer_append_byte(instance->tx_buffer, 0x0E); - bit_buffer_append_byte(instance->tx_buffer, data->chip_id); + bit_buffer_append_byte(instance->tx_buffer, chip_id); - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); if(ret != St25tbErrorNone) { - instance->state = St25tbPollerStateActivationFailed; break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { - FURI_LOG_D(TAG, "Unexpected Select response size"); - instance->state = St25tbPollerStateActivationFailed; + FURI_LOG_E(TAG, "Unexpected Select response size"); ret = St25tbErrorCommunication; break; } - if(bit_buffer_get_byte(instance->rx_buffer, 0) != data->chip_id) { - FURI_LOG_D(TAG, "ChipID mismatch"); - instance->state = St25tbPollerStateActivationFailed; + if(bit_buffer_get_byte(instance->rx_buffer, 0) != chip_id) { + FURI_LOG_E(TAG, "ChipID mismatch"); ret = St25tbErrorColResFailed; break; } - instance->state = St25tbPollerStateActivated; - ret = st25tb_poller_get_uid(instance, data->uid); + ret = st25tb_poller_get_uid(instance, instance->data->uid); if(ret != St25tbErrorNone) { - instance->state = St25tbPollerStateActivationFailed; break; } - data->type = st25tb_get_type_from_uid(data->uid); + instance->data->type = st25tb_get_type_from_uid(instance->data->uid); + } while(false); + + return ret; +} + +St25tbError st25tb_poller_read(St25tbPoller* instance, St25tbData* data) { + furi_assert(instance); + furi_assert(instance->nfc); + + St25tbError ret; + + memcpy(data, instance->data, sizeof(St25tbData)); + + do { bool read_blocks = true; for(uint8_t i = 0; i < st25tb_get_block_count(data->type); i++) { ret = st25tb_poller_read_block(instance, &data->blocks[i], i); @@ -181,6 +160,9 @@ St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data) { break; } ret = st25tb_poller_read_block(instance, &data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); + if(ret != St25tbErrorNone) { + break; + } } while(false); return ret; @@ -198,15 +180,14 @@ St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) { bit_buffer_append_byte(instance->tx_buffer, 0x0B); - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); if(ret != St25tbErrorNone) { break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != ST25TB_UID_SIZE) { - FURI_LOG_D(TAG, "Unexpected Get_UID() response size"); - instance->state = St25tbPollerStateActivationFailed; + FURI_LOG_E(TAG, "Unexpected Get_UID() response size"); ret = St25tbErrorCommunication; break; } @@ -215,6 +196,17 @@ St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) { FURI_SWAP(uid[1], uid[6]); FURI_SWAP(uid[2], uid[5]); FURI_SWAP(uid[3], uid[4]); + FURI_LOG_I( + TAG, + "Got tag with uid: %02X %02X %02X %02X %02X %02X %02X %02X", + uid[0], + uid[1], + uid[2], + uid[3], + uid[4], + uid[5], + uid[6], + uid[7]); } while(false); return ret; } @@ -227,7 +219,7 @@ St25tbError furi_assert( (block_number <= st25tb_get_block_count(instance->data->type)) || block_number == ST25TB_SYSTEM_OTP_BLOCK); - FURI_LOG_D(TAG, "reading block %d", block_number); + FURI_LOG_T(TAG, "reading block %d", block_number); bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); @@ -236,19 +228,64 @@ St25tbError bit_buffer_append_byte(instance->tx_buffer, block_number); St25tbError ret; do { - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); if(ret != St25tbErrorNone) { break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != ST25TB_BLOCK_SIZE) { - FURI_LOG_D(TAG, "Unexpected Read_block(Addr) response size"); + FURI_LOG_E(TAG, "Unexpected Read_block(Addr) response size"); ret = St25tbErrorCommunication; break; } bit_buffer_write_bytes(instance->rx_buffer, block, ST25TB_BLOCK_SIZE); - FURI_LOG_D(TAG, "read result: %08lX", *block); + FURI_LOG_D(TAG, "Read_block(%d) result: %08lX", block_number, *block); + } while(false); + + return ret; +} + +St25tbError + st25tb_poller_write_block(St25tbPoller* instance, uint32_t block, uint8_t block_number) { + furi_assert(instance); + furi_assert(instance->nfc); + furi_assert( + (block_number <= st25tb_get_block_count(instance->data->type)) || + block_number == ST25TB_SYSTEM_OTP_BLOCK); + FURI_LOG_T(TAG, "writing block %d", block_number); + bit_buffer_reset(instance->tx_buffer); + + // Send Write_block(Addr, Data) + bit_buffer_append_byte(instance->tx_buffer, 0x09); + bit_buffer_append_byte(instance->tx_buffer, block_number); + bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)&block, ST25TB_BLOCK_SIZE); + St25tbError ret; + do { + ret = st25tb_poller_send_frame( + instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); + if(ret != St25tbErrorTimeout) { // tag doesn't ack writes so timeout are expected. + break; + } + + furi_delay_ms(7); // 7ms is the max programming time as per datasheet + + uint32_t block_check; + ret = st25tb_poller_read_block(instance, &block_check, block_number); + if(ret != St25tbErrorNone) { + FURI_LOG_E(TAG, "write verification failed: read error"); + break; + } + if(block_check != block) { + FURI_LOG_E( + TAG, + "write verification failed: wrote %08lX but read back %08lX", + block, + block_check); + ret = St25tbErrorWriteFailed; + break; + } + FURI_LOG_D(TAG, "wrote %08lX to block %d", block, block_number); } while(false); return ret; @@ -266,30 +303,13 @@ St25tbError st25tb_poller_halt(St25tbPoller* instance) { St25tbError ret; do { - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); if(ret != St25tbErrorTimeout) { break; } - instance->state = St25tbPollerStateIdle; - } while(false); - - return ret; -} - -St25tbError st25tb_poller_send_frame( - St25tbPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt) { - St25tbError ret; - - do { - ret = st25tb_poller_prepare_trx(instance); - if(ret != St25tbErrorNone) break; - - ret = st25tb_poller_frame_exchange(instance, tx_buffer, rx_buffer, fwt); + instance->state = St25tbPollerStateSelect; } while(false); return ret; diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_i.h b/lib/nfc/protocols/st25tb/st25tb_poller_i.h index 27218d7b44..e16feb7812 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller_i.h +++ b/lib/nfc/protocols/st25tb/st25tb_poller_i.h @@ -1,8 +1,9 @@ #pragma once -#include "protocols/st25tb/st25tb.h" #include "st25tb_poller.h" +#include + #ifdef __cplusplus extern "C" { #endif @@ -10,14 +11,30 @@ extern "C" { #define ST25TB_POLLER_MAX_BUFFER_SIZE (16U) typedef enum { - St25tbPollerStateIdle, - St25tbPollerStateInitiateInProgress, - St25tbPollerStateInitiateFailed, - St25tbPollerStateActivationInProgress, - St25tbPollerStateActivationFailed, - St25tbPollerStateActivated, + St25tbPollerStateSelect, + St25tbPollerStateRequestMode, + St25tbPollerStateRead, + St25tbPollerStateWrite, + St25tbPollerStateSuccess, + St25tbPollerStateFailure, + + St25tbPollerStateNum, } St25tbPollerState; +typedef struct { + uint8_t current_block; +} St25tbPollerReadContext; + +typedef struct { + uint8_t block_number; + uint32_t block_data; +} St25tbPollerWriteContext; + +typedef union { + St25tbPollerReadContext read; + St25tbPollerWriteContext write; +} St25tbPollerContext; + struct St25tbPoller { Nfc* nfc; St25tbPollerState state; @@ -25,6 +42,8 @@ struct St25tbPoller { BitBuffer* tx_buffer; BitBuffer* rx_buffer; + St25tbPollerContext poller_ctx; + NfcGenericEvent general_event; St25tbPollerEvent st25tb_event; St25tbPollerEventData st25tb_event_data; diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_sync.c b/lib/nfc/protocols/st25tb/st25tb_poller_sync.c new file mode 100644 index 0000000000..3cd0b37929 --- /dev/null +++ b/lib/nfc/protocols/st25tb/st25tb_poller_sync.c @@ -0,0 +1,211 @@ +#include "st25tb_poller_sync.h" +#include "st25tb_poller_i.h" + +#define ST25TB_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) + +typedef enum { + St25tbPollerCmdTypeDetectType, + St25tbPollerCmdTypeReadBlock, + St25tbPollerCmdTypeWriteBlock, + + St25tbPollerCmdTypeNum, +} St25tbPollerCmdType; + +typedef struct { + St25tbType* type; +} St25tbPollerCmdDetectTypeData; + +typedef struct { + St25tbData* data; +} St25tbPollerCmdReadData; + +typedef struct { + uint8_t block_num; + uint32_t* block; +} St25tbPollerCmdReadBlockData; + +typedef struct { + uint8_t block_num; + uint32_t block; +} St25tbPollerCmdWriteBlockData; + +typedef union { + St25tbPollerCmdDetectTypeData detect_type; + St25tbPollerCmdReadData read; + St25tbPollerCmdReadBlockData read_block; + St25tbPollerCmdWriteBlockData write_block; +} St25tbPollerCmdData; + +typedef struct { + FuriThreadId thread_id; + St25tbError error; + St25tbPollerCmdType cmd_type; + St25tbPollerCmdData cmd_data; +} St25tbPollerSyncContext; + +typedef St25tbError (*St25tbPollerCmdHandler)(St25tbPoller* poller, St25tbPollerCmdData* data); + +static St25tbError st25tb_poller_detect_handler(St25tbPoller* poller, St25tbPollerCmdData* data) { + uint8_t uid[ST25TB_UID_SIZE]; + St25tbError error = st25tb_poller_get_uid(poller, uid); + if(error == St25tbErrorNone) { + *data->detect_type.type = st25tb_get_type_from_uid(uid); + } + return error; +} + +static St25tbError + st25tb_poller_read_block_handler(St25tbPoller* poller, St25tbPollerCmdData* data) { + return st25tb_poller_read_block(poller, data->read_block.block, data->read_block.block_num); +} + +static St25tbError + st25tb_poller_write_block_handler(St25tbPoller* poller, St25tbPollerCmdData* data) { + return st25tb_poller_write_block(poller, data->write_block.block, data->write_block.block_num); +} + +static St25tbPollerCmdHandler st25tb_poller_cmd_handlers[St25tbPollerCmdTypeNum] = { + [St25tbPollerCmdTypeDetectType] = st25tb_poller_detect_handler, + [St25tbPollerCmdTypeReadBlock] = st25tb_poller_read_block_handler, + [St25tbPollerCmdTypeWriteBlock] = st25tb_poller_write_block_handler, +}; + +static NfcCommand st25tb_poller_cmd_callback(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.event_data); + furi_assert(event.instance); + furi_assert(event.protocol == NfcProtocolSt25tb); + + St25tbPollerSyncContext* poller_context = context; + St25tbPoller* st25tb_poller = event.instance; + St25tbPollerEvent* st25tb_event = event.event_data; + + if(st25tb_event->type == St25tbPollerEventTypeReady) { + poller_context->error = st25tb_poller_cmd_handlers[poller_context->cmd_type]( + st25tb_poller, &poller_context->cmd_data); + } else { + poller_context->error = st25tb_event->data->error; + } + + furi_thread_flags_set(poller_context->thread_id, ST25TB_POLLER_FLAG_COMMAND_COMPLETE); + + return NfcCommandStop; +} + +static St25tbError st25tb_poller_cmd_execute(Nfc* nfc, St25tbPollerSyncContext* poller_ctx) { + furi_assert(nfc); + furi_assert(poller_ctx->cmd_type < St25tbPollerCmdTypeNum); + poller_ctx->thread_id = furi_thread_get_current_id(); + + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolSt25tb); + nfc_poller_start(poller, st25tb_poller_cmd_callback, poller_ctx); + furi_thread_flags_wait(ST25TB_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(ST25TB_POLLER_FLAG_COMMAND_COMPLETE); + + nfc_poller_stop(poller); + nfc_poller_free(poller); + + return poller_ctx->error; +} + +St25tbError st25tb_poller_sync_read_block(Nfc* nfc, uint8_t block_num, uint32_t* block) { + furi_assert(block); + St25tbPollerSyncContext poller_context = { + .cmd_type = St25tbPollerCmdTypeReadBlock, + .cmd_data = + { + .read_block = + { + .block = block, + .block_num = block_num, + }, + }, + }; + return st25tb_poller_cmd_execute(nfc, &poller_context); +} + +St25tbError st25tb_poller_sync_write_block(Nfc* nfc, uint8_t block_num, uint32_t block) { + St25tbPollerSyncContext poller_context = { + .cmd_type = St25tbPollerCmdTypeWriteBlock, + .cmd_data = + { + .write_block = + { + .block = block, + .block_num = block_num, + }, + }, + }; + return st25tb_poller_cmd_execute(nfc, &poller_context); +} + +St25tbError st25tb_poller_sync_detect_type(Nfc* nfc, St25tbType* type) { + furi_assert(type); + St25tbPollerSyncContext poller_context = { + .cmd_type = St25tbPollerCmdTypeDetectType, + .cmd_data = + { + .detect_type = + { + .type = type, + }, + }, + }; + return st25tb_poller_cmd_execute(nfc, &poller_context); +} + +static NfcCommand nfc_scene_read_poller_callback_st25tb(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.event_data); + furi_assert(event.instance); + furi_assert(event.protocol == NfcProtocolSt25tb); + + St25tbPollerSyncContext* poller_context = context; + St25tbPollerEvent* st25tb_event = event.event_data; + + NfcCommand command = NfcCommandContinue; + if(st25tb_event->type == St25tbPollerEventTypeRequestMode) { + st25tb_event->data->mode_request.mode = St25tbPollerModeRead; + } else if( + st25tb_event->type == St25tbPollerEventTypeSuccess || + st25tb_event->type == St25tbPollerEventTypeFailure) { + if(st25tb_event->type == St25tbPollerEventTypeSuccess) { + memcpy( + poller_context->cmd_data.read.data, + st25tb_poller_get_data(event.instance), + sizeof(St25tbData)); + } else { + poller_context->error = st25tb_event->data->error; + } + command = NfcCommandStop; + furi_thread_flags_set(poller_context->thread_id, ST25TB_POLLER_FLAG_COMMAND_COMPLETE); + } + + return command; +} + +St25tbError st25tb_poller_sync_read(Nfc* nfc, St25tbData* data) { + furi_assert(nfc); + furi_assert(data); + + St25tbPollerSyncContext poller_context = { + .thread_id = furi_thread_get_current_id(), + .cmd_data = + { + .read = + { + .data = data, + }, + }, + }; + + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolSt25tb); + nfc_poller_start(poller, nfc_scene_read_poller_callback_st25tb, &poller_context); + furi_thread_flags_wait(ST25TB_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(ST25TB_POLLER_FLAG_COMMAND_COMPLETE); + + nfc_poller_stop(poller); + nfc_poller_free(poller); + + return poller_context.error; +} \ No newline at end of file diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_sync.h b/lib/nfc/protocols/st25tb/st25tb_poller_sync.h new file mode 100644 index 0000000000..ecd994b398 --- /dev/null +++ b/lib/nfc/protocols/st25tb/st25tb_poller_sync.h @@ -0,0 +1,20 @@ +#pragma once + +#include "st25tb.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +St25tbError st25tb_poller_sync_read_block(Nfc* nfc, uint8_t block_num, uint32_t* block); + +St25tbError st25tb_poller_sync_write_block(Nfc* nfc, uint8_t block_num, uint32_t block); + +St25tbError st25tb_poller_sync_detect_type(Nfc* nfc, St25tbType* type); + +St25tbError st25tb_poller_sync_read(Nfc* nfc, St25tbData* data); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index cd89b554af..e735e2c6dd 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,48.0,, +Version,+,49.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 45c98ae1a5..e25254dddd 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,48.0,, +Version,+,49.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -145,6 +145,7 @@ Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h,, Header,+,lib/nfc/protocols/slix/slix.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,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, @@ -2810,15 +2811,21 @@ Function,+,st25tb_free,void,St25tbData* Function,+,st25tb_get_base_data,St25tbData*,const St25tbData* Function,+,st25tb_get_block_count,uint8_t,St25tbType Function,+,st25tb_get_device_name,const char*,"const St25tbData*, NfcDeviceNameType" +Function,+,st25tb_get_type_from_uid,St25tbType,const uint8_t* Function,+,st25tb_get_uid,const uint8_t*,"const St25tbData*, size_t*" Function,+,st25tb_is_equal,_Bool,"const St25tbData*, const St25tbData*" Function,+,st25tb_load,_Bool,"St25tbData*, FlipperFormat*, uint32_t" -Function,+,st25tb_poller_activate,St25tbError,"St25tbPoller*, St25tbData*" Function,+,st25tb_poller_get_uid,St25tbError,"St25tbPoller*, uint8_t*" Function,+,st25tb_poller_halt,St25tbError,St25tbPoller* Function,+,st25tb_poller_initiate,St25tbError,"St25tbPoller*, uint8_t*" Function,+,st25tb_poller_read_block,St25tbError,"St25tbPoller*, uint32_t*, uint8_t" +Function,+,st25tb_poller_select,St25tbError,"St25tbPoller*, uint8_t*" Function,+,st25tb_poller_send_frame,St25tbError,"St25tbPoller*, const BitBuffer*, BitBuffer*, uint32_t" +Function,+,st25tb_poller_sync_detect_type,St25tbError,"Nfc*, St25tbType*" +Function,+,st25tb_poller_sync_read,St25tbError,"Nfc*, St25tbData*" +Function,+,st25tb_poller_sync_read_block,St25tbError,"Nfc*, uint8_t, uint32_t*" +Function,+,st25tb_poller_sync_write_block,St25tbError,"Nfc*, uint8_t, uint32_t" +Function,+,st25tb_poller_write_block,St25tbError,"St25tbPoller*, uint32_t, uint8_t" Function,+,st25tb_reset,void,St25tbData* Function,+,st25tb_save,_Bool,"const St25tbData*, FlipperFormat*" Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t" From b51a754fd95285069c360afa48de380e6311c8e2 Mon Sep 17 00:00:00 2001 From: Augusto Zanellato Date: Fri, 1 Dec 2023 14:25:53 +0100 Subject: [PATCH 34/40] Mifare Classic nested auth support (#3238) Co-authored-by: Aleksandr Kutuzov --- lib/nfc/protocols/mf_classic/crypto1.c | 9 +- lib/nfc/protocols/mf_classic/crypto1.h | 3 +- .../protocols/mf_classic/mf_classic_poller.h | 40 +++++++++ .../mf_classic/mf_classic_poller_i.c | 89 ++++++++++++++++--- targets/f18/api_symbols.csv | 2 +- targets/f7/api_symbols.csv | 4 +- 6 files changed, 128 insertions(+), 19 deletions(-) diff --git a/lib/nfc/protocols/mf_classic/crypto1.c b/lib/nfc/protocols/mf_classic/crypto1.c index df01a348c8..02bc677ba6 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.c +++ b/lib/nfc/protocols/mf_classic/crypto1.c @@ -143,7 +143,8 @@ void crypto1_encrypt_reader_nonce( uint32_t cuid, uint8_t* nt, uint8_t* nr, - BitBuffer* out) { + BitBuffer* out, + bool is_nested) { furi_assert(crypto); furi_assert(nt); furi_assert(nr); @@ -153,7 +154,11 @@ void crypto1_encrypt_reader_nonce( uint32_t nt_num = nfc_util_bytes2num(nt, sizeof(uint32_t)); crypto1_init(crypto, key); - crypto1_word(crypto, nt_num ^ cuid, 0); + if(is_nested) { + nt_num = crypto1_word(crypto, nt_num ^ cuid, 1) ^ nt_num; + } else { + crypto1_word(crypto, nt_num ^ cuid, 0); + } for(size_t i = 0; i < 4; i++) { uint8_t byte = crypto1_byte(crypto, nr[i], 0) ^ nr[i]; diff --git a/lib/nfc/protocols/mf_classic/crypto1.h b/lib/nfc/protocols/mf_classic/crypto1.h index f2bdb272b0..7cc16fcffd 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.h +++ b/lib/nfc/protocols/mf_classic/crypto1.h @@ -35,7 +35,8 @@ void crypto1_encrypt_reader_nonce( uint32_t cuid, uint8_t* nt, uint8_t* nr, - BitBuffer* out); + BitBuffer* out, + bool is_nested); uint32_t prng_successor(uint32_t x, uint32_t n); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index f05a6800ad..19e5257017 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -178,6 +178,25 @@ MfClassicError mf_classic_poller_get_nt( MfClassicKeyType key_type, MfClassicNt* nt); +/** + * @brief Collect tag nonce during nested authentication. + * + * Must ONLY be used inside the callback function. + * + * Starts nested authentication procedure and collects tag nonce. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number for authentication. + * @param[in] key_type key type to be used for authentication. + * @param[out] nt pointer to the MfClassicNt structure to be filled with nonce data. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_get_nt_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt); + /** * @brief Perform authentication. * @@ -200,6 +219,27 @@ MfClassicError mf_classic_poller_auth( MfClassicKeyType key_type, MfClassicAuthContext* data); +/** + * @brief Perform nested authentication. + * + * Must ONLY be used inside the callback function. + * + * Perform nested authentication as specified in Mf Classic protocol. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number for authentication. + * @param[in] key key to be used for authentication. + * @param[in] key_type key type to be used for authentication. + * @param[out] data pointer to MfClassicAuthContext structure to be filled with authentication data. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_auth_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data); + /** * @brief Halt the tag. * diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 4b071815ea..16bfb3f728 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -33,11 +33,12 @@ MfClassicError mf_classic_process_error(Iso14443_3aError error) { return ret; } -MfClassicError mf_classic_poller_get_nt( +static MfClassicError mf_classic_poller_get_nt_common( MfClassicPoller* instance, uint8_t block_num, MfClassicKeyType key_type, - MfClassicNt* nt) { + MfClassicNt* nt, + bool is_nested) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -47,14 +48,29 @@ MfClassicError mf_classic_poller_get_nt( uint8_t auth_cmd[2] = {auth_type, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd)); - error = iso14443_3a_poller_send_standard_frame( - instance->iso14443_3a_poller, - instance->tx_plain_buffer, - instance->rx_plain_buffer, - MF_CLASSIC_FWT_FC); - if(error != Iso14443_3aErrorWrongCrc) { - ret = mf_classic_process_error(error); - break; + if(is_nested) { + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, + instance->tx_encrypted_buffer, + instance->rx_plain_buffer, // NT gets decrypted by mf_classic_async_auth + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorNone) { + ret = mf_classic_process_error(error); + break; + } + } else { + error = iso14443_3a_poller_send_standard_frame( + instance->iso14443_3a_poller, + instance->tx_plain_buffer, + instance->rx_plain_buffer, + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorWrongCrc) { + ret = mf_classic_process_error(error); + break; + } } if(bit_buffer_get_size_bytes(instance->rx_plain_buffer) != sizeof(MfClassicNt)) { ret = MfClassicErrorProtocol; @@ -69,12 +85,29 @@ MfClassicError mf_classic_poller_get_nt( return ret; } -MfClassicError mf_classic_poller_auth( +MfClassicError mf_classic_poller_get_nt( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt) { + return mf_classic_poller_get_nt_common(instance, block_num, key_type, nt, false); +} + +MfClassicError mf_classic_poller_get_nt_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt) { + return mf_classic_poller_get_nt_common(instance, block_num, key_type, nt, true); +} + +static MfClassicError mf_classic_poller_auth_common( MfClassicPoller* instance, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, - MfClassicAuthContext* data) { + MfClassicAuthContext* data, + bool is_nested) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -84,7 +117,11 @@ MfClassicError mf_classic_poller_auth( iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); MfClassicNt nt = {}; - ret = mf_classic_poller_get_nt(instance, block_num, key_type, &nt); + if(is_nested) { + ret = mf_classic_poller_get_nt_nested(instance, block_num, key_type, &nt); + } else { + ret = mf_classic_poller_get_nt(instance, block_num, key_type, &nt); + } if(ret != MfClassicErrorNone) break; if(data) { data->nt = nt; @@ -96,7 +133,13 @@ MfClassicError mf_classic_poller_auth( furi_hal_random_fill_buf(nr.data, sizeof(MfClassicNr)); crypto1_encrypt_reader_nonce( - instance->crypto, key_num, cuid, nt.data, nr.data, instance->tx_encrypted_buffer); + instance->crypto, + key_num, + cuid, + nt.data, + nr.data, + instance->tx_encrypted_buffer, + is_nested); error = iso14443_3a_poller_txrx_custom_parity( instance->iso14443_3a_poller, instance->tx_encrypted_buffer, @@ -130,6 +173,24 @@ MfClassicError mf_classic_poller_auth( return ret; } +MfClassicError mf_classic_poller_auth( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data) { + return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, false); +} + +MfClassicError mf_classic_poller_auth_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data) { + return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, true); +} + MfClassicError mf_classic_poller_halt(MfClassicPoller* instance) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index e735e2c6dd..cb34f969ad 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.0,, +Version,+,49.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index e25254dddd..439fc7bf5a 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.0,, +Version,+,49.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2288,6 +2288,8 @@ Function,+,mf_classic_is_sector_trailer,_Bool,uint8_t Function,+,mf_classic_is_value_block,_Bool,"MfClassicSectorTrailer*, uint8_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_auth_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_get_nt_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" Function,+,mf_classic_poller_get_nt,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller* Function,+,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*" From 6a5d63803aeadc9f2b3cb4f150bb32dee841dc03 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Sat, 2 Dec 2023 07:45:47 +0300 Subject: [PATCH 35/40] [FL-3675] Ntag21x write (#3246) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New scenes for ultralight poller write mode * Added new button and transition logic for write operation For now write is only possible for NTAG21x cards with default password and no AUTHLIM set * Poller states extended * Enums and datatypes extended for new poller mode * Added mode field to poller instance datatype * New states for poller added in order to implement write mode * Added new event type for locked cards in order to simplify state flow * New logic for poller write commands * Scenes adjustments * Scenes renamed * New field added to poller instance * Now we write in 'page per call' mode * Now function takes callback return value into account * Callback will be called only in write mode * Event type added * Log adjusted and start page to write set * Logs added and check in now false at start, then it moves to true * Now mf_ultralight_poller_handler_request_write_data halts card in case of check failure and stops poller * All fail events now returns NfcCommandStop callback * In case of fail we move back properly * Remove garbage Co-authored-by: gornekich Co-authored-by: あく --- .../mf_ultralight/mf_ultralight.c | 13 ++ .../main/nfc/scenes/nfc_scene_config.h | 4 + .../scenes/nfc_scene_mf_ultralight_write.c | 119 +++++++++++++++ .../nfc_scene_mf_ultralight_write_fail.c | 67 +++++++++ .../nfc_scene_mf_ultralight_write_success.c | 43 ++++++ .../nfc_scene_mf_ultralight_wrong_card.c | 58 ++++++++ .../mf_ultralight/mf_ultralight_poller.c | 139 +++++++++++++++++- .../mf_ultralight/mf_ultralight_poller.h | 16 ++ .../mf_ultralight/mf_ultralight_poller_i.h | 7 + 9 files changed, 462 insertions(+), 4 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index c4fd04c7e5..3e27fc539e 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -12,6 +12,7 @@ enum { SubmenuIndexUnlock = SubmenuIndexCommonMax, SubmenuIndexUnlockByReader, SubmenuIndexUnlockByPassword, + SubmenuIndexWrite, }; static void nfc_scene_info_on_enter_mf_ultralight(NfcApp* instance) { @@ -106,6 +107,15 @@ static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instanc SubmenuIndexUnlock, nfc_protocol_support_common_submenu_callback, instance); + } else if( + data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 || + data->type == MfUltralightTypeNTAG216) { + submenu_add_item( + submenu, + "Write", + SubmenuIndexWrite, + nfc_protocol_support_common_submenu_callback, + instance); } } @@ -146,6 +156,9 @@ static bool if(event == SubmenuIndexUnlock) { scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu); return true; + } else if(event == SubmenuIndexWrite) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite); + return true; } return false; } diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index f415c66a6f..a9887996d6 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -24,6 +24,10 @@ ADD_SCENE(nfc, field, Field) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) +ADD_SCENE(nfc, mf_ultralight_write, MfUltralightWrite) +ADD_SCENE(nfc, mf_ultralight_write_success, MfUltralightWriteSuccess) +ADD_SCENE(nfc, mf_ultralight_write_fail, MfUltralightWriteFail) +ADD_SCENE(nfc, mf_ultralight_wrong_card, MfUltralightWrongCard) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c new file mode 100644 index 0000000000..b3c1beef5a --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c @@ -0,0 +1,119 @@ +#include "../nfc_app_i.h" + +#include + +enum { + NfcSceneMfUltralightWriteStateCardSearch, + NfcSceneMfUltralightWriteStateCardFound, +}; + +NfcCommand nfc_scene_mf_ultralight_write_worker_callback(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.event_data); + furi_assert(event.protocol == NfcProtocolMfUltralight); + + NfcCommand command = NfcCommandContinue; + NfcApp* instance = context; + MfUltralightPollerEvent* mfu_event = event.event_data; + + if(mfu_event->type == MfUltralightPollerEventTypeRequestMode) { + mfu_event->data->poller_mode = MfUltralightPollerModeWrite; + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected); + } else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) { + mfu_event->data->auth_context.skip_auth = true; + } else if(mfu_event->type == MfUltralightPollerEventTypeRequestWriteData) { + mfu_event->data->write_data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight); + } else if(mfu_event->type == MfUltralightPollerEventTypeCardMismatch) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWrongCard); + command = NfcCommandStop; + } else if(mfu_event->type == MfUltralightPollerEventTypeCardLocked) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerFailure); + command = NfcCommandStop; + } else if(mfu_event->type == MfUltralightPollerEventTypeWriteFail) { + command = NfcCommandStop; + } else if(mfu_event->type == MfUltralightPollerEventTypeWriteSuccess) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + command = NfcCommandStop; + } + return command; +} + +static void nfc_scene_mf_ultralight_write_setup_view(NfcApp* instance) { + Popup* popup = instance->popup; + popup_reset(popup); + uint32_t state = + scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfUltralightWrite); + + if(state == NfcSceneMfUltralightWriteStateCardSearch) { + popup_set_text( + instance->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_icon(popup, 12, 23, &A_Loading_24); + } + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + +void nfc_scene_mf_ultralight_write_on_enter(void* context) { + NfcApp* instance = context; + dolphin_deed(DolphinDeedNfcEmulate); + + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfUltralightWrite, + NfcSceneMfUltralightWriteStateCardSearch); + nfc_scene_mf_ultralight_write_setup_view(instance); + + // Setup and start worker + FURI_LOG_D("WMFU", "Card searching..."); + instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfUltralight); + nfc_poller_start(instance->poller, nfc_scene_mf_ultralight_write_worker_callback, instance); + + nfc_blink_emulate_start(instance); +} + +bool nfc_scene_mf_ultralight_write_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventCardDetected) { + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfUltralightWrite, + NfcSceneMfUltralightWriteStateCardFound); + nfc_scene_mf_ultralight_write_setup_view(instance); + consumed = true; + } else if(event.event == NfcCustomEventWrongCard) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrongCard); + consumed = true; + } else if(event.event == NfcCustomEventPollerSuccess) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWriteSuccess); + consumed = true; + } else if(event.event == NfcCustomEventPollerFailure) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWriteFail); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_ultralight_write_on_exit(void* context) { + NfcApp* instance = context; + + nfc_poller_stop(instance->poller); + nfc_poller_free(instance->poller); + + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfUltralightWrite, + NfcSceneMfUltralightWriteStateCardSearch); + // Clear view + popup_reset(instance->popup); + + nfc_blink_stop(instance); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c new file mode 100644 index 0000000000..dff5f27815 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c @@ -0,0 +1,67 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_write_fail_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* instance = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_ultralight_write_fail_on_enter(void* context) { + NfcApp* instance = context; + Widget* widget = instance->widget; + + notification_message(instance->notifications, &sequence_error); + + widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!"); + widget_add_string_multiline_element( + widget, + 7, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Card protected by\npassword, AUTH0\nor lock bits"); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Finish", + nfc_scene_mf_ultralight_write_fail_widget_callback, + instance); + + // Setup and start worker + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +static bool nfc_scene_mf_ultralight_write_fail_move_to_back_scene(const NfcApp* const instance) { + bool was_saved = scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSavedMenu); + uint32_t scene_id = was_saved ? NfcSceneSavedMenu : NfcSceneReadMenu; + + return scene_manager_search_and_switch_to_previous_scene(instance->scene_manager, scene_id); +} + +bool nfc_scene_mf_ultralight_write_fail_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = nfc_scene_mf_ultralight_write_fail_move_to_back_scene(instance); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = nfc_scene_mf_ultralight_write_fail_move_to_back_scene(instance); + } + return consumed; +} + +void nfc_scene_mf_ultralight_write_fail_on_exit(void* context) { + NfcApp* instance = context; + + widget_reset(instance->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c new file mode 100644 index 0000000000..c1fbc35ee5 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c @@ -0,0 +1,43 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_write_success_popup_callback(void* context) { + NfcApp* instance = context; + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_ultralight_write_success_on_enter(void* context) { + NfcApp* instance = context; + dolphin_deed(DolphinDeedNfcSave); + + notification_message(instance->notifications, &sequence_success); + + Popup* popup = instance->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, instance); + popup_set_callback(popup, nfc_scene_mf_ultralight_write_success_popup_callback); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_ultralight_write_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneSavedMenu); + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_write_success_on_exit(void* context) { + NfcApp* instance = context; + + // Clear view + popup_reset(instance->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c new file mode 100644 index 0000000000..a225c474db --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c @@ -0,0 +1,58 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_wrong_card_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* instance = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_ultralight_wrong_card_on_enter(void* context) { + NfcApp* instance = context; + Widget* widget = instance->widget; + + notification_message(instance->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); + widget_add_string_multiline_element( + widget, + 4, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Card of the same\ntype should be\n presented"); + //"Data management\nis only possible\nwith card of same type"); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + nfc_scene_mf_ultralight_wrong_card_widget_callback, + instance); + + // Setup and start worker + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_ultralight_wrong_card_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(instance->scene_manager); + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_wrong_card_on_exit(void* context) { + NfcApp* instance = context; + + widget_reset(instance->widget); +} \ No newline at end of file diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 86ab68c8b1..619cd8c5fb 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -224,11 +224,24 @@ static NfcCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance instance->tearing_flag_read = 0; instance->tearing_flag_total = 3; instance->pages_read = 0; - instance->state = MfUltralightPollerStateReadVersion; - + instance->state = MfUltralightPollerStateRequestMode; + instance->current_page = 0; return NfcCommandContinue; } +static NfcCommand mf_ultralight_poller_handler_request_mode(MfUltralightPoller* instance) { + NfcCommand command = NfcCommandContinue; + + instance->mfu_event.type = MfUltralightPollerEventTypeRequestMode; + instance->mfu_event.data->poller_mode = MfUltralightPollerModeRead; + + command = instance->callback(instance->general_event, instance->context); + instance->mode = instance->mfu_event.data->poller_mode; + + instance->state = MfUltralightPollerStateReadVersion; + return command; +} + static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { instance->error = mf_ultralight_poller_read_version(instance, &instance->data->version); if(instance->error == MfUltralightErrorNone) { @@ -259,6 +272,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPo } static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { + MfUltralightPollerState next_state = MfUltralightPollerStateGetFeatureSet; MfUltralightPageReadCommandData data = {}; instance->error = mf_ultralight_poller_read_page(instance, 41, &data); if(instance->error == MfUltralightErrorNone) { @@ -268,8 +282,13 @@ static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller FURI_LOG_D(TAG, "Original Ultralight detected"); iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->data->type = MfUltralightTypeUnknown; + if(instance->mode == MfUltralightPollerModeWrite) { + instance->mfu_event.type = MfUltralightPollerEventTypeCardMismatch; + instance->callback(instance->general_event, instance->context); + next_state = MfUltralightPollerStateWriteFail; + } } - instance->state = MfUltralightPollerStateGetFeatureSet; + instance->state = next_state; return NfcCommandContinue; } @@ -508,6 +527,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { FURI_LOG_D(TAG, "Read Failed"); iso14443_3a_poller_halt(instance->iso14443_3a_poller); + instance->mfu_event.type = MfUltralightPollerEventTypeReadFailed; instance->mfu_event.data->error = instance->error; NfcCommand command = instance->callback(instance->general_event, instance->context); instance->state = MfUltralightPollerStateIdle; @@ -516,15 +536,121 @@ static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* ins static NfcCommand mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) { FURI_LOG_D(TAG, "Read success"); - iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->mfu_event.type = MfUltralightPollerEventTypeReadSuccess; NfcCommand command = instance->callback(instance->general_event, instance->context); + + if(instance->mode == MfUltralightPollerModeRead) { + iso14443_3a_poller_halt(instance->iso14443_3a_poller); + instance->state = MfUltralightPollerStateIdle; + } else { + instance->state = MfUltralightPollerStateRequestWriteData; + } + + return command; +} + +static NfcCommand mf_ultralight_poller_handler_request_write_data(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Check writing capability"); + NfcCommand command = NfcCommandContinue; + MfUltralightPollerState next_state = MfUltralightPollerStateWritePages; + instance->current_page = 4; + + instance->mfu_event.type = MfUltralightPollerEventTypeRequestWriteData; + instance->callback(instance->general_event, instance->context); + + const MfUltralightData* write_data = instance->mfu_event.data->write_data; + const MfUltralightData* tag_data = instance->data; + uint32_t features = mf_ultralight_get_feature_support_set(tag_data->type); + + bool check_passed = false; + do { + if(write_data->type != tag_data->type) { + FURI_LOG_D(TAG, "Incorrect tag type"); + instance->mfu_event.type = MfUltralightPollerEventTypeCardMismatch; + break; + } + + if(!instance->auth_context.auth_success) { + FURI_LOG_D(TAG, "Unknown password"); + instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked; + break; + } + + const MfUltralightPage staticlock_page = tag_data->page[2]; + if(staticlock_page.data[2] != 0 || staticlock_page.data[3] != 0) { + FURI_LOG_D(TAG, "Static lock bits are set"); + instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked; + break; + } + + if(mf_ultralight_support_feature(features, MfUltralightFeatureSupportDynamicLock)) { + uint8_t dynlock_num = mf_ultralight_get_config_page_num(tag_data->type) - 1; + const MfUltralightPage dynlock_page = tag_data->page[dynlock_num]; + if(dynlock_page.data[0] != 0 || dynlock_page.data[1] != 0) { + FURI_LOG_D(TAG, "Dynamic lock bits are set"); + instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked; + break; + } + } + + check_passed = true; + } while(false); + + if(!check_passed) { + iso14443_3a_poller_halt(instance->iso14443_3a_poller); + command = instance->callback(instance->general_event, instance->context); + next_state = MfUltralightPollerStateWriteFail; + } + + instance->state = next_state; + return command; +} + +static NfcCommand mf_ultralight_poller_handler_write_pages(MfUltralightPoller* instance) { + NfcCommand command = NfcCommandContinue; + + do { + const MfUltralightData* write_data = instance->mfu_event.data->write_data; + uint8_t end_page = mf_ultralight_get_config_page_num(write_data->type) - 1; + if(instance->current_page == end_page) { + instance->state = MfUltralightPollerStateWriteSuccess; + break; + } + FURI_LOG_D(TAG, "Writing page %d", instance->current_page); + MfUltralightError error = mf_ultralight_poller_write_page( + instance, instance->current_page, &write_data->page[instance->current_page]); + if(error != MfUltralightErrorNone) { + instance->state = MfUltralightPollerStateWriteFail; + instance->error = error; + break; + } + instance->current_page++; + } while(false); + + return command; +} + +static NfcCommand mf_ultralight_poller_handler_write_fail(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Write failed"); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); + instance->mfu_event.data->error = instance->error; + instance->mfu_event.type = MfUltralightPollerEventTypeWriteFail; + NfcCommand command = instance->callback(instance->general_event, instance->context); + return command; +} + +static NfcCommand mf_ultralight_poller_handler_write_success(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Write success"); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); + instance->mfu_event.type = MfUltralightPollerEventTypeWriteSuccess; + NfcCommand command = instance->callback(instance->general_event, instance->context); return command; } static const MfUltralightPollerReadHandler mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = { [MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle, + [MfUltralightPollerStateRequestMode] = mf_ultralight_poller_handler_request_mode, [MfUltralightPollerStateReadVersion] = mf_ultralight_poller_handler_read_version, [MfUltralightPollerStateDetectMfulC] = mf_ultralight_poller_handler_check_ultralight_c, [MfUltralightPollerStateDetectNtag203] = mf_ultralight_poller_handler_check_ntag_203, @@ -538,6 +664,11 @@ static const MfUltralightPollerReadHandler [MfUltralightPollerStateReadPages] = mf_ultralight_poller_handler_read_pages, [MfUltralightPollerStateReadFailed] = mf_ultralight_poller_handler_read_fail, [MfUltralightPollerStateReadSuccess] = mf_ultralight_poller_handler_read_success, + [MfUltralightPollerStateRequestWriteData] = + mf_ultralight_poller_handler_request_write_data, + [MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages, + [MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail, + [MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success, }; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index 665d90cb70..2343be089b 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -16,13 +16,27 @@ typedef struct MfUltralightPoller MfUltralightPoller; * @brief Enumeration of possible MfUltralight poller event types. */ typedef enum { + MfUltralightPollerEventTypeRequestMode, /**< Poller requests for operating mode. */ MfUltralightPollerEventTypeAuthRequest, /**< Poller requests to fill authentication context. */ MfUltralightPollerEventTypeAuthSuccess, /**< Authentication succeeded. */ MfUltralightPollerEventTypeAuthFailed, /**< Authentication failed. */ MfUltralightPollerEventTypeReadSuccess, /**< Poller read card successfully. */ MfUltralightPollerEventTypeReadFailed, /**< Poller failed to read card. */ + MfUltralightPollerEventTypeRequestWriteData, /**< Poller request card data for write operation. */ + MfUltralightPollerEventTypeCardMismatch, /**< Type of card for writing differs from presented one. */ + MfUltralightPollerEventTypeCardLocked, /**< Presented card is locked by password, AUTH0 or lock bytes. */ + MfUltralightPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */ + MfUltralightPollerEventTypeWriteFail, /**< Poller failed to write card. */ } MfUltralightPollerEventType; +/** + * @brief Enumeration of possible MfUltralight poller operating modes. + */ +typedef enum { + MfUltralightPollerModeRead, /**< Poller will only read card. It's a default mode. */ + MfUltralightPollerModeWrite, /**< Poller will write already saved card to another presented card. */ +} MfUltralightPollerMode; + /** * @brief MfUltralight poller authentication context. */ @@ -39,6 +53,8 @@ typedef struct { typedef union { MfUltralightPollerAuthContext auth_context; /**< Authentication context. */ MfUltralightError error; /**< Error code indicating reading fail reason. */ + const MfUltralightData* write_data; + MfUltralightPollerMode poller_mode; } MfUltralightPollerEventData; /** diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index c89402b421..7c7354b1c6 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -49,6 +49,7 @@ typedef union { typedef enum { MfUltralightPollerStateIdle, + MfUltralightPollerStateRequestMode, MfUltralightPollerStateReadVersion, MfUltralightPollerStateDetectMfulC, MfUltralightPollerStateDetectNtag203, @@ -61,6 +62,10 @@ typedef enum { MfUltralightPollerStateTryDefaultPass, MfUltralightPollerStateReadFailed, MfUltralightPollerStateReadSuccess, + MfUltralightPollerStateRequestWriteData, + MfUltralightPollerStateWritePages, + MfUltralightPollerStateWriteFail, + MfUltralightPollerStateWriteSuccess, MfUltralightPollerStateNum, } MfUltralightPollerState; @@ -68,6 +73,7 @@ typedef enum { struct MfUltralightPoller { Iso14443_3aPoller* iso14443_3a_poller; MfUltralightPollerState state; + MfUltralightPollerMode mode; BitBuffer* tx_buffer; BitBuffer* rx_buffer; MfUltralightData* data; @@ -79,6 +85,7 @@ struct MfUltralightPoller { uint8_t counters_total; uint8_t tearing_flag_read; uint8_t tearing_flag_total; + uint16_t current_page; MfUltralightError error; NfcGenericEvent general_event; From 93732865acac9053cb0c580a2bf3e58962b3a678 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Sat, 2 Dec 2023 08:52:04 +0400 Subject: [PATCH 36/40] [FL-3132] HID app: Add new function key icons (#3236) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add new function key icons * Fix graphical glitches on the buttons Co-authored-by: あく --- applications/system/hid_app/assets/Alt_11x7.png | Bin 2417 -> 0 bytes applications/system/hid_app/assets/Alt_17x10.png | Bin 0 -> 550 bytes applications/system/hid_app/assets/Cmd_15x7.png | Bin 2426 -> 0 bytes applications/system/hid_app/assets/Cmd_17x10.png | Bin 0 -> 556 bytes applications/system/hid_app/assets/Ctrl_15x7.png | Bin 2433 -> 0 bytes .../system/hid_app/assets/Ctrl_17x10.png | Bin 0 -> 552 bytes applications/system/hid_app/assets/Del_12x7.png | Bin 2417 -> 0 bytes applications/system/hid_app/assets/Del_17x10.png | Bin 0 -> 551 bytes applications/system/hid_app/assets/Esc_14x7.png | Bin 2430 -> 0 bytes applications/system/hid_app/assets/Esc_17x10.png | Bin 0 -> 550 bytes applications/system/hid_app/assets/Tab_15x7.png | Bin 2419 -> 0 bytes applications/system/hid_app/assets/Tab_17x10.png | Bin 0 -> 549 bytes applications/system/hid_app/views/hid_keyboard.c | 14 +++++++------- 13 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 applications/system/hid_app/assets/Alt_11x7.png create mode 100644 applications/system/hid_app/assets/Alt_17x10.png delete mode 100644 applications/system/hid_app/assets/Cmd_15x7.png create mode 100644 applications/system/hid_app/assets/Cmd_17x10.png delete mode 100644 applications/system/hid_app/assets/Ctrl_15x7.png create mode 100644 applications/system/hid_app/assets/Ctrl_17x10.png delete mode 100644 applications/system/hid_app/assets/Del_12x7.png create mode 100644 applications/system/hid_app/assets/Del_17x10.png delete mode 100644 applications/system/hid_app/assets/Esc_14x7.png create mode 100644 applications/system/hid_app/assets/Esc_17x10.png delete mode 100644 applications/system/hid_app/assets/Tab_15x7.png create mode 100644 applications/system/hid_app/assets/Tab_17x10.png diff --git a/applications/system/hid_app/assets/Alt_11x7.png b/applications/system/hid_app/assets/Alt_11x7.png deleted file mode 100644 index 3e4bf320ee313c725e228356b6bf58989e804441..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2417 zcmbtVdsGu=79SqVBOtIXmWphdCPf~SC-O=|SV#a}0MIvsdA#66UH}hCLeQNGkr)bq zcTa>1R32bv_F?`7bNu@j92v z`l8yzhW7qnMoXqL9u8oW115)RouiKo*y%c3U!Xp?HC)*;s#de{#`Mk&>7CTA2M#+O z-lDTv({%Ojqbaa?pl7CLb}3=}LU4di?!BDea*vzjVF*~Jz*o@)l&bxPA+j_S9Sc1i1mNL1KbF+DpzfjGLEg>amgp`<$n!g7O z4LeaQ_RUh>s}RCYx$OlJQn!|$bLVPD--*{vpQI+h?4C}~Gx1;gI8Wwje*SIvS*|+b z+_%NP&ts`Imd$ovpY19!#akK43s0ZzjW~YHXt>bR%EUU~jvih;?c16eQEmU7MeJof z^WboQtFW)=rjF{W%KAZYk!{hVKXKI?j~2B3zA-y>Vk2Ys+x$bIIh+=~`}A3o^_cYJ z*cs``x!Xe%gH4XVECMy5dlp;A$GRB4rAw5@o#&gTq+ygRrWvWyvgA(Vcm<`KDWD4q zv*v8bMI($&@1F(>?b~)r@+DpDkIYy&_sDm#)8!F)_5R_i`a9T9_y-Brd#HHp-R|RP$5K=5!=8%Rhwf3P zi-s9`nd5!oHLl~^{uxe6{{e|s2R!i#lyJ{b!;(amr%(OSHT;>bZ99-&r>r+hFo<3l znQikfOl+GiwB3@a85rT-{}EH6s!s;@x5f<7&{#C~6I)Cbu%|n9YFpyu#nXQ$jl#tr z_p5xPdZ`=-Nsd?3^(M)Vps|ggWgCm=`}Vq*yKO=A8F(z%e>fX;+0%TeT(5Ip+U~YLLDMh=lygg!Ga*WQb=;t? z$L*}^jS)fC9c8xTPotG`y8)m#tzp;F{PTV3PxQJ6f!Y&GdP{anlN;hY?Zkk{hav^> zLLuNp$VPyk&Rc*UA?Xk&pu+@o37JD&tj}RUe_0Oza^ea2NRT)P43;7|f=Lkt$a1AI zKnE6s<-+h_y3=Gd7R!?XGF>I{Viwa81RaDTF)Y^_I|6|23EfpRlM{NYvY{54=Dj_T zm{@c;G!l;#{(&tB%U3@_g`@*-n__C99OXE^punoT8aw|K@;dqPft%e zgGFbtsDuR-OO@jyB~^}5UVyyB;X{}hg%voA$U!ZxC=N-+y~t#3pw(lAr%WLfu7;9h zD|rza(v>0wok?TRWitBfJTW{3S|j;dPb@T50ntMs3`s`C5MfSv9S~8t|4ra^PBLZr+gf(V6dJ|a$*L2_Kc=MoB<1eUP3G5y?J`2Kz_?wSZMbQI|zk|ts&BO4VTHGzoJ{Q=g_q+wXVfp^zX8k zXkadhi1cz8a7jU`yfR`w>=5vMLf_q#b0C@ofJXY2^MiFZqHE;VgEL)Go44AN4T`EP zs4c-k#>KST&6=a;Qx$1IIfMUXdufGPq$qdvcazVeHJe9^ckO70@?kEP)L%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ8|eBA@6YN^=FSz=Hm(eG{(jQj8)Dum3s32i>k78GhN>N&o-=07*qoM6N<$g1ch(GXMYp literal 0 HcmV?d00001 diff --git a/applications/system/hid_app/assets/Cmd_15x7.png b/applications/system/hid_app/assets/Cmd_15x7.png deleted file mode 100644 index a63a4be747a89745cbb32b5c9fb55d754f600dae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2426 zcmbtVdsGu=79So3iM+POA}pt*Ns))-i6kTqu|NWi-5{nsTv^1B3}k?0(##-1d9^^x z3RnxPRtt@fibYsq1q2#h1rb5^6xgQ15d`EVT@a)$LKR^r5rI9}?jJjIX6DYFdw=)d z-}l`+e+~%_vcfsy006KOyw4M1PaEtq-(ZH_yL0Sa0l?H63J3^E2nY&*6JgbdO0fhC z0u`VNl8A!*0l=rAAS_De6lTZ$s-b%8JKtyNN=pl^7rp;dlPK!SzB|4MR?GW5ixO-6 zjNxQQJvW-~>2@K1vAH+b`~mUF9#eDVQSV`n_qTs_C$#h1 z809B}i9cM;dX{mSe=niAH*4qT)zmb*0h9VC$30ZX?tf;h2^;A{b1TVE^-bF)umQ4| zAp%j_D>*9M47XVlcJPYRI9hgr*>!#EdEJRP+kq@~QX}Vf%M@>+mKI%%OG+0NTaMYh z1q=>(kg5*M5#Op3LLRy81rajFt)Fw}>&M=VHBOr%#X;=uPS&~DLw=r9dBZ>dF8n;V zIil?A zGMe%EP+zOCx9GN!=9ADjBX}DqHFDqC^Ek(G z+3E3fveWZF4o(gtoiG)>FGh*vDrQ)J~yofff5qK+n@ z2nw_2od`uEREM|E;tO5dK9uH5yVyIdy>A^OAkxPTUAhz_qDaHcyOKAa?ANjwC;f7; zrsL)g4b!%#qo*U`_R(&|UUr%yB2OC_uF>8>enQ`gbBrgUt#@@Ls*a_m=m*_Z(GQq= zEEmnwO)@5W!|S{!w*4a{(;Te?5}1K+!qAGaVgiJaGBQlnG1aqYG@ zDYF~~^8UVSaz>~6=~BD(P(D;rQ+x7Xhi{8I_1(EWmsvK06(*g}WbKU1xZ$hQKn1r{{Y0d8ZH^f* z_W3dEMq|WI$BuI6iP=cC!lfVRNxiyv>DluGX^%~G13>+$C6gr=^~Rf$JMGwj$Om@| zVueD$1CuuZCPuFVCYWS|oq!PyFvesKcF{kB08@h=02J60@RPzZAU;F}qc9?am3X>0 znTmI#Q|Vq*9~zS^C)4RHDxT&ojg`=8?s&YLP%MEIdSiD0Fg|6xf@X8dWJNaDBS$ge zkFkkGfkJnqyM=#XOJF%!tdB-k%awWqfTLz(q8voUc(puHfw0xS1cL<|ll5u}0dFut z6MPA~g(3I=SOwx4WGb0T;NtLjJVzysWs7)$%kJ2lFF}T)N;ZX(oSaNf_9DZoI0}u$ zVo|7c3Y|{EEJ#R-0u`%C3WWFqy^GhUgNro zyu$8ksfKoVu}k&zvIA707==}#Fr3K!KU&-n>A%3%WTD?P?42qI+Ztkh*KlbZ$~xV$ zJ%^%isWmP3qJIrqtbw^WEYiziz{SOuRSshFAymNg3*GEca5xVK*xH(wEG$tZI^C|J zL$f^%z2nt{Ga--b{~ecAmiV6MR}0tG@eKBfEez4@=ryZ5nJ0OpR!6h}7pY?r@<$Fc huhluV`!L-O&R7cBE}ON;j!OLi67Yk07yb8r@*g!;qu&4k diff --git a/applications/system/hid_app/assets/Cmd_17x10.png b/applications/system/hid_app/assets/Cmd_17x10.png new file mode 100644 index 0000000000000000000000000000000000000000..26ca3395c699cd19f2ae3c12d46954a45310eab7 GIT binary patch literal 556 zcmV+{0@MA8P)L%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ8n!+r=$Vtj3glk1^)H`0000501vCmP2ndL{yrdq5DkeKY1oo)gKX&HK%$+;;{_gMI z@4I*Y9vTw7oajgd0ARW3FTybVX^USLmge}qGsnRd0L*NlfPm1%fZzZ)2}V9rNu*#f zs00y68W!vi0KNqU5ixS72z&mwH5F^#`z1?PQc`H6_x?v^Qdmd!tr0y~q3H1}N~#p> zX&$?M5L)duIC~6o=i3YH>c8(V>NiB!yS}@vbUcrGq%!n~S(e*O`;*|q*Bq=yYrHCI zi>ebZwD$ZqTs)a^uNR%@UACv%GkRaIi>asMY3kkU0~J??wOTG#pWePay`8$|%e@|Z zSDXBCu;JpZ@kvr+Z|CFl(}sl6)1kp8xwmt=%6wbM10bMZdF5=(PBX#NCacc487uAk zNyVgr6_=}ksJFkfeQ>tzz*nr?*g#LWQ~7#rcdo@f%Hz#u7U+ZSFL~bI|KLt;4Q%!) z{U(HR{X*8$%yWUa6Sdu0>vvZ$((U^Q)sOdkAp7p@veQHi^@gT602oAi=ILOPyTLYiXPi&Q>vFi;2k@Va3+Nw(kJ_ z10K}!9n+L|%EgdJZfil5+~?}Axii(nZ^fIYPf!yeZf85^c>EUv&xyRjU*Cv4!PiEe z{BFPhvsmhR`$iYP&$kp?V@-_Y*+);dM;$z1IZ()PSmv1TLXWJP@^8wFs&YMM7kduN z+&$3KBw@M#*Jr1Wtz>L{Q@Dp@3#CPGJ$i!ZI3hnh za$J6R=0^WmUxWK^dfz{dOPJ~AqMSks|PHKBxQ*m-q%BPoJLeS+-k{>rv1 zA86QiU2R=$i7k6Om0P&!%BZ~Bph!*aP4qtYUV`H`D%NyMcMxeaG{oNPERVg%-fXS6 z$RK2nc1ND~9$ou$Br*L*I9eP0&@V*BKTeHEl2jZ$vdKI0iK%ldkY1y%wM;ONo*kNQ zURRjdJYDF#I&-jhh=1o7RD)8o%ys8ol4^UAucU8Z7tt^U4trX zRbSpu8^)$|$o;deHUs(4!OE&{{{6+}=Apqj;u)65Th@0k9daA}airF%qr|3azx*yx z{t3&s0T$_>IdrEU2T_f=@2u zM%Lx}sP&F*rOu;|qSZ>5UZ5-O!WP5RXFJj#5_Ek)^&tbn;G$l3MS8Op9}xNAMp3+2 z40zzOB|tD)0T6J>1U~^2CSZ!oJp5wqf&jBQJpd^2Cm@i)aUdyF4r4GXhgBq&H;qAZ zV=-7>3|}Ujrl7G{90rN$EsK}3nC>K!n^+=+ltyEB05Cmdx`1YTh_E1A7?ESx@Td61 zqC?>uv5n%ta;30>CNV~%sTC@t0l-spaZv$c5|Ubxq(r%DKk}Rf7nhA{I+-+Qf+hNq zH;O|^0WboRd}s_BgUlzANF*L2i|2+3gXZ1wH$So*!&F>4JtZZDmf}T&kpw!E!{N{w zEINxt#Vx34suGi^sY;ac9OMO#5JaU2q{1LrNiyO};^1V=k4!cOS~%u;DpX?eLMSCV zpBJ7XT`f`3nKTAnp`gFY6UD;7MUt=dM8i{6AUzC3;bcS#;^vfB0pW%F-vnOeghBDI z32yu{$9thBc*;CHh*-=O!qQ{~sKi7k$aw8WLmI@R>aNOS*Y`9^KedOIqxC|ITUg z2Idp-NH2x~pLi|e*bRI>M2m!i@V8gx>=vxJM6x9084PH0_rF5MbS?FO2pDzR5MjZ* zwk&l7d}deg9ccNd!iI}=F85dO%9S@&l&}v#b~bM?zl!cVm9q)ib$xhxQ?%EK84a&h c-wD*%=rG#yo8xYw#yKPk3=y98-}>2q0D4cRIRF3v diff --git a/applications/system/hid_app/assets/Ctrl_17x10.png b/applications/system/hid_app/assets/Ctrl_17x10.png new file mode 100644 index 0000000000000000000000000000000000000000..0eda72160009907c74a5f44e2dd90cd923f1fdfb GIT binary patch literal 552 zcmV+@0@wYCP)L%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ8xs5R007ntcL;*T1E?xm8=0AOSR^Z7w>e1AR?kD%|VBvQy9 zQbH&!4fgi|09IaJXq0?Ys5S5J)n!{Z|CG^LRFrQq@BU?Zd~iqRtAM6VKY)s_wgif`Ns|I)}IS72nUHoGK4GWt8DK(?08e@?SP)W7V!@ zH3e01S6h33A1RznyVs|l=v#NF$|dqhpS_`r?FGu+p9jlsjOcV6tS+^EeQG;p>*t4^ z4{tH}^HBY@TlXiy#=fq{m!}tE$1Vi<8)VMmimkOm=Oe#7-kQ3s5?pEQ|uMbDV& zw#65MgReGJ0O4aI^2t8U!=li*R2+yYS?Uw z3`Et`W}(C>o=zJ2LG7kd?A&?Jjvuz3?K~E1)t{kBsN=RYP6*~I7~(==LRxU4`H1CP zz`&q0rF8!^`K?kB?3~@27cTd>@muyx)yV5HhN%;jSeVn*&OQ_KnYYVC&d_gv3Omcw zg`fN8sLxX|<+637z1PQk3eB-5dcxeJ*~IYU$4m$F**5EJbM0wi6;nP<>ERU)-&%<) zvGjw3y-lK?f))eqHLdO4paQ#s`+wuc81Jul`h6a_9I|h|X>7EE?o+fte$alteo`Jvt~F0fmKP_qo5iTeoeUvO zn4dATiBvF5-}v@vFyEp1Jz1`-gR|4Z{l*cJTK2HIqchon9IW-ssm&Qp@@|}um3=i( z-gbSb*3+uHt-CF*<#3mB4<}U_o>Su&rmeZD{uSFCYrBtvHQnkwjLxr-)PBc-GtN zRT&%mbN>16_*5tQ>!ntU!Cd%wdBxZN{;Z*Scqp29k?H)p`Q0B*IF4Nzt=ZI3WKnTc zeitbHfXS*yg!4~rdXmpTYOOJA&SBg1?n<`hKnbD!iM-Y0Kc1EIfI-KlLG@vmdBBu|Qa`*Q~oPz1fNnh+HT_ z7$Xt^&bVv}5DZ=g2)JZ`pMU`aFw~C_{9=9r14fH_08rvjz*~kyLtu~`!4S0^QGrZ% zDjjrW(wVMw7Q>UOpfZ_kI>>OB#YmY9ClGWLNu;n+Z|npBh9?Y{(acW}mSqz?vc>mq zuiz7l28Tpo5u$fEQba+O=%Z0J3YFdf;A%LysDLmDs8Pf#)f|l%Y0-j%%X&491TLCj zabBbdQ4q*SPzdy((y4S3j|hSw7nQ|uf(3p{?)aM*NseJE4vm(SltfK(r6Oo7jlpKK zX>=xy$)w;G6m_x^lV~VPHTfCHa~uJrmZGoAzP zIOZk6^~q?|AvW>%nwBri_55z zplV28QZLf;ny$`KpXTDCaNxCkJiX~`7Tufmaz1NZSNN$a$P}QuI@^z zi|z1im+H&Q;iHfQL(mWeiRb+vExs7(zra?p(C-;eAPVDKL!$2*9)n9;qg%4)()2C0 zs>Po5@1hoOU>*^V^n4ibh&vkWJn{LkODOOTd1GVN!44t-niAY+7sQnTK`9ZNcc54D zdVd^D3=VgLXD diff --git a/applications/system/hid_app/assets/Del_17x10.png b/applications/system/hid_app/assets/Del_17x10.png new file mode 100644 index 0000000000000000000000000000000000000000..13d736983079f920184d157d83054efe809a6981 GIT binary patch literal 551 zcmV+?0@(eDP)L%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ8Askdnas~hZ002ovPDHLkV1h}~`Pcve literal 0 HcmV?d00001 diff --git a/applications/system/hid_app/assets/Esc_14x7.png b/applications/system/hid_app/assets/Esc_14x7.png deleted file mode 100644 index 3be4691d8a3d050bf14f5bd29099705d984eead7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2430 zcmbtVd0Z2B79Wn~hzL|c3X3HsMGnb{97#jikN`{DAf;Rjix`rD43JEk86Z#&yI@6u zYN2ZFVxuB>z$$A%py*mKBFC=4mI@092#B~KNL_&nLMMp8e$?$BJM)>DH*enizVCa# z-+OZ)z~6Tx&I$(rz(&8{^8&G_F?Q)2=wWwv-!w}A&^3m*+<v=Simijq*nh57?RfWgR%dBxf$^ftSCt8Y9oao&i=ax<=Tw+b$vNCS zarXqY-FbN74CKHzK^?M0L z_@PZVs({e9zcqP$x$XFu^qeSfC;JO|i|XDS{RhOEa9w@maqkx_mvet{AhdcnyOw?9 zPyFFp)_mp_@4NBp-mG1RRMd2{0iBweV~+Bp_x77AgGc(%oJ(X#b<=bStc47xi9lrC z)qQf@G+QkU{`9K#7<&GKTgUf1&UPM;H66%OB-XQ98Yg)RRkWxgTw+FGkFmiSHuA9BoT%?}m3-ufwLu4Z&gjCT4YDHdXOwKGa$4sx6(bBBL=E95L&9eV!T zV_wgrNY!SIwjQ7FE;2%!sEG?tpCyH!IBqahz_8e0m1j!{shaj`$_%ZtJ7XGk11Nv9*4-B0a->VTo0%>R&8_nZQP$l-9-{BYTE&sjrk>6d^0uXhs0UpYQ4ie0jTZGY zbTY?#L#kcIcm6#Dm;N0bq4s^^;V)vBkb)Bgs^Zgsa0z*)ZPN;**DC4^V)Y^xMrNBm z3*wt+3v9M$4)>3+@7+d}a^)ujdz&H$$?_<9)F(EG(l@R%Wol>qe;204o^Aj_)CYgiGH4zgng2_)a*x3OOrA_@aVbpStBx?!1_&eT2$IjwwY&xEX#5r z_irCfOn1s3UT!rW%7ac+R(A?tg#Me*C+!I_r*7Z}GWBZ%PS>DD~VI?B1IVzrrvXEZ1qD7q`0ZjUB!=1(dT(6*GYfJ9YGcw)>A+ zH|j%oS+$kfj6aP~NNxLp?zC&Wm*$_Rra#f?8~|!gF6k`UDmL5{-f6`KL>?IC7sKZR zj+kr!=xA*MbTCN^I{_^kppD5a?4s|70NrIh07$VXz!AaGAU;40qc9?dWq7&^nTofk zQ|ZoBcbXenLZ;IhR6NZ^6eFb59PoI1zCZ{`HO3AApnXz%70vjh&Z?}hLGJnTOanHt zC{R!s8pi*SDTF0tfhHPRA(3ee0G5J@i4qVM;1!YtDZ*5E5SA^Nn54|aG~R;{ z#t*=AVL6C*B~!^%0vm_N<5_Z13^S1Dv*M1uc@V@XDq~V8$;rv&WM?ugkEPHU3M)^8&i-)kcjEVp)%a595-h-h7XPA?ako2x^rFW z9Cs?shfDW%Wl>&nT`S`Xte+G?1yUin0t>Cdy8asMI@ecVdD!1D2^9IrVaf6`$^>!* z)RfeN@Uo`sbJV1{yeLfQjeK^#na?Y(Ykby_MQ<#i%da7?b6rDTt?pW?%kA)Dmukw( zyW|kIH3XWjVbfTYS9B}(EQ+S3*0tD+{$18$ z4a~-2kzNi1Htt}oi#0YM!u)ugptmja4}FFMwi$5ECzmq+75*R5*5m-we>@y*$vKxY zAG8&G0zb~F*_t%HiK%t_!@*SA{?KYw%I1l<1B0H$7Y?Yhjp~}=Ae$L}&Y^QP^R6{p bCa#;5Jap7X#>00@?kEP)L%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ8X71d%_jiBy ze&4Z;t|yP45ZTAFV?=k--}LTG#D?a?`?O5Wp9kWkG% z+&q5g7`(}IaP~Xcm1D=Xt^dBipnpE9-ud0VW%qN)C#yqFnr67nv^@zr@h^MJu{zHx zT|sU9m6o30hl?lEMtaeS-c^TdJ)(+wos2yk&XMo^JWzFgSg&Vc^_sTTnl`fgp+dL9 zO-AnwHvD+|{v_Dg+xht7^nBddxsV{E>^oUq<-RwF0}wE`_S*UA{ifWfO_rT8GnV@I z6Nd2qh<=wBJxq5uz zeG^Rj`AWvq^a}xZ;`QAb+rF%#Y3%w;Y9AkQQx)C)+*TVt)PrSLP~fU-w)0ROY&k^& zqIH+ERD>yxUK0N4kBOYY-`E4qNC ze>u?8Bu@imz_H-|pE>%qU*|P{P@kDRzLvJ;CH2 zYaeQTY`a>!TH|jNb}DwWG>XU^U0{S(cMJU$doRvmFBxmP-EmCSI^Q4~>8uou`0TQp zGfy)~AM1{|=ry+apAiJjB_v88^w2L@$|)g-Cy1*~o&4A<;)$_i3!te}>n!5TqGpGt zo44f0H&5p~Zb~2Q9pc=*iE35aPx|&ZMfX!wB9-V9M^qcMw)vxDUtOs)8W7Rd^{QKb5=ApqDLIuNZoz=acj=PLq8r5xRFSV{YBD)7v ze#-D|Km>Eo?7NdoAXIDSJL~-Z^sWm`oBnc>wx_Zd@BMLuS0;gSPO18FsM=W{(`W4a zOUBju$ZZa-WsYNyqSOkfUZ5-W%I^86&r&oGO*;C3+T-&k^G@nj*Ce-E@Bxtv?G(fc zg@79_TL30TYXB2mGQv;5hz=OzG8?}bpTmIZf*t@A_!Hntkr)UJks%m@$`B>U@S@N_ z7Y2>tN%N)qP~;Q_gGmGFUeZ_zgYF7~E<&*cRv3(30l@gU@e-QNag!z4+<+YIgB-vo z78MTLiR~1A#F8L#ir5g1qLwQS1^`>l!bLfRi9xkIL4mT=e#8X}7A_mqR3f-wg2nq0 zcM3y59-@LkZwieRfCgM~43dcX5s8LCOUEKlxl$-x3Z+07 z^TIQvs>MnwokF9^<oW3Eb(d3JXou&!)KFd) zPX&oFL=}c037r3<#TO#|7uX6GhCRdDrh@UUAvSakht8(Hq+7ISQw=S(qQ#!~?}8R@ zU=9I~^kNur2&4j+L3}<41$=JU+v`gXZ6^Sr1<&i!eBlpoisu6aj&a4RFF$vo+%;~I;vL%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ805AxW#{Ykr9-0u-+Re!Ys32*Va5DoCOQQ;aSac0_jg3zVnM+Y|nGr}v+m<$F n&ROGyli#B?gm};CuYPx{fw(FRB*KjF00000NkvXXu0mjf2deXy literal 0 HcmV?d00001 diff --git a/applications/system/hid_app/views/hid_keyboard.c b/applications/system/hid_app/views/hid_keyboard.c index 17ff754f52..9060c1d6a6 100644 --- a/applications/system/hid_app/views/hid_keyboard.c +++ b/applications/system/hid_app/views/hid_keyboard.c @@ -49,7 +49,7 @@ typedef struct { #define ROW_COUNT 7 #define COLUMN_COUNT 12 -// 0 width items are not drawn, but there value is used +// 0 width items are not drawn, but their value is used const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { { {.width = 1, .icon = &I_ButtonF1_5x8, .value = HID_KEYBOARD_F1}, @@ -140,17 +140,17 @@ const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { {.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW}, }, { - {.width = 2, .icon = &I_Ctrl_15x7, .value = HID_KEYBOARD_L_CTRL}, + {.width = 2, .icon = &I_Ctrl_17x10, .value = HID_KEYBOARD_L_CTRL}, {.width = 0, .value = HID_KEYBOARD_L_CTRL}, - {.width = 2, .icon = &I_Alt_11x7, .value = HID_KEYBOARD_L_ALT}, + {.width = 2, .icon = &I_Alt_17x10, .value = HID_KEYBOARD_L_ALT}, {.width = 0, .value = HID_KEYBOARD_L_ALT}, - {.width = 2, .icon = &I_Cmd_15x7, .value = HID_KEYBOARD_L_GUI}, + {.width = 2, .icon = &I_Cmd_17x10, .value = HID_KEYBOARD_L_GUI}, {.width = 0, .value = HID_KEYBOARD_L_GUI}, - {.width = 2, .icon = &I_Tab_15x7, .value = HID_KEYBOARD_TAB}, + {.width = 2, .icon = &I_Tab_17x10, .value = HID_KEYBOARD_TAB}, {.width = 0, .value = HID_KEYBOARD_TAB}, - {.width = 2, .icon = &I_Esc_14x7, .value = HID_KEYBOARD_ESCAPE}, + {.width = 2, .icon = &I_Esc_17x10, .value = HID_KEYBOARD_ESCAPE}, {.width = 0, .value = HID_KEYBOARD_ESCAPE}, - {.width = 2, .icon = &I_Del_12x7, .value = HID_KEYBOARD_DELETE_FORWARD}, + {.width = 2, .icon = &I_Del_17x10, .value = HID_KEYBOARD_DELETE_FORWARD}, {.width = 0, .value = HID_KEYBOARD_DELETE_FORWARD}, }, }; From 04cead1fc56d4093bffee8d3a4a7b47fba93061f Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Sat, 2 Dec 2023 09:03:10 +0400 Subject: [PATCH 37/40] [FL-3620] Add the "remove pairing" button to BLE hid (#3237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/system/hid_app/hid.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/applications/system/hid_app/hid.c b/applications/system/hid_app/hid.c index a42fc60917..88a68f09d0 100644 --- a/applications/system/hid_app/hid.c +++ b/applications/system/hid_app/hid.c @@ -14,8 +14,22 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexMouse, HidSubmenuIndexMouseClicker, HidSubmenuIndexMouseJiggler, + HidSubmenuIndexRemovePairing, }; +static void bt_hid_remove_pairing(Bt* bt) { + bt_disconnect(bt); + + // Wait 2nd core to update nvm storage + furi_delay_ms(200); + + furi_hal_bt_stop_advertising(); + + bt_forget_bonded_devices(bt); + + furi_hal_bt_start_advertising(); +} + static void hid_submenu_callback(void* context, uint32_t index) { furi_assert(context); Hid* app = context; @@ -45,6 +59,8 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexMouseJiggler) { app->view_id = HidViewMouseJiggler; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler); + } else if(index == HidSubmenuIndexRemovePairing) { + bt_hid_remove_pairing(app->bt); } } @@ -143,6 +159,14 @@ Hid* hid_alloc(HidTransport transport) { HidSubmenuIndexMouseJiggler, hid_submenu_callback, app); + if(transport == HidTransportBle) { + submenu_add_item( + app->device_type_submenu, + "Remove Pairing", + HidSubmenuIndexRemovePairing, + hid_submenu_callback, + app); + } view_set_previous_callback(submenu_get_view(app->device_type_submenu), hid_exit); view_dispatcher_add_view( app->view_dispatcher, HidViewSubmenu, submenu_get_view(app->device_type_submenu)); From c6a14e1a6779ded87b848b06b2cbc51a147f96b3 Mon Sep 17 00:00:00 2001 From: pborsutzki Date: Sat, 2 Dec 2023 08:27:58 +0100 Subject: [PATCH 38/40] Fixed a zero allocation error when reading an iso15693 nfc tag with no additional blocks. (#3229) Co-authored-by: gornekich --- .../iso15693_3/iso15693_3_poller_i.c | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c index 917f7dbb8e..ca6f5435e3 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c @@ -108,28 +108,30 @@ Iso15693_3Error iso15693_3_poller_activate(Iso15693_3Poller* instance, Iso15693_ break; } - // Read blocks: Optional command - simple_array_init(data->block_data, system_info->block_count * system_info->block_size); - ret = iso15693_3_poller_read_blocks( - instance, - simple_array_get_data(data->block_data), - system_info->block_count, - system_info->block_size); - if(ret != Iso15693_3ErrorNone) { - ret = iso15693_3_poller_filter_error(ret); - break; + if(system_info->block_count > 0) { + // Read blocks: Optional command + simple_array_init( + data->block_data, system_info->block_count * system_info->block_size); + ret = iso15693_3_poller_read_blocks( + instance, + simple_array_get_data(data->block_data), + system_info->block_count, + system_info->block_size); + if(ret != Iso15693_3ErrorNone) { + ret = iso15693_3_poller_filter_error(ret); + break; + } + + // Get block security status: Optional command + simple_array_init(data->block_security, system_info->block_count); + + ret = iso15693_3_poller_get_blocks_security( + instance, simple_array_get_data(data->block_security), system_info->block_count); + if(ret != Iso15693_3ErrorNone) { + ret = iso15693_3_poller_filter_error(ret); + break; + } } - - // Get block security status: Optional command - simple_array_init(data->block_security, system_info->block_count); - - ret = iso15693_3_poller_get_blocks_security( - instance, simple_array_get_data(data->block_security), system_info->block_count); - if(ret != Iso15693_3ErrorNone) { - ret = iso15693_3_poller_filter_error(ret); - break; - } - } while(false); return ret; From eb6fe0a4dbe2e6d3776483e6a191de2307b0060e Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Sat, 2 Dec 2023 11:34:02 +0400 Subject: [PATCH 39/40] SubGhz: fix count bit for detect gate_tx protocol (#3253) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/subghz/protocols/gate_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index 51a424fed9..2ebd6bb03b 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -227,7 +227,7 @@ void subghz_protocol_decoder_gate_tx_feed(void* context, bool level, uint32_t du if(duration >= ((uint32_t)subghz_protocol_gate_tx_const.te_short * 10 + subghz_protocol_gate_tx_const.te_delta)) { instance->decoder.parser_step = GateTXDecoderStepFoundStartBit; - if(instance->decoder.decode_count_bit >= + if(instance->decoder.decode_count_bit == subghz_protocol_gate_tx_const.min_count_bit_for_found) { instance->generic.data = instance->decoder.decode_data; instance->generic.data_count_bit = instance->decoder.decode_count_bit; From c477d1321af5a25df57d1cbbf709c9853f768f78 Mon Sep 17 00:00:00 2001 From: Honghao Zeng Date: Sun, 3 Dec 2023 20:00:46 +0900 Subject: [PATCH 40/40] nfc: m1k-based Aime (non-AIC) card support (#3241) Co-authored-by: gornekich --- applications/main/nfc/application.fam | 9 + .../main/nfc/plugins/supported_cards/aime.c | 164 ++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 applications/main/nfc/plugins/supported_cards/aime.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 9a98b57c8c..07e97c0c9c 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -74,6 +74,15 @@ App( sources=["plugins/supported_cards/two_cities.c"], ) +App( + appid="aime_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="aime_plugin_ep", + targets=["f7"], + requires=["nfc"], + sources=["plugins/supported_cards/aime.c"], +) + App( appid="nfc_start", targets=["f7"], diff --git a/applications/main/nfc/plugins/supported_cards/aime.c b/applications/main/nfc/plugins/supported_cards/aime.c new file mode 100644 index 0000000000..1db89ffd63 --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/aime.c @@ -0,0 +1,164 @@ +#include "nfc_supported_card_plugin.h" + +#include + +#include +#include +#include + +#define TAG "Aime" + +static const uint64_t aime_key = 0x574343467632; + +bool aime_verify(Nfc* nfc) { + bool verified = false; + + do { + const uint8_t verify_sector = 0; + uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector); + FURI_LOG_D(TAG, "Verifying sector %u", verify_sector); + + MfClassicKey key = {}; + nfc_util_num2bytes(aime_key, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_ctx = {}; + MfClassicError error = + mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx); + + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); + break; + } + + verified = true; + } while(false); + + return verified; +} + +static bool aime_read(Nfc* nfc, NfcDevice* device) { + furi_assert(nfc); + furi_assert(device); + + bool is_read = false; + + MfClassicData* data = mf_classic_alloc(); + nfc_device_copy_data(device, NfcProtocolMfClassic, data); + + do { + MfClassicType type = MfClassicType1k; + MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); + if(error != MfClassicErrorNone) break; + + data->type = type; + MfClassicDeviceKeys keys = {}; + for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { + nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_a[i].data); + FURI_BIT_SET(keys.key_a_mask, i); + nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_b[i].data); + FURI_BIT_SET(keys.key_b_mask, i); + } + + error = mf_classic_poller_sync_read(nfc, &keys, data); + if(error != MfClassicErrorNone) { + FURI_LOG_W(TAG, "Failed to read data"); + break; + } + + nfc_device_set_data(device, NfcProtocolMfClassic, data); + + is_read = true; + } while(false); + + mf_classic_free(data); + + return is_read; +} + +static bool aime_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + bool parsed = false; + + do { + // verify key + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 0); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, 6); + if(key != aime_key) break; + + // Aime Magic is stored at block 1, starts from byte 0, len 4 bytes + const uint8_t* aime_magic = &data->block[1].data[0]; + + // verify aime magic + if(aime_magic[0] != 'S' || aime_magic[1] != 'B' || aime_magic[2] != 'S' || + aime_magic[3] != 'D') + break; + + // Aime checksum is stored at block 1, starts from byte 13, len 3 bytes + // seems like only old games checks this? e.g., old versions of Chunithm + const uint8_t* aime_checksum = &data->block[1].data[13]; + + // Aime access code is stored as decimal hex representation in block 2, starts from byte 6, len 10 bytes + const uint8_t* aime_accesscode = &data->block[2].data[6]; + + char aime_accesscode_str[24 + 1]; + snprintf( + aime_accesscode_str, + sizeof(aime_accesscode_str), + "%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x", + aime_accesscode[0], + aime_accesscode[1], + aime_accesscode[2], + aime_accesscode[3], + aime_accesscode[4], + aime_accesscode[5], + aime_accesscode[6], + aime_accesscode[7], + aime_accesscode[8], + aime_accesscode[9]); + + // validate decimal hex representation + for(int i = 0; i < 24; i++) { + if(aime_accesscode_str[i] == ' ') continue; + if(aime_accesscode_str[i] < '0' || aime_accesscode_str[i] > '9') return false; + } + + // Note: Aime access code has some other self-check algorithms that are not public. + // This parser does not try to verify the number. + + furi_string_printf( + parsed_data, + "\e#Aime Card\nAccess Code: \n%s\nChecksum: %02X%02X%02X\n", + aime_accesscode_str, + aime_checksum[0], + aime_checksum[1], + aime_checksum[2]); + + parsed = true; + + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin aime_plugin = { + .protocol = NfcProtocolMfClassic, + .verify = aime_verify, + .read = aime_read, + .parse = aime_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor aime_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &aime_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* aime_plugin_ep() { + return &aime_plugin_descriptor; +}