diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 81f0e0d050e..9c6c6b2db6f 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -29,12 +29,14 @@ jobs: - name: 'Flash unit tests firmware' id: flashing if: success() + timeout-minutes: 10 run: | ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1 - name: 'Wait for flipper and format ext' id: format_ext if: steps.flashing.outcome == 'success' + timeout-minutes: 5 run: | source scripts/toolchain/fbtenv.sh python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}} @@ -43,6 +45,7 @@ jobs: - name: 'Copy assets and unit data, reboot and wait for flipper' id: copy if: steps.format_ext.outcome == 'success' + timeout-minutes: 5 run: | source scripts/toolchain/fbtenv.sh python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/resources /ext @@ -53,7 +56,7 @@ jobs: - name: 'Run units and validate results' id: run_units if: steps.copy.outcome == 'success' - timeout-minutes: 2.5 + timeout-minutes: 7 run: | source scripts/toolchain/fbtenv.sh python3 scripts/testing/units.py ${{steps.device.outputs.flipper}} diff --git a/.github/workflows/updater_test.yml b/.github/workflows/updater_test.yml index bd837297974..27a181c4612 100644 --- a/.github/workflows/updater_test.yml +++ b/.github/workflows/updater_test.yml @@ -30,6 +30,7 @@ jobs: - name: 'Flashing target firmware' id: first_full_flash + timeout-minutes: 10 run: | source scripts/toolchain/fbtenv.sh ./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1 @@ -37,6 +38,7 @@ jobs: - name: 'Validating updater' id: second_full_flash + timeout-minutes: 10 if: success() run: | source scripts/toolchain/fbtenv.sh diff --git a/CODING_STYLE.md b/CODING_STYLE.md index c62009eff5f..002c67f246a 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -48,7 +48,7 @@ Almost everything in flipper firmware is built around this concept. # C coding style - Tab is 4 spaces -- Use `fbt format` to reformat source code and check style guide before commit +- Use `./fbt format` to reformat source code and check style guide before commit ## Naming diff --git a/applications/ReadMe.md b/applications/ReadMe.md index e50d8e46a5f..10e54ce2257 100644 --- a/applications/ReadMe.md +++ b/applications/ReadMe.md @@ -26,7 +26,6 @@ Applications for main Flipper menu. - `archive` - Archive and file manager - `bad_usb` - Bad USB application -- `fap_loader` - External applications loader - `gpio` - GPIO application: includes USART bridge and GPIO control - `ibutton` - iButton application, onewire keys and more - `infrared` - Infrared application, controls your IR devices diff --git a/applications/debug/application.fam b/applications/debug/application.fam index a33b3693dfe..cdbf8fe18b6 100644 --- a/applications/debug/application.fam +++ b/applications/debug/application.fam @@ -12,5 +12,6 @@ App( "display_test", "text_box_test", "file_browser_test", + "speaker_debug", ], ) diff --git a/applications/debug/crash_test/application.fam b/applications/debug/crash_test/application.fam new file mode 100644 index 00000000000..55f62f86d89 --- /dev/null +++ b/applications/debug/crash_test/application.fam @@ -0,0 +1,10 @@ +App( + appid="crash_test", + 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/crash_test/crash_test.c b/applications/debug/crash_test/crash_test.c new file mode 100644 index 00000000000..92f1668be9f --- /dev/null +++ b/applications/debug/crash_test/crash_test.c @@ -0,0 +1,128 @@ +#include +#include + +#include +#include +#include + +#define TAG "CrashTest" + +typedef struct { + Gui* gui; + ViewDispatcher* view_dispatcher; + Submenu* submenu; +} CrashTest; + +typedef enum { + CrashTestViewSubmenu, +} CrashTestView; + +typedef enum { + CrashTestSubmenuCheck, + CrashTestSubmenuCheckMessage, + CrashTestSubmenuAssert, + CrashTestSubmenuAssertMessage, + CrashTestSubmenuCrash, + CrashTestSubmenuHalt, +} CrashTestSubmenu; + +static void crash_test_submenu_callback(void* context, uint32_t index) { + CrashTest* instance = (CrashTest*)context; + UNUSED(instance); + + switch(index) { + case CrashTestSubmenuCheck: + furi_check(false); + break; + case CrashTestSubmenuCheckMessage: + furi_check(false, "Crash test: furi_check with message"); + break; + case CrashTestSubmenuAssert: + furi_assert(false); + break; + case CrashTestSubmenuAssertMessage: + furi_assert(false, "Crash test: furi_assert with message"); + break; + case CrashTestSubmenuCrash: + furi_crash("Crash test: furi_crash"); + break; + case CrashTestSubmenuHalt: + furi_halt("Crash test: furi_halt"); + break; + default: + furi_crash("Programming error"); + } +} + +static uint32_t crash_test_exit_callback(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +CrashTest* crash_test_alloc() { + CrashTest* instance = malloc(sizeof(CrashTest)); + + View* view = NULL; + + instance->gui = furi_record_open(RECORD_GUI); + instance->view_dispatcher = view_dispatcher_alloc(); + view_dispatcher_enable_queue(instance->view_dispatcher); + view_dispatcher_attach_to_gui( + instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen); + + // Menu + instance->submenu = submenu_alloc(); + view = submenu_get_view(instance->submenu); + view_set_previous_callback(view, crash_test_exit_callback); + view_dispatcher_add_view(instance->view_dispatcher, CrashTestViewSubmenu, view); + submenu_add_item( + instance->submenu, "Check", CrashTestSubmenuCheck, crash_test_submenu_callback, instance); + submenu_add_item( + instance->submenu, + "Check with message", + CrashTestSubmenuCheckMessage, + crash_test_submenu_callback, + instance); + submenu_add_item( + instance->submenu, "Assert", CrashTestSubmenuAssert, crash_test_submenu_callback, instance); + submenu_add_item( + instance->submenu, + "Assert with message", + CrashTestSubmenuAssertMessage, + crash_test_submenu_callback, + instance); + submenu_add_item( + instance->submenu, "Crash", CrashTestSubmenuCrash, crash_test_submenu_callback, instance); + submenu_add_item( + instance->submenu, "Halt", CrashTestSubmenuHalt, crash_test_submenu_callback, instance); + + return instance; +} + +void crash_test_free(CrashTest* instance) { + view_dispatcher_remove_view(instance->view_dispatcher, CrashTestViewSubmenu); + submenu_free(instance->submenu); + + view_dispatcher_free(instance->view_dispatcher); + furi_record_close(RECORD_GUI); + + free(instance); +} + +int32_t crash_test_run(CrashTest* instance) { + view_dispatcher_switch_to_view(instance->view_dispatcher, CrashTestViewSubmenu); + view_dispatcher_run(instance->view_dispatcher); + return 0; +} + +int32_t crash_test_app(void* p) { + UNUSED(p); + + CrashTest* instance = crash_test_alloc(); + + int32_t ret = crash_test_run(instance); + + crash_test_free(instance); + + return ret; +} diff --git a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c index 74c53ae6d48..ac2e2b80611 100644 --- a/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c +++ b/applications/debug/lfrfid_debug/scenes/lfrfid_debug_app_scene_tune.c @@ -6,6 +6,11 @@ static void comparator_trigger_callback(bool level, void* comp_ctx) { furi_hal_gpio_write(&gpio_ext_pa7, !level); } +void lfrfid_debug_view_tune_callback(void* context) { + LfRfidDebug* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, 0xBA); +} + void lfrfid_debug_scene_tune_on_enter(void* context) { LfRfidDebug* app = context; @@ -16,6 +21,8 @@ void lfrfid_debug_scene_tune_on_enter(void* context) { furi_hal_rfid_tim_read_start(125000, 0.5); + lfrfid_debug_view_tune_set_callback(app->tune_view, lfrfid_debug_view_tune_callback, app); + view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewTune); } diff --git a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c index fd221c4e9d3..9e48a7e27fe 100644 --- a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c +++ b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c @@ -13,6 +13,8 @@ typedef struct { uint32_t ARR; uint32_t CCR; int pos; + void (*update_callback)(void* context); + void* update_context; } LfRfidTuneViewModel; static void lfrfid_debug_view_tune_draw_callback(Canvas* canvas, void* _model) { @@ -151,6 +153,18 @@ static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* conte consumed = false; break; } + + if(event->key == InputKeyLeft || event->key == InputKeyRight) { + with_view_model( + tune_view->view, + LfRfidTuneViewModel * model, + { + if(model->update_callback) { + model->update_callback(model->update_context); + } + }, + false); + } } return consumed; @@ -161,19 +175,7 @@ LfRfidTuneView* lfrfid_debug_view_tune_alloc() { tune_view->view = view_alloc(); view_set_context(tune_view->view, tune_view); view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel)); - - with_view_model( - tune_view->view, - LfRfidTuneViewModel * model, - { - model->dirty = true; - model->fine = false; - model->ARR = 511; - model->CCR = 255; - model->pos = 0; - }, - true); - + lfrfid_debug_view_tune_clean(tune_view); view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback); view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback); @@ -199,6 +201,8 @@ void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) { model->ARR = 511; model->CCR = 255; model->pos = 0; + model->update_callback = NULL; + model->update_context = NULL; }, true); } @@ -232,3 +236,17 @@ uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) { return result; } + +void lfrfid_debug_view_tune_set_callback( + LfRfidTuneView* tune_view, + void (*callback)(void* context), + void* context) { + with_view_model( + tune_view->view, + LfRfidTuneViewModel * model, + { + model->update_callback = callback; + model->update_context = context; + }, + false); +} diff --git a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h index fd6d0b1fe9a..be54b63f9a8 100644 --- a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h +++ b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.h @@ -16,3 +16,8 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view); uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view); uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view); + +void lfrfid_debug_view_tune_set_callback( + LfRfidTuneView* tune_view, + void (*callback)(void* context), + void* context); diff --git a/applications/debug/speaker_debug/application.fam b/applications/debug/speaker_debug/application.fam new file mode 100644 index 00000000000..68d8b188bdd --- /dev/null +++ b/applications/debug/speaker_debug/application.fam @@ -0,0 +1,11 @@ +App( + appid="speaker_debug", + name="Speaker Debug", + apptype=FlipperAppType.DEBUG, + entry_point="speaker_debug_app", + requires=["gui", "notification"], + stack_size=2 * 1024, + order=10, + fap_category="Debug", + fap_libs=["music_worker"], +) diff --git a/applications/debug/speaker_debug/speaker_debug.c b/applications/debug/speaker_debug/speaker_debug.c new file mode 100644 index 00000000000..e01d5b8ec44 --- /dev/null +++ b/applications/debug/speaker_debug/speaker_debug.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + +#define TAG "SpeakerDebug" +#define CLI_COMMAND "speaker_debug" + +typedef enum { + SpeakerDebugAppMessageTypeStop, +} SpeakerDebugAppMessageType; + +typedef struct { + SpeakerDebugAppMessageType type; +} SpeakerDebugAppMessage; + +typedef struct { + MusicWorker* music_worker; + FuriMessageQueue* message_queue; + Cli* cli; +} SpeakerDebugApp; + +static SpeakerDebugApp* speaker_app_alloc() { + SpeakerDebugApp* app = (SpeakerDebugApp*)malloc(sizeof(SpeakerDebugApp)); + app->music_worker = music_worker_alloc(); + app->message_queue = furi_message_queue_alloc(8, sizeof(SpeakerDebugAppMessage)); + app->cli = furi_record_open(RECORD_CLI); + return app; +} + +static void speaker_app_free(SpeakerDebugApp* app) { + music_worker_free(app->music_worker); + furi_message_queue_free(app->message_queue); + furi_record_close(RECORD_CLI); + free(app); +} + +static void speaker_app_cli(Cli* cli, FuriString* args, void* context) { + UNUSED(cli); + + SpeakerDebugApp* app = (SpeakerDebugApp*)context; + SpeakerDebugAppMessage message; + FuriString* cmd = furi_string_alloc(); + + if(!args_read_string_and_trim(args, cmd)) { + furi_string_free(cmd); + printf("Usage:\r\n"); + printf("\t" CLI_COMMAND " stop\r\n"); + return; + } + + if(furi_string_cmp(cmd, "stop") == 0) { + message.type = SpeakerDebugAppMessageTypeStop; + FuriStatus status = furi_message_queue_put(app->message_queue, &message, 100); + if(status != FuriStatusOk) { + printf("Failed to send message\r\n"); + } else { + printf("Stopping\r\n"); + } + } else { + printf("Usage:\r\n"); + printf("\t" CLI_COMMAND " stop\r\n"); + } + + furi_string_free(cmd); +} + +static bool speaker_app_music_play(SpeakerDebugApp* app, const char* rtttl) { + if(music_worker_is_playing(app->music_worker)) { + music_worker_stop(app->music_worker); + } + + if(!music_worker_load_rtttl_from_string(app->music_worker, rtttl)) { + FURI_LOG_E(TAG, "Failed to load RTTTL"); + return false; + } + + music_worker_set_volume(app->music_worker, 1.0f); + music_worker_start(app->music_worker); + + return true; +} + +static void speaker_app_music_stop(SpeakerDebugApp* app) { + if(music_worker_is_playing(app->music_worker)) { + music_worker_stop(app->music_worker); + } +} + +static void speaker_app_run(SpeakerDebugApp* app, const char* arg) { + if(!arg || !speaker_app_music_play(app, arg)) { + FURI_LOG_E(TAG, "Provided RTTTL is invalid"); + return; + } + + cli_add_command(app->cli, CLI_COMMAND, CliCommandFlagParallelSafe, speaker_app_cli, app); + + SpeakerDebugAppMessage message; + FuriStatus status; + while(true) { + status = furi_message_queue_get(app->message_queue, &message, FuriWaitForever); + + if(status == FuriStatusOk) { + if(message.type == SpeakerDebugAppMessageTypeStop) { + speaker_app_music_stop(app); + break; + } + } + } + + cli_delete_command(app->cli, CLI_COMMAND); +} + +int32_t speaker_debug_app(void* arg) { + SpeakerDebugApp* app = speaker_app_alloc(); + speaker_app_run(app, arg); + speaker_app_free(app); + return 0; +} diff --git a/applications/debug/uart_echo/uart_echo.c b/applications/debug/uart_echo/uart_echo.c index dc132752921..4bede9ab45f 100644 --- a/applications/debug/uart_echo/uart_echo.c +++ b/applications/debug/uart_echo/uart_echo.c @@ -10,6 +10,8 @@ #define LINES_ON_SCREEN 6 #define COLUMNS_ON_SCREEN 21 +#define TAG "UartEcho" +#define DEFAULT_BAUD_RATE 230400 typedef struct UartDumpModel UartDumpModel; @@ -179,7 +181,7 @@ static int32_t uart_echo_worker(void* context) { return 0; } -static UartEchoApp* uart_echo_app_alloc() { +static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) { UartEchoApp* app = malloc(sizeof(UartEchoApp)); app->rx_stream = furi_stream_buffer_alloc(2048, 1); @@ -220,7 +222,7 @@ static UartEchoApp* uart_echo_app_alloc() { // Enable uart listener furi_hal_console_disable(); - furi_hal_uart_set_br(FuriHalUartIdUSART1, 115200); + furi_hal_uart_set_br(FuriHalUartIdUSART1, baudrate); furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_echo_on_irq_cb, app); return app; @@ -263,8 +265,18 @@ static void uart_echo_app_free(UartEchoApp* app) { } int32_t uart_echo_app(void* p) { - UNUSED(p); - UartEchoApp* app = uart_echo_app_alloc(); + uint32_t baudrate = DEFAULT_BAUD_RATE; + if(p) { + const char* baudrate_str = p; + if(sscanf(baudrate_str, "%lu", &baudrate) != 1) { + FURI_LOG_E(TAG, "Invalid baudrate: %s", baudrate_str); + baudrate = DEFAULT_BAUD_RATE; + } + } + + FURI_LOG_I(TAG, "Using baudrate: %lu", baudrate); + + UartEchoApp* app = uart_echo_app_alloc(baudrate); view_dispatcher_run(app->view_dispatcher); uart_echo_app_free(app); return 0; diff --git a/applications/debug/unit_tests/dialogs/dialogs_file_browser_options.c b/applications/debug/unit_tests/dialogs/dialogs_file_browser_options.c new file mode 100644 index 00000000000..2d5bad4c8a5 --- /dev/null +++ b/applications/debug/unit_tests/dialogs/dialogs_file_browser_options.c @@ -0,0 +1,32 @@ +#include + +#include "../minunit.h" + +MU_TEST(test_dialog_file_browser_set_basic_options_should_init_all_fields) { + mu_assert( + sizeof(DialogsFileBrowserOptions) == 28, + "Changes to `DialogsFileBrowserOptions` should also be reflected in `dialog_file_browser_set_basic_options`"); + + DialogsFileBrowserOptions options; + dialog_file_browser_set_basic_options(&options, ".fap", NULL); + // note: this assertions can safely be changed, their primary purpose is to remind the maintainer + // to update `dialog_file_browser_set_basic_options` by including all structure fields in it + mu_assert_string_eq(".fap", options.extension); + mu_assert_null(options.base_path); + mu_assert(options.skip_assets, "`skip_assets` should default to `true"); + mu_assert(options.hide_dot_files, "`hide_dot_files` should default to `true"); + mu_assert_null(options.icon); + mu_assert(options.hide_ext, "`hide_ext` should default to `true"); + mu_assert_null(options.item_loader_callback); + mu_assert_null(options.item_loader_context); +} + +MU_TEST_SUITE(dialogs_file_browser_options) { + MU_RUN_TEST(test_dialog_file_browser_set_basic_options_should_init_all_fields); +} + +int run_minunit_test_dialogs_file_browser_options() { + MU_RUN_SUITE(dialogs_file_browser_options); + + return MU_EXIT_CODE; +} diff --git a/applications/debug/unit_tests/nfc/nfc_test.c b/applications/debug/unit_tests/nfc/nfc_test.c index a027ea958f5..0cb0898986b 100644 --- a/applications/debug/unit_tests/nfc/nfc_test.c +++ b/applications/debug/unit_tests/nfc/nfc_test.c @@ -17,6 +17,12 @@ #define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_device_test.nfc") +// Maximum allowed time for buffer preparation to fit 500us nt message timeout +#define NFC_TEST_4_BYTE_BUILD_BUFFER_TIM_MAX (150) +#define NFC_TEST_16_BYTE_BUILD_BUFFER_TIM_MAX (640) +#define NFC_TEST_4_BYTE_BUILD_SIGNAL_TIM_MAX (110) +#define NFC_TEST_16_BYTE_BUILD_SIGNAL_TIM_MAX (440) + typedef struct { Storage* storage; } NfcTest; diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index f1ab926538f..6bdaa641e8d 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #define TAG "SubGhz TEST" #define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes") @@ -49,12 +51,15 @@ static void subghz_test_init(void) { subghz_environment_set_protocol_registry( environment_handler, (void*)&subghz_protocol_registry); + subghz_devices_init(); + receiver_handler = subghz_receiver_alloc_init(environment_handler); subghz_receiver_set_filter(receiver_handler, SubGhzProtocolFlag_Decodable); subghz_receiver_set_rx_callback(receiver_handler, subghz_test_rx_callback, NULL); } static void subghz_test_deinit(void) { + subghz_devices_deinit(); subghz_receiver_free(receiver_handler); subghz_environment_free(environment_handler); } @@ -68,7 +73,7 @@ static bool subghz_decoder_test(const char* path, const char* name_decoder) { if(decoder) { file_worker_encoder_handler = subghz_file_encoder_worker_alloc(); - if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path)) { + if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) { // the worker needs a file in order to open and read part of the file furi_delay_ms(100); @@ -108,7 +113,7 @@ static bool subghz_decode_random_test(const char* path) { uint32_t test_start = furi_get_tick(); file_worker_encoder_handler = subghz_file_encoder_worker_alloc(); - if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path)) { + if(subghz_file_encoder_worker_start(file_worker_encoder_handler, path, NULL)) { // the worker needs a file in order to open and read part of the file furi_delay_ms(100); @@ -318,7 +323,7 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) { SubGhzHalAsyncTxTest test = {0}; test.type = type; furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); furi_hal_subghz_set_frequency_and_path(433920000); if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) { diff --git a/applications/debug/unit_tests/test_index.c b/applications/debug/unit_tests/test_index.c index ac71ca397ee..9d7631bfee3 100644 --- a/applications/debug/unit_tests/test_index.c +++ b/applications/debug/unit_tests/test_index.c @@ -27,6 +27,7 @@ int run_minunit_test_nfc(); int run_minunit_test_bit_lib(); int run_minunit_test_float_tools(); int run_minunit_test_bt(); +int run_minunit_test_dialogs_file_browser_options(); typedef int (*UnitTestEntry)(); @@ -55,6 +56,8 @@ const UnitTest unit_tests[] = { {.name = "bit_lib", .entry = run_minunit_test_bit_lib}, {.name = "float_tools", .entry = run_minunit_test_float_tools}, {.name = "bt", .entry = run_minunit_test_bt}, + {.name = "dialogs_file_browser_options", + .entry = run_minunit_test_dialogs_file_browser_options}, }; void minunit_print_progress() { diff --git a/applications/drivers/application.fam b/applications/drivers/application.fam new file mode 100644 index 00000000000..dc70e630c9f --- /dev/null +++ b/applications/drivers/application.fam @@ -0,0 +1,6 @@ +# Placeholder +App( + appid="drivers", + name="Drivers device", + apptype=FlipperAppType.METAPACKAGE, +) diff --git a/applications/drivers/subghz/application.fam b/applications/drivers/subghz/application.fam new file mode 100644 index 00000000000..aaf0e1bd94d --- /dev/null +++ b/applications/drivers/subghz/application.fam @@ -0,0 +1,8 @@ +App( + appid="radio_device_cc1101_ext", + apptype=FlipperAppType.PLUGIN, + targets=["f7"], + entry_point="subghz_device_cc1101_ext_ep", + requires=["subghz"], + fap_libs=["hwdrivers"], +) diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c new file mode 100644 index 00000000000..896b9bd2f60 --- /dev/null +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.c @@ -0,0 +1,765 @@ +#include "cc1101_ext.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define TAG "SubGhz_Device_CC1101_Ext" + +#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO &gpio_ext_pb2 + +/* DMA Channels definition */ +#define SUBGHZ_DEVICE_CC1101_EXT_DMA DMA2 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL LL_DMA_CHANNEL_3 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL LL_DMA_CHANNEL_4 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL LL_DMA_CHANNEL_5 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ FuriHalInterruptIdDma2Ch3 +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \ + SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \ + SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL +#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF \ + SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL + +/** Low level buffer dimensions and guard times */ +#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL (256) +#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF \ + (SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL / 2) +#define SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME 999 + +/** SubGhz state */ +typedef enum { + SubGhzDeviceCC1101ExtStateInit, /**< Init pending */ + SubGhzDeviceCC1101ExtStateIdle, /**< Idle, energy save mode */ + SubGhzDeviceCC1101ExtStateAsyncRx, /**< Async RX started */ + SubGhzDeviceCC1101ExtStateAsyncTx, /**< Async TX started, DMA and timer is on */ + SubGhzDeviceCC1101ExtStateAsyncTxEnd, /**< Async TX complete, cleanup needed */ +} SubGhzDeviceCC1101ExtState; + +/** SubGhz regulation, receive transmission on the current frequency for the + * region */ +typedef enum { + SubGhzDeviceCC1101ExtRegulationOnlyRx, /**only Rx*/ + SubGhzDeviceCC1101ExtRegulationTxRx, /**TxRx*/ +} SubGhzDeviceCC1101ExtRegulation; + +typedef struct { + uint32_t* buffer; + LevelDuration carry_ld; + SubGhzDeviceCC1101ExtCallback callback; + void* callback_context; + uint32_t gpio_tx_buff[2]; + uint32_t debug_gpio_buff[2]; +} SubGhzDeviceCC1101ExtAsyncTx; + +typedef struct { + uint32_t capture_delta_duration; + SubGhzDeviceCC1101ExtCaptureCallback capture_callback; + void* capture_callback_context; +} SubGhzDeviceCC1101ExtAsyncRx; + +typedef struct { + volatile SubGhzDeviceCC1101ExtState state; + volatile SubGhzDeviceCC1101ExtRegulation regulation; + const GpioPin* async_mirror_pin; + FuriHalSpiBusHandle* spi_bus_handle; + const GpioPin* g0_pin; + SubGhzDeviceCC1101ExtAsyncTx async_tx; + SubGhzDeviceCC1101ExtAsyncRx async_rx; +} SubGhzDeviceCC1101Ext; + +static SubGhzDeviceCC1101Ext* subghz_device_cc1101_ext = NULL; + +static bool subghz_device_cc1101_ext_check_init() { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateInit); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; + + bool ret = false; + + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(100 * 1000); + do { + // Reset + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + + // Prepare GD0 for power on self test + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + + // GD0 low + cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHW); + while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != false) { + if(furi_hal_cortex_timer_is_expired(timer)) { + //timeout + break; + } + } + if(furi_hal_cortex_timer_is_expired(timer)) { + //timeout + break; + } + + // GD0 high + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, + CC1101_IOCFG0, + CC1101IocfgHW | CC1101_IOCFG_INV); + while(furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin) != true) { + if(furi_hal_cortex_timer_is_expired(timer)) { + //timeout + break; + } + } + if(furi_hal_cortex_timer_is_expired(timer)) { + //timeout + break; + } + + // Reset GD0 to floating state + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + // RF switches + furi_hal_gpio_init(&gpio_rf_sw_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG2, CC1101IocfgHW); + + // Go to sleep + cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle); + ret = true; + } while(false); + + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + + if(ret) { + FURI_LOG_I(TAG, "Init OK"); + } else { + FURI_LOG_E(TAG, "Init failed"); + } + return ret; +} + +bool subghz_device_cc1101_ext_alloc() { + furi_assert(subghz_device_cc1101_ext == NULL); + subghz_device_cc1101_ext = malloc(sizeof(SubGhzDeviceCC1101Ext)); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateInit; + subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx; + subghz_device_cc1101_ext->async_mirror_pin = NULL; + subghz_device_cc1101_ext->spi_bus_handle = &furi_hal_spi_bus_handle_external; + subghz_device_cc1101_ext->g0_pin = SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO; + + subghz_device_cc1101_ext->async_rx.capture_delta_duration = 0; + + furi_hal_spi_bus_handle_init(subghz_device_cc1101_ext->spi_bus_handle); + return subghz_device_cc1101_ext_check_init(); +} + +void subghz_device_cc1101_ext_free() { + furi_assert(subghz_device_cc1101_ext != NULL); + furi_hal_spi_bus_handle_deinit(subghz_device_cc1101_ext->spi_bus_handle); + free(subghz_device_cc1101_ext); + subghz_device_cc1101_ext = NULL; +} + +void subghz_device_cc1101_ext_set_async_mirror_pin(const GpioPin* pin) { + subghz_device_cc1101_ext->async_mirror_pin = pin; +} + +const GpioPin* subghz_device_cc1101_ext_get_data_gpio() { + return subghz_device_cc1101_ext->g0_pin; +} + +bool subghz_device_cc1101_ext_is_connect() { + bool ret = false; + + if(subghz_device_cc1101_ext == NULL) { // not initialized + ret = subghz_device_cc1101_ext_alloc(); + subghz_device_cc1101_ext_free(); + } else { // initialized + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + uint8_t partnumber = cc1101_get_partnumber(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + ret = (partnumber != 0) && (partnumber != 0xFF); + } + + return ret; +} + +void subghz_device_cc1101_ext_sleep() { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle); + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + + cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle); + + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle); + + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_dump_state() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + printf( + "[subghz_device_cc1101_ext] cc1101 chip %d, version %d\r\n", + cc1101_get_partnumber(subghz_device_cc1101_ext->spi_bus_handle), + cc1101_get_version(subghz_device_cc1101_ext->spi_bus_handle)); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data) { + //load config + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); + uint32_t i = 0; + uint8_t pa[8] = {0}; + while(preset_data[i]) { + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, preset_data[i], preset_data[i + 1]); + i += 2; + } + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + + //load pa table + memcpy(&pa[0], &preset_data[i + 2], 8); + subghz_device_cc1101_ext_load_patable(pa); + + //show debug + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + i = 0; + FURI_LOG_D(TAG, "Loading custom preset"); + while(preset_data[i]) { + FURI_LOG_D(TAG, "Reg[%lu]: %02X=%02X", i, preset_data[i], preset_data[i + 1]); + i += 2; + } + for(uint8_t y = i; y < i + 10; y++) { + FURI_LOG_D(TAG, "PA[%u]: %02X", y, preset_data[y]); + } + } +} + +void subghz_device_cc1101_ext_load_registers(const uint8_t* data) { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); + uint32_t i = 0; + while(data[i]) { + cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, data[i], data[i + 1]); + i += 2; + } + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_load_patable(const uint8_t data[8]) { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_set_pa_table(subghz_device_cc1101_ext->spi_bus_handle, data); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_write_packet(const uint8_t* data, uint8_t size) { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_flush_tx(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_write_reg(subghz_device_cc1101_ext->spi_bus_handle, CC1101_FIFO, size); + cc1101_write_fifo(subghz_device_cc1101_ext->spi_bus_handle, data, size); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_flush_rx() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_flush_rx(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_flush_tx() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_flush_tx(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +bool subghz_device_cc1101_ext_rx_pipe_not_empty() { + CC1101RxBytes status[1]; + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_read_reg( + subghz_device_cc1101_ext->spi_bus_handle, + (CC1101_STATUS_RXBYTES) | CC1101_BURST, + (uint8_t*)status); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + // TODO: you can add a buffer overflow flag if needed + if(status->NUM_RXBYTES > 0) { + return true; + } else { + return false; + } +} + +bool subghz_device_cc1101_ext_is_rx_data_crc_valid() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + uint8_t data[1]; + cc1101_read_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + if(((data[0] >> 7) & 0x01)) { + return true; + } else { + return false; + } +} + +void subghz_device_cc1101_ext_read_packet(uint8_t* data, uint8_t* size) { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_read_fifo(subghz_device_cc1101_ext->spi_bus_handle, data, size); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_shutdown() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + // Reset and shutdown + cc1101_shutdown(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_reset() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_reset(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_write_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_IOCFG0, CC1101IocfgHighImpedance); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_idle() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_switch_to_idle(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +void subghz_device_cc1101_ext_rx() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_switch_to_rx(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); +} + +bool subghz_device_cc1101_ext_tx() { + if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false; + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + cc1101_switch_to_tx(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + return true; +} + +float subghz_device_cc1101_ext_get_rssi() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + int32_t rssi_dec = cc1101_get_rssi(subghz_device_cc1101_ext->spi_bus_handle); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + + float rssi = rssi_dec; + if(rssi_dec >= 128) { + rssi = ((rssi - 256.0f) / 2.0f) - 74.0f; + } else { + rssi = (rssi / 2.0f) - 74.0f; + } + + return rssi; +} + +uint8_t subghz_device_cc1101_ext_get_lqi() { + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + uint8_t data[1]; + cc1101_read_reg( + subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data); + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + return data[0] & 0x7F; +} + +bool subghz_device_cc1101_ext_is_frequency_valid(uint32_t value) { + if(!(value >= 299999755 && value <= 348000335) && + !(value >= 386999938 && value <= 464000000) && + !(value >= 778999847 && value <= 928000000)) { + return false; + } + + return true; +} + +uint32_t subghz_device_cc1101_ext_set_frequency(uint32_t value) { + if(furi_hal_region_is_frequency_allowed(value)) { + subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationTxRx; + } else { + subghz_device_cc1101_ext->regulation = SubGhzDeviceCC1101ExtRegulationOnlyRx; + } + + furi_hal_spi_acquire(subghz_device_cc1101_ext->spi_bus_handle); + uint32_t real_frequency = + cc1101_set_frequency(subghz_device_cc1101_ext->spi_bus_handle, value); + cc1101_calibrate(subghz_device_cc1101_ext->spi_bus_handle); + + while(true) { + CC1101Status status = cc1101_get_status(subghz_device_cc1101_ext->spi_bus_handle); + if(status.STATE == CC1101StateIDLE) break; + } + + furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); + return real_frequency; +} + +static bool subghz_device_cc1101_ext_start_debug() { + bool ret = false; + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) { + furi_hal_gpio_init( + subghz_device_cc1101_ext->async_mirror_pin, + GpioModeOutputPushPull, + GpioPullNo, + GpioSpeedVeryHigh); + ret = true; + } + return ret; +} + +static bool subghz_device_cc1101_ext_stop_debug() { + bool ret = false; + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) { + furi_hal_gpio_init( + subghz_device_cc1101_ext->async_mirror_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + ret = true; + } + return ret; +} + +static void subghz_device_cc1101_ext_capture_ISR() { + if(!furi_hal_gpio_read(subghz_device_cc1101_ext->g0_pin)) { + if(subghz_device_cc1101_ext->async_rx.capture_callback) { + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) + furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false); + + subghz_device_cc1101_ext->async_rx.capture_callback( + true, + LL_TIM_GetCounter(TIM17), + (void*)subghz_device_cc1101_ext->async_rx.capture_callback_context); + } + } else { + if(subghz_device_cc1101_ext->async_rx.capture_callback) { + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) + furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, true); + + subghz_device_cc1101_ext->async_rx.capture_callback( + false, + LL_TIM_GetCounter(TIM17), + (void*)subghz_device_cc1101_ext->async_rx.capture_callback_context); + } + } + LL_TIM_SetCounter(TIM17, 6); +} + +void subghz_device_cc1101_ext_start_async_rx( + SubGhzDeviceCC1101ExtCaptureCallback callback, + void* context) { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncRx; + + subghz_device_cc1101_ext->async_rx.capture_callback = callback; + subghz_device_cc1101_ext->async_rx.capture_callback_context = context; + + furi_hal_bus_enable(FuriHalBusTIM17); + + // Configure TIM + LL_TIM_SetPrescaler(TIM17, 64 - 1); + LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetAutoReload(TIM17, 0xFFFF); + LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1); + + // Timer: advanced + LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(TIM17); + LL_TIM_DisableDMAReq_TRIG(TIM17); + LL_TIM_DisableIT_TRIG(TIM17); + + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeInterruptRiseFall, GpioPullUp, GpioSpeedVeryHigh); + furi_hal_gpio_remove_int_callback(subghz_device_cc1101_ext->g0_pin); + furi_hal_gpio_add_int_callback( + subghz_device_cc1101_ext->g0_pin, + subghz_device_cc1101_ext_capture_ISR, + subghz_device_cc1101_ext->async_rx.capture_callback); + + // Start timer + LL_TIM_SetCounter(TIM17, 0); + LL_TIM_EnableCounter(TIM17); + + // Start debug + subghz_device_cc1101_ext_start_debug(); + + // Switch to RX + subghz_device_cc1101_ext_rx(); + + //Clear the variable after the end of the session + subghz_device_cc1101_ext->async_rx.capture_delta_duration = 0; +} + +void subghz_device_cc1101_ext_stop_async_rx() { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncRx); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; + + // Shutdown radio + subghz_device_cc1101_ext_idle(); + + FURI_CRITICAL_ENTER(); + furi_hal_bus_disable(FuriHalBusTIM17); + + // Stop debug + subghz_device_cc1101_ext_stop_debug(); + + FURI_CRITICAL_EXIT(); + furi_hal_gpio_remove_int_callback(subghz_device_cc1101_ext->g0_pin); + furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); +} + +static void subghz_device_cc1101_ext_async_tx_refill(uint32_t* buffer, size_t samples) { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx); + while(samples > 0) { + bool is_odd = samples % 2; + LevelDuration ld; + if(level_duration_is_reset(subghz_device_cc1101_ext->async_tx.carry_ld)) { + ld = subghz_device_cc1101_ext->async_tx.callback( + subghz_device_cc1101_ext->async_tx.callback_context); + } else { + ld = subghz_device_cc1101_ext->async_tx.carry_ld; + subghz_device_cc1101_ext->async_tx.carry_ld = level_duration_reset(); + } + + if(level_duration_is_wait(ld)) { + *buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME; + buffer++; + samples--; + } else if(level_duration_is_reset(ld)) { + *buffer = 0; + buffer++; + samples--; + LL_DMA_DisableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_DMA_DisableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_TIM_EnableIT_UPDATE(TIM17); + break; + } else { + bool level = level_duration_get_level(ld); + + // Inject guard time if level is incorrect + if(is_odd != level) { + *buffer = SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_GUARD_TIME; + buffer++; + samples--; + + // Special case: prevent buffer overflow if sample is last + if(samples == 0) { + subghz_device_cc1101_ext->async_tx.carry_ld = ld; + break; + } + } + + uint32_t duration = level_duration_get_duration(ld); + furi_assert(duration > 0); + *buffer = duration - 1; + buffer++; + samples--; + } + } +} + +static void subghz_device_cc1101_ext_async_tx_dma_isr() { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx); + +#if SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL == LL_DMA_CHANNEL_3 + if(LL_DMA_IsActiveFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) { + LL_DMA_ClearFlag_HT3(SUBGHZ_DEVICE_CC1101_EXT_DMA); + subghz_device_cc1101_ext_async_tx_refill( + subghz_device_cc1101_ext->async_tx.buffer, + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF); + } + if(LL_DMA_IsActiveFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA)) { + LL_DMA_ClearFlag_TC3(SUBGHZ_DEVICE_CC1101_EXT_DMA); + subghz_device_cc1101_ext_async_tx_refill( + subghz_device_cc1101_ext->async_tx.buffer + + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF, + SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_HALF); + } +#else +#error Update this code. Would you kindly? +#endif +} + +static void subghz_device_cc1101_ext_async_tx_timer_isr() { + if(LL_TIM_IsActiveFlag_UPDATE(TIM17)) { + if(LL_TIM_GetAutoReload(TIM17) == 0) { + LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); + if(subghz_device_cc1101_ext->async_mirror_pin != NULL) + furi_hal_gpio_write(subghz_device_cc1101_ext->async_mirror_pin, false); + LL_TIM_DisableCounter(TIM17); + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTxEnd; + } + LL_TIM_ClearFlag_UPDATE(TIM17); + } +} + +bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context) { + furi_assert(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateIdle); + furi_assert(callback); + + //If transmission is prohibited by regional settings + if(subghz_device_cc1101_ext->regulation != SubGhzDeviceCC1101ExtRegulationTxRx) return false; + + subghz_device_cc1101_ext->async_tx.callback = callback; + subghz_device_cc1101_ext->async_tx.callback_context = context; + + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateAsyncTx; + + subghz_device_cc1101_ext->async_tx.buffer = + malloc(SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL * sizeof(uint32_t)); + + //Signal generation with mem-to-mem DMA + furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); + furi_hal_gpio_init( + subghz_device_cc1101_ext->g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + + // Configure DMA update timer + LL_DMA_SetMemoryAddress( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t)subghz_device_cc1101_ext->async_tx.buffer); + LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, (uint32_t) & (TIM17->ARR)); + LL_DMA_ConfigTransfer( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_MODE_NORMAL); + LL_DMA_SetDataLength( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL); + LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF, LL_DMAMUX_REQ_TIM17_UP); + + LL_DMA_EnableIT_TC(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_DMA_EnableIT_HT(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + + furi_hal_interrupt_set_isr( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, subghz_device_cc1101_ext_async_tx_dma_isr, NULL); + + furi_hal_bus_enable(FuriHalBusTIM17); + + // Configure TIM + LL_TIM_SetPrescaler(TIM17, 64 - 1); + LL_TIM_SetCounterMode(TIM17, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetAutoReload(TIM17, 0xFFFF); + LL_TIM_SetClockDivision(TIM17, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockSource(TIM17, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(TIM17); + + furi_hal_interrupt_set_isr( + FuriHalInterruptIdTim1TrgComTim17, subghz_device_cc1101_ext_async_tx_timer_isr, NULL); + + subghz_device_cc1101_ext_async_tx_refill( + subghz_device_cc1101_ext->async_tx.buffer, SUBGHZ_DEVICE_CC1101_EXT_ASYNC_TX_BUFFER_FULL); + + // Configure tx gpio dma + const GpioPin* gpio = subghz_device_cc1101_ext->g0_pin; + + subghz_device_cc1101_ext->async_tx.gpio_tx_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; + subghz_device_cc1101_ext->async_tx.gpio_tx_buff[1] = gpio->pin; + + LL_DMA_SetMemoryAddress( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, + (uint32_t)subghz_device_cc1101_ext->async_tx.gpio_tx_buff); + LL_DMA_SetPeriphAddress(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, (uint32_t) & (gpio->port->BSRR)); + LL_DMA_ConfigTransfer( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_PRIORITY_HIGH); + LL_DMA_SetDataLength(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, 2); + LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF, LL_DMAMUX_REQ_TIM17_UP); + LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF); + + // Start debug + if(subghz_device_cc1101_ext_start_debug()) { + gpio = subghz_device_cc1101_ext->async_mirror_pin; + subghz_device_cc1101_ext->async_tx.debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER; + subghz_device_cc1101_ext->async_tx.debug_gpio_buff[1] = gpio->pin; + + LL_DMA_SetMemoryAddress( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, + (uint32_t)subghz_device_cc1101_ext->async_tx.debug_gpio_buff); + LL_DMA_SetPeriphAddress( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, (uint32_t) & (gpio->port->BSRR)); + LL_DMA_ConfigTransfer( + SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_PRIORITY_LOW); + LL_DMA_SetDataLength(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, 2); + LL_DMA_SetPeriphRequest(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF, LL_DMAMUX_REQ_TIM17_UP); + LL_DMA_EnableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF); + } + + // Start counter + LL_TIM_EnableDMAReq_UPDATE(TIM17); + LL_TIM_GenerateEvent_UPDATE(TIM17); + + subghz_device_cc1101_ext_tx(); + + LL_TIM_SetCounter(TIM17, 0); + LL_TIM_EnableCounter(TIM17); + + return true; +} + +bool subghz_device_cc1101_ext_is_async_tx_complete() { + return subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd; +} + +void subghz_device_cc1101_ext_stop_async_tx() { + furi_assert( + subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx || + subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTxEnd); + + // Shutdown radio + subghz_device_cc1101_ext_idle(); + + // Deinitialize Timer + FURI_CRITICAL_ENTER(); + furi_hal_bus_disable(FuriHalBusTIM17); + furi_hal_interrupt_set_isr(FuriHalInterruptIdTim1TrgComTim17, NULL, NULL); + + // Deinitialize DMA + LL_DMA_DeInit(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF); + LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF); + furi_hal_interrupt_set_isr(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ, NULL, NULL); + + // Deinitialize GPIO + furi_hal_gpio_write(subghz_device_cc1101_ext->g0_pin, false); + furi_hal_gpio_init(subghz_device_cc1101_ext->g0_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + + // Stop debug + if(subghz_device_cc1101_ext_stop_debug()) { + LL_DMA_DisableChannel(SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_DEF); + } + + FURI_CRITICAL_EXIT(); + + free(subghz_device_cc1101_ext->async_tx.buffer); + + subghz_device_cc1101_ext->state = SubGhzDeviceCC1101ExtStateIdle; +} diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext.h b/applications/drivers/subghz/cc1101_ext/cc1101_ext.h new file mode 100644 index 00000000000..d972fcb6618 --- /dev/null +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext.h @@ -0,0 +1,206 @@ +/** + * @file furi_hal_subghz.h + * SubGhz HAL API + */ + +#pragma once +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Mirror RX/TX async modulation signal to specified pin + * + * @warning Configures pin to output mode. Make sure it is not connected + * directly to power or ground. + * + * @param[in] pin pointer to the gpio pin structure or NULL to disable + */ +void subghz_device_cc1101_ext_set_async_mirror_pin(const GpioPin* pin); + +/** Get data GPIO + * + * @return pointer to the gpio pin structure + */ +const GpioPin* subghz_device_cc1101_ext_get_data_gpio(); + +/** Initialize device + * + * @return true if success + */ +bool subghz_device_cc1101_ext_alloc(); + +/** Deinitialize device + */ +void subghz_device_cc1101_ext_free(); + +/** Check and switch to power save mode Used by internal API-HAL + * initialization routine Can be used to reinitialize device to safe state and + * send it to sleep + */ +bool subghz_device_cc1101_ext_is_connect(); + +/** Send device to sleep mode + */ +void subghz_device_cc1101_ext_sleep(); + +/** Dump info to stdout + */ +void subghz_device_cc1101_ext_dump_state(); + +/** Load custom registers from preset + * + * @param preset_data registers to load + */ +void subghz_device_cc1101_ext_load_custom_preset(const uint8_t* preset_data); + +/** Load registers + * + * @param data Registers data + */ +void subghz_device_cc1101_ext_load_registers(const uint8_t* data); + +/** Load PATABLE + * + * @param data 8 uint8_t values + */ +void subghz_device_cc1101_ext_load_patable(const uint8_t data[8]); + +/** Write packet to FIFO + * + * @param data bytes array + * @param size size + */ +void subghz_device_cc1101_ext_write_packet(const uint8_t* data, uint8_t size); + +/** Check if receive pipe is not empty + * + * @return true if not empty + */ +bool subghz_device_cc1101_ext_rx_pipe_not_empty(); + +/** Check if received data crc is valid + * + * @return true if valid + */ +bool subghz_device_cc1101_ext_is_rx_data_crc_valid(); + +/** Read packet from FIFO + * + * @param data pointer + * @param size size + */ +void subghz_device_cc1101_ext_read_packet(uint8_t* data, uint8_t* size); + +/** Flush rx FIFO buffer + */ +void subghz_device_cc1101_ext_flush_rx(); + +/** Flush tx FIFO buffer + */ +void subghz_device_cc1101_ext_flush_tx(); + +/** Shutdown Issue SPWD command + * @warning registers content will be lost + */ +void subghz_device_cc1101_ext_shutdown(); + +/** Reset Issue reset command + * @warning registers content will be lost + */ +void subghz_device_cc1101_ext_reset(); + +/** Switch to Idle + */ +void subghz_device_cc1101_ext_idle(); + +/** Switch to Receive + */ +void subghz_device_cc1101_ext_rx(); + +/** Switch to Transmit + * + * @return true if the transfer is allowed by belonging to the region + */ +bool subghz_device_cc1101_ext_tx(); + +/** Get RSSI value in dBm + * + * @return RSSI value + */ +float subghz_device_cc1101_ext_get_rssi(); + +/** Get LQI + * + * @return LQI value + */ +uint8_t subghz_device_cc1101_ext_get_lqi(); + +/** Check if frequency is in valid range + * + * @param value frequency in Hz + * + * @return true if frequency is valid, otherwise false + */ +bool subghz_device_cc1101_ext_is_frequency_valid(uint32_t value); + +/** Set frequency + * + * @param value frequency in Hz + * + * @return real frequency in Hz + */ +uint32_t subghz_device_cc1101_ext_set_frequency(uint32_t value); + +/* High Level API */ + +/** Signal Timings Capture callback */ +typedef void (*SubGhzDeviceCC1101ExtCaptureCallback)(bool level, uint32_t duration, void* context); + +/** Enable signal timings capture Initializes GPIO and TIM2 for timings capture + * + * @param callback SubGhzDeviceCC1101ExtCaptureCallback + * @param context callback context + */ +void subghz_device_cc1101_ext_start_async_rx( + SubGhzDeviceCC1101ExtCaptureCallback callback, + void* context); + +/** Disable signal timings capture Resets GPIO and TIM2 + */ +void subghz_device_cc1101_ext_stop_async_rx(); + +/** Async TX callback type + * @param context callback context + * @return LevelDuration + */ +typedef LevelDuration (*SubGhzDeviceCC1101ExtCallback)(void* context); + +/** Start async TX Initializes GPIO, TIM2 and DMA1 for signal output + * + * @param callback SubGhzDeviceCC1101ExtCallback + * @param context callback context + * + * @return true if the transfer is allowed by belonging to the region + */ +bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callback, void* context); + +/** Wait for async transmission to complete + * + * @return true if TX complete + */ +bool subghz_device_cc1101_ext_is_async_tx_complete(); + +/** Stop async transmission and cleanup resources Resets GPIO, TIM2, and DMA1 + */ +void subghz_device_cc1101_ext_stop_async_tx(); + +#ifdef __cplusplus +} +#endif diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c new file mode 100644 index 00000000000..51f5a0d1ddb --- /dev/null +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.c @@ -0,0 +1,110 @@ +#include "cc1101_ext_interconnect.h" +#include "cc1101_ext.h" +#include + +#define TAG "SubGhzDeviceCC1101Ext" + +static bool subghz_device_cc1101_ext_interconnect_is_frequency_valid(uint32_t frequency) { + bool ret = subghz_device_cc1101_ext_is_frequency_valid(frequency); + if(!ret) { + furi_crash("SubGhz: Incorrect frequency."); + } + return ret; +} + +static uint32_t subghz_device_cc1101_ext_interconnect_set_frequency(uint32_t frequency) { + subghz_device_cc1101_ext_interconnect_is_frequency_valid(frequency); + return subghz_device_cc1101_ext_set_frequency(frequency); +} + +static bool subghz_device_cc1101_ext_interconnect_start_async_tx(void* callback, void* context) { + return subghz_device_cc1101_ext_start_async_tx( + (SubGhzDeviceCC1101ExtCallback)callback, context); +} + +static void subghz_device_cc1101_ext_interconnect_start_async_rx(void* callback, void* context) { + subghz_device_cc1101_ext_start_async_rx( + (SubGhzDeviceCC1101ExtCaptureCallback)callback, context); +} + +static void subghz_device_cc1101_ext_interconnect_load_preset( + FuriHalSubGhzPreset preset, + uint8_t* preset_data) { + switch(preset) { + case FuriHalSubGhzPresetOok650Async: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_ook_650khz_async_regs); + break; + case FuriHalSubGhzPresetOok270Async: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_ook_270khz_async_regs); + break; + case FuriHalSubGhzPreset2FSKDev238Async: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs); + break; + case FuriHalSubGhzPreset2FSKDev476Async: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs); + break; + case FuriHalSubGhzPresetMSK99_97KbAsync: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_msk_99_97kb_async_regs); + break; + case FuriHalSubGhzPresetGFSK9_99KbAsync: + subghz_device_cc1101_ext_load_custom_preset( + subghz_device_cc1101_preset_gfsk_9_99kb_async_regs); + break; + + default: + subghz_device_cc1101_ext_load_custom_preset(preset_data); + } +} + +const SubGhzDeviceInterconnect subghz_device_cc1101_ext_interconnect = { + .begin = subghz_device_cc1101_ext_alloc, + .end = subghz_device_cc1101_ext_free, + .is_connect = subghz_device_cc1101_ext_is_connect, + .reset = subghz_device_cc1101_ext_reset, + .sleep = subghz_device_cc1101_ext_sleep, + .idle = subghz_device_cc1101_ext_idle, + .load_preset = subghz_device_cc1101_ext_interconnect_load_preset, + .set_frequency = subghz_device_cc1101_ext_interconnect_set_frequency, + .is_frequency_valid = subghz_device_cc1101_ext_is_frequency_valid, + .set_async_mirror_pin = subghz_device_cc1101_ext_set_async_mirror_pin, + .get_data_gpio = subghz_device_cc1101_ext_get_data_gpio, + + .set_tx = subghz_device_cc1101_ext_tx, + .flush_tx = subghz_device_cc1101_ext_flush_tx, + .start_async_tx = subghz_device_cc1101_ext_interconnect_start_async_tx, + .is_async_complete_tx = subghz_device_cc1101_ext_is_async_tx_complete, + .stop_async_tx = subghz_device_cc1101_ext_stop_async_tx, + + .set_rx = subghz_device_cc1101_ext_rx, + .flush_rx = subghz_device_cc1101_ext_flush_rx, + .start_async_rx = subghz_device_cc1101_ext_interconnect_start_async_rx, + .stop_async_rx = subghz_device_cc1101_ext_stop_async_rx, + + .get_rssi = subghz_device_cc1101_ext_get_rssi, + .get_lqi = subghz_device_cc1101_ext_get_lqi, + + .rx_pipe_not_empty = subghz_device_cc1101_ext_rx_pipe_not_empty, + .is_rx_data_crc_valid = subghz_device_cc1101_ext_is_rx_data_crc_valid, + .read_packet = subghz_device_cc1101_ext_read_packet, + .write_packet = subghz_device_cc1101_ext_write_packet, +}; + +const SubGhzDevice subghz_device_cc1101_ext = { + .name = SUBGHZ_DEVICE_CC1101_EXT_NAME, + .interconnect = &subghz_device_cc1101_ext_interconnect, +}; + +static const FlipperAppPluginDescriptor subghz_device_cc1101_ext_descriptor = { + .appid = SUBGHZ_RADIO_DEVICE_PLUGIN_APP_ID, + .ep_api_version = SUBGHZ_RADIO_DEVICE_PLUGIN_API_VERSION, + .entry_point = &subghz_device_cc1101_ext, +}; + +const FlipperAppPluginDescriptor* subghz_device_cc1101_ext_ep() { + return &subghz_device_cc1101_ext_descriptor; +} \ No newline at end of file diff --git a/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h new file mode 100644 index 00000000000..cf1ff3ee07f --- /dev/null +++ b/applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h @@ -0,0 +1,8 @@ +#pragma once +#include + +#define SUBGHZ_DEVICE_CC1101_EXT_NAME "cc1101_ext" + +typedef struct SubGhzDeviceCC1101Ext SubGhzDeviceCC1101Ext; + +const FlipperAppPluginDescriptor* subghz_device_cc1101_ext_ep(); diff --git a/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c index 0ee5cefa1de..b4c12cbc38a 100644 --- a/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c +++ b/applications/external/avr_isp_programmer/helpers/avr_isp_worker_rw.c @@ -60,7 +60,9 @@ static int32_t avr_isp_worker_rw_thread(void* context) { AvrIspWorkerRW* instance = context; /* start PWM on &gpio_ext_pa4 */ - furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50); + if(!furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4)) { + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50); + } FURI_LOG_D(TAG, "Start"); @@ -122,7 +124,9 @@ static int32_t avr_isp_worker_rw_thread(void* context) { } FURI_LOG_D(TAG, "Stop"); - furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); + if(furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4)) { + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); + } return 0; } @@ -136,7 +140,12 @@ bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance) { instance->chip_arr_ind = avr_isp_chip_arr_size + 1; /* start PWM on &gpio_ext_pa4 */ - furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50); + bool was_pwm_enabled = false; + if(!furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4)) { + furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50); + } else { + was_pwm_enabled = true; + } do { if(!avr_isp_auto_set_spi_speed_start_pmode(instance->avr_isp)) { @@ -200,7 +209,9 @@ bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance) { } while(0); - furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); + if(furi_hal_pwm_is_running(FuriHalPwmOutputIdLptim2PA4) && !was_pwm_enabled) { + furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4); + } if(instance->callback) { if(instance->chip_arr_ind > avr_isp_chip_arr_size) { diff --git a/applications/external/hid_app/assets/Space_60x18.png b/applications/external/hid_app/assets/Space_60x18.png new file mode 100644 index 00000000000..e29f50ae922 Binary files /dev/null and b/applications/external/hid_app/assets/Space_60x18.png differ diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index ea408c39287..a969a933a12 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -7,6 +7,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexKeynote, + HidSubmenuIndexKeynoteVertical, HidSubmenuIndexKeyboard, HidSubmenuIndexMedia, HidSubmenuIndexTikTok, @@ -20,6 +21,11 @@ static void hid_submenu_callback(void* context, uint32_t index) { Hid* app = context; if(index == HidSubmenuIndexKeynote) { app->view_id = HidViewKeynote; + hid_keynote_set_orientation(app->hid_keynote, false); + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynote); + } else if(index == HidSubmenuIndexKeynoteVertical) { + app->view_id = HidViewKeynote; + hid_keynote_set_orientation(app->hid_keynote, true); view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynote); } else if(index == HidSubmenuIndexKeyboard) { app->view_id = HidViewKeyboard; @@ -105,6 +111,12 @@ Hid* hid_alloc(HidTransport transport) { app->device_type_submenu = submenu_alloc(); submenu_add_item( app->device_type_submenu, "Keynote", HidSubmenuIndexKeynote, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, + "Keynote Vertical", + HidSubmenuIndexKeynoteVertical, + hid_submenu_callback, + app); submenu_add_item( app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); submenu_add_item( diff --git a/applications/external/hid_app/views/hid_keynote.c b/applications/external/hid_app/views/hid_keynote.c index 5e5eeb79094..543363bf67b 100644 --- a/applications/external/hid_app/views/hid_keynote.c +++ b/applications/external/hid_app/views/hid_keynote.c @@ -111,6 +111,91 @@ static void hid_keynote_draw_callback(Canvas* canvas, void* context) { elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back"); } +static void hid_keynote_draw_vertical_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidKeynoteModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 20, 3, AlignLeft, AlignTop, "Keynote"); + } else { + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 12, 3, AlignLeft, AlignTop, "Keynote"); + } + + canvas_draw_icon(canvas, 2, 18, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 15, 19, AlignLeft, AlignTop, "Hold to exit"); + + const uint8_t x_2 = 23; + const uint8_t x_1 = 2; + const uint8_t x_3 = 44; + + const uint8_t y_1 = 44; + const uint8_t y_2 = 65; + + // Up + canvas_draw_icon(canvas, x_2, y_1, &I_Button_18x18); + if(model->up_pressed) { + elements_slightly_rounded_box(canvas, x_2 + 3, y_1 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_draw_arrow(canvas, x_2 + 9, y_1 + 6, CanvasDirectionBottomToTop); + canvas_set_color(canvas, ColorBlack); + + // Down + canvas_draw_icon(canvas, x_2, y_2, &I_Button_18x18); + if(model->down_pressed) { + elements_slightly_rounded_box(canvas, x_2 + 3, y_2 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_draw_arrow(canvas, x_2 + 9, y_2 + 10, CanvasDirectionTopToBottom); + canvas_set_color(canvas, ColorBlack); + + // Left + canvas_draw_icon(canvas, x_1, y_2, &I_Button_18x18); + if(model->left_pressed) { + elements_slightly_rounded_box(canvas, x_1 + 3, y_2 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_draw_arrow(canvas, x_1 + 7, y_2 + 8, CanvasDirectionRightToLeft); + canvas_set_color(canvas, ColorBlack); + + // Right + canvas_draw_icon(canvas, x_3, y_2, &I_Button_18x18); + if(model->right_pressed) { + elements_slightly_rounded_box(canvas, x_3 + 3, y_2 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_draw_arrow(canvas, x_3 + 11, y_2 + 8, CanvasDirectionLeftToRight); + canvas_set_color(canvas, ColorBlack); + + // Ok + canvas_draw_icon(canvas, 2, 86, &I_Space_60x18); + if(model->ok_pressed) { + elements_slightly_rounded_box(canvas, 5, 88, 55, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 11, 90, &I_Ok_btn_9x9); + elements_multiline_text_aligned(canvas, 26, 98, AlignLeft, AlignBottom, "Space"); + canvas_set_color(canvas, ColorBlack); + + // Back + canvas_draw_icon(canvas, 2, 107, &I_Space_60x18); + if(model->back_pressed) { + elements_slightly_rounded_box(canvas, 5, 109, 55, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 11, 111, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 26, 119, AlignLeft, AlignBottom, "Back"); +} + static void hid_keynote_process(HidKeynote* hid_keynote, InputEvent* event) { with_view_model( hid_keynote->view, @@ -212,3 +297,16 @@ void hid_keynote_set_connected_status(HidKeynote* hid_keynote, bool connected) { with_view_model( hid_keynote->view, HidKeynoteModel * model, { model->connected = connected; }, true); } + +void hid_keynote_set_orientation(HidKeynote* hid_keynote, bool vertical) { + furi_assert(hid_keynote); + + if(vertical) { + view_set_draw_callback(hid_keynote->view, hid_keynote_draw_vertical_callback); + view_set_orientation(hid_keynote->view, ViewOrientationVerticalFlip); + + } else { + view_set_draw_callback(hid_keynote->view, hid_keynote_draw_callback); + view_set_orientation(hid_keynote->view, ViewOrientationHorizontal); + } +} diff --git a/applications/external/hid_app/views/hid_keynote.h b/applications/external/hid_app/views/hid_keynote.h index 4d4a0a9b1a0..84bfed4ce41 100644 --- a/applications/external/hid_app/views/hid_keynote.h +++ b/applications/external/hid_app/views/hid_keynote.h @@ -12,3 +12,5 @@ void hid_keynote_free(HidKeynote* hid_keynote); View* hid_keynote_get_view(HidKeynote* hid_keynote); void hid_keynote_set_connected_status(HidKeynote* hid_keynote, bool connected); + +void hid_keynote_set_orientation(HidKeynote* hid_keynote, bool vertical); diff --git a/applications/external/mfkey32/mfkey32.c b/applications/external/mfkey32/mfkey32.c index 3f114227741..5e790b01f6e 100644 --- a/applications/external/mfkey32/mfkey32.c +++ b/applications/external/mfkey32/mfkey32.c @@ -161,7 +161,7 @@ static const uint8_t lookup2[256] = { 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6, 2, 2, 6, 6, 2, 6, 2, 2, 2, 6, 2, 2, 6, 6, 6, 6}; -uint32_t old_prng_successor(uint32_t x, uint32_t n) { +uint32_t prng_successor(uint32_t x, uint32_t n) { SWAPENDIAN(x); while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; return SWAPENDIAN(x); @@ -945,7 +945,7 @@ MfClassicNonceArray* napi_mf_classic_nonce_array_alloc( next_line_cstr = endptr; } (program_state->total)++; - uint32_t p64b = old_prng_successor(res.nt1, 64); + uint32_t p64b = prng_successor(res.nt1, 64); if((system_dict_exists && napi_key_already_found_for_nonce( system_dict, res.uid ^ res.nt1, res.nr1_enc, p64b, res.ar1_enc)) || @@ -1051,8 +1051,8 @@ void mfkey32(ProgramState* program_state) { // TODO: Work backwards on this array and free memory for(i = 0; i < nonce_arr->total_nonces; i++) { MfClassicNonce next_nonce = nonce_arr->remaining_nonce_array[i]; - uint32_t p64 = old_prng_successor(next_nonce.nt0, 64); - uint32_t p64b = old_prng_successor(next_nonce.nt1, 64); + uint32_t p64 = prng_successor(next_nonce.nt0, 64); + uint32_t p64b = prng_successor(next_nonce.nt1, 64); if(key_already_found_for_nonce( keyarray, keyarray_size, diff --git a/applications/external/music_player/application.fam b/applications/external/music_player/application.fam index 3414c0a482d..c9cd5e44de7 100644 --- a/applications/external/music_player/application.fam +++ b/applications/external/music_player/application.fam @@ -7,18 +7,10 @@ App( "gui", "dialogs", ], - provides=["music_player_start"], stack_size=2 * 1024, order=20, fap_icon="icons/music_10px.png", fap_category="Media", fap_icon_assets="icons", -) - -App( - appid="music_player_start", - apptype=FlipperAppType.STARTUP, - entry_point="music_player_on_system_start", - requires=["music_player"], - order=30, + fap_libs=["music_worker"], ) diff --git a/applications/external/music_player/music_player.c b/applications/external/music_player/music_player.c index 2380d7d17be..8b0b758c1c1 100644 --- a/applications/external/music_player/music_player.c +++ b/applications/external/music_player/music_player.c @@ -1,4 +1,4 @@ -#include "music_player_worker.h" +#include #include #include @@ -34,7 +34,7 @@ typedef struct { ViewPort* view_port; Gui* gui; - MusicPlayerWorker* worker; + MusicWorker* worker; } MusicPlayer; static const float MUSIC_PLAYER_VOLUMES[] = {0, .25, .5, .75, 1}; @@ -218,7 +218,7 @@ static void input_callback(InputEvent* input_event, void* ctx) { } } -static void music_player_worker_callback( +static void music_worker_callback( uint8_t semitone, uint8_t dots, uint8_t duration, @@ -250,7 +250,7 @@ static void music_player_worker_callback( void music_player_clear(MusicPlayer* instance) { memset(instance->model->duration_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); memset(instance->model->semitone_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); - music_player_worker_clear(instance->worker); + music_worker_clear(instance->worker); } MusicPlayer* music_player_alloc() { @@ -263,10 +263,9 @@ MusicPlayer* music_player_alloc() { instance->input_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - instance->worker = music_player_worker_alloc(); - music_player_worker_set_volume( - instance->worker, MUSIC_PLAYER_VOLUMES[instance->model->volume]); - music_player_worker_set_callback(instance->worker, music_player_worker_callback, instance); + instance->worker = music_worker_alloc(); + music_worker_set_volume(instance->worker, MUSIC_PLAYER_VOLUMES[instance->model->volume]); + music_worker_set_callback(instance->worker, music_worker_callback, instance); music_player_clear(instance); @@ -286,7 +285,7 @@ void music_player_free(MusicPlayer* instance) { furi_record_close(RECORD_GUI); view_port_free(instance->view_port); - music_player_worker_free(instance->worker); + music_worker_free(instance->worker); furi_message_queue_free(instance->input_queue); @@ -330,12 +329,12 @@ int32_t music_player_app(void* p) { } } - if(!music_player_worker_load(music_player->worker, furi_string_get_cstr(file_path))) { + if(!music_worker_load(music_player->worker, furi_string_get_cstr(file_path))) { FURI_LOG_E(TAG, "Unable to load file"); break; } - music_player_worker_start(music_player->worker); + music_worker_start(music_player->worker); InputEvent input; while(furi_message_queue_get(music_player->input_queue, &input, FuriWaitForever) == @@ -349,11 +348,11 @@ int32_t music_player_app(void* p) { } else if(input.key == InputKeyUp) { if(music_player->model->volume < COUNT_OF(MUSIC_PLAYER_VOLUMES) - 1) music_player->model->volume++; - music_player_worker_set_volume( + music_worker_set_volume( music_player->worker, MUSIC_PLAYER_VOLUMES[music_player->model->volume]); } else if(input.key == InputKeyDown) { if(music_player->model->volume > 0) music_player->model->volume--; - music_player_worker_set_volume( + music_worker_set_volume( music_player->worker, MUSIC_PLAYER_VOLUMES[music_player->model->volume]); } @@ -361,7 +360,7 @@ int32_t music_player_app(void* p) { view_port_update(music_player->view_port); } - music_player_worker_stop(music_player->worker); + music_worker_stop(music_player->worker); if(p && strlen(p)) break; // Exit instead of going to browser if launched with arg music_player_clear(music_player); } while(1); diff --git a/applications/external/music_player/music_player_cli.c b/applications/external/music_player/music_player_cli.c deleted file mode 100644 index 90060d7ee00..00000000000 --- a/applications/external/music_player/music_player_cli.c +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include "music_player_worker.h" - -static void music_player_cli(Cli* cli, FuriString* args, void* context) { - UNUSED(context); - MusicPlayerWorker* music_player_worker = music_player_worker_alloc(); - Storage* storage = furi_record_open(RECORD_STORAGE); - - do { - if(storage_common_stat(storage, furi_string_get_cstr(args), NULL) == FSE_OK) { - if(!music_player_worker_load(music_player_worker, furi_string_get_cstr(args))) { - printf("Failed to open file %s\r\n", furi_string_get_cstr(args)); - break; - } - } else { - if(!music_player_worker_load_rtttl_from_string( - music_player_worker, furi_string_get_cstr(args))) { - printf("Argument is not a file or RTTTL\r\n"); - break; - } - } - - printf("Press CTRL+C to stop\r\n"); - music_player_worker_set_volume(music_player_worker, 1.0f); - music_player_worker_start(music_player_worker); - while(!cli_cmd_interrupt_received(cli)) { - furi_delay_ms(50); - } - music_player_worker_stop(music_player_worker); - } while(0); - - furi_record_close(RECORD_STORAGE); - music_player_worker_free(music_player_worker); -} - -void music_player_on_system_start() { -#ifdef SRV_CLI - Cli* cli = furi_record_open(RECORD_CLI); - - cli_add_command(cli, "music_player", CliCommandFlagDefault, music_player_cli, NULL); - - furi_record_close(RECORD_CLI); -#else - UNUSED(music_player_cli); -#endif -} diff --git a/applications/external/music_player/music_player_worker.h b/applications/external/music_player/music_player_worker.h deleted file mode 100644 index 00320b11fe5..00000000000 --- a/applications/external/music_player/music_player_worker.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include - -typedef void (*MusicPlayerWorkerCallback)( - uint8_t semitone, - uint8_t dots, - uint8_t duration, - float position, - void* context); - -typedef struct MusicPlayerWorker MusicPlayerWorker; - -MusicPlayerWorker* music_player_worker_alloc(); - -void music_player_worker_clear(MusicPlayerWorker* instance); - -void music_player_worker_free(MusicPlayerWorker* instance); - -bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string); - -void music_player_worker_set_callback( - MusicPlayerWorker* instance, - MusicPlayerWorkerCallback callback, - void* context); - -void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume); - -void music_player_worker_start(MusicPlayerWorker* instance); - -void music_player_worker_stop(MusicPlayerWorker* instance); diff --git a/applications/external/nfc_magic/lib/magic/magic.h b/applications/external/nfc_magic/lib/magic/magic.h deleted file mode 100644 index 15e793d894c..00000000000 --- a/applications/external/nfc_magic/lib/magic/magic.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -bool magic_wupa(); - -bool magic_read_block(uint8_t block_num, MfClassicBlock* data); - -bool magic_data_access_cmd(); - -bool magic_write_blk(uint8_t block_num, MfClassicBlock* data); - -bool magic_wipe(); - -void magic_deactivate(); diff --git a/applications/external/nfc_magic/nfc_magic_i.h b/applications/external/nfc_magic/nfc_magic_i.h index 4d6b89103d4..88bc5706fa8 100644 --- a/applications/external/nfc_magic/nfc_magic_i.h +++ b/applications/external/nfc_magic/nfc_magic_i.h @@ -46,6 +46,7 @@ enum NfcMagicCustomEvent { struct NfcMagicDevice { MagicType type; uint32_t cuid; + uint8_t uid_len; uint32_t password; }; diff --git a/applications/external/nfc_magic/nfc_magic_worker.c b/applications/external/nfc_magic/nfc_magic_worker.c index 9ee7fd3eecd..eb715fe0dda 100644 --- a/applications/external/nfc_magic/nfc_magic_worker.c +++ b/applications/external/nfc_magic/nfc_magic_worker.c @@ -107,14 +107,7 @@ void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) { } magic_activate(); if(magic_gen1_wupa()) { - if(!magic_gen1_data_access_cmd()) { - FURI_LOG_E( - TAG, "No card response to data access command (not a magic card)"); - nfc_magic_worker->callback( - NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); - done = true; - break; - } + magic_gen1_data_access_cmd(); MfClassicData* mfc_data = &dev_data->mf_classic_data; for(size_t i = 0; i < 64; i++) { @@ -296,6 +289,7 @@ void nfc_magic_worker_write(NfcMagicWorker* nfc_magic_worker) { } void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { + FuriHalNfcDevData nfc_data = {}; NfcMagicDevice* magic_dev = nfc_magic_worker->magic_dev; bool card_found_notified = false; uint8_t gen4_config[MAGIC_GEN4_CONFIG_LEN]; @@ -310,32 +304,44 @@ void nfc_magic_worker_check(NfcMagicWorker* nfc_magic_worker) { card_found_notified = true; } - furi_hal_nfc_activate_nfca(200, &magic_dev->cuid); - nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); - break; - } - - magic_deactivate(); - furi_delay_ms(300); - magic_activate(); - - furi_hal_nfc_activate_nfca(200, &magic_dev->cuid); - if(magic_gen4_get_cfg(magic_dev->password, gen4_config)) { - magic_dev->type = MagicTypeGen4; - if(!card_found_notified) { - nfc_magic_worker->callback( - NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); - card_found_notified = true; + if(furi_hal_nfc_detect(&nfc_data, 200)) { + magic_dev->cuid = nfc_data.cuid; + magic_dev->uid_len = nfc_data.uid_len; + } else { + // wrong BCC + magic_dev->uid_len = 4; } - nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context); break; - } + } else { + magic_deactivate(); + magic_activate(); + if(furi_hal_nfc_detect(&nfc_data, 200)) { + magic_dev->cuid = nfc_data.cuid; + magic_dev->uid_len = nfc_data.uid_len; + if(magic_gen4_get_cfg(magic_dev->password, gen4_config)) { + magic_dev->type = MagicTypeGen4; + if(!card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventCardDetected, nfc_magic_worker->context); + card_found_notified = true; + } - if(card_found_notified) { - nfc_magic_worker->callback( - NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); - card_found_notified = false; + nfc_magic_worker->callback( + NfcMagicWorkerEventSuccess, nfc_magic_worker->context); + } else { + nfc_magic_worker->callback( + NfcMagicWorkerEventWrongCard, nfc_magic_worker->context); + card_found_notified = true; + } + break; + } else { + if(card_found_notified) { + nfc_magic_worker->callback( + NfcMagicWorkerEventNoCardDetected, nfc_magic_worker->context); + card_found_notified = false; + } + } } magic_deactivate(); diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c index a7d1703d137..04b7024ffbd 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_file_select.c @@ -1,14 +1,14 @@ #include "../nfc_magic_i.h" static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) { - NfcDevice* nfc_device = nfc_magic->source_dev; - if(nfc_device->format == NfcDeviceSaveFormatMifareClassic) { + NfcDevice* nfc_dev = nfc_magic->source_dev; + if(nfc_dev->format == NfcDeviceSaveFormatMifareClassic) { switch(nfc_magic->dev->type) { case MagicTypeClassicGen1: case MagicTypeClassicDirectWrite: case MagicTypeClassicAPDU: - if((nfc_device->dev_data.mf_classic_data.type != MfClassicType1k) || - (nfc_device->dev_data.nfc_data.uid_len != 4)) { + if((nfc_dev->dev_data.mf_classic_data.type != MfClassicType1k) || + (nfc_dev->dev_data.nfc_data.uid_len != nfc_magic->dev->uid_len)) { return false; } return true; @@ -19,15 +19,15 @@ static bool nfc_magic_scene_file_select_is_file_suitable(NfcMagic* nfc_magic) { return false; } } else if( - (nfc_device->format == NfcDeviceSaveFormatMifareUl) && - (nfc_device->dev_data.nfc_data.uid_len == 7)) { + (nfc_dev->format == NfcDeviceSaveFormatMifareUl) && + (nfc_dev->dev_data.nfc_data.uid_len == 7)) { switch(nfc_magic->dev->type) { case MagicTypeUltralightGen1: case MagicTypeUltralightDirectWrite: case MagicTypeUltralightC_Gen1: case MagicTypeUltralightC_DirectWrite: case MagicTypeGen4: - switch(nfc_device->dev_data.mf_ul_data.type) { + switch(nfc_dev->dev_data.mf_ul_data.type) { case MfUltralightTypeNTAGI2C1K: case MfUltralightTypeNTAGI2C2K: case MfUltralightTypeNTAGI2CPlus1K: diff --git a/applications/external/nfc_magic/scenes/nfc_magic_scene_not_magic.c b/applications/external/nfc_magic/scenes/nfc_magic_scene_not_magic.c index b87f7f383e8..b4f579f444d 100644 --- a/applications/external/nfc_magic/scenes/nfc_magic_scene_not_magic.c +++ b/applications/external/nfc_magic/scenes/nfc_magic_scene_not_magic.c @@ -13,11 +13,10 @@ void nfc_magic_scene_not_magic_on_enter(void* context) { notification_message(nfc_magic->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, "Not a magic\ncard"); + widget, 4, 17, AlignLeft, AlignTop, FontSecondary, "Not magic or unsupported\ncard"); widget_add_button_element( widget, GuiButtonTypeLeft, "Retry", nfc_magic_scene_not_magic_widget_callback, nfc_magic); diff --git a/applications/external/nfc_rfid_detector/application.fam b/applications/external/nfc_rfid_detector/application.fam new file mode 100644 index 00000000000..70c91bc8437 --- /dev/null +++ b/applications/external/nfc_rfid_detector/application.fam @@ -0,0 +1,13 @@ +App( + appid="nfc_rfid_detector", + name="NFC/RFID detector", + apptype=FlipperAppType.EXTERNAL, + targets=["f7"], + entry_point="nfc_rfid_detector_app", + requires=["gui"], + stack_size=4 * 1024, + order=50, + fap_icon="nfc_rfid_detector_10px.png", + fap_category="Tools", + fap_icon_assets="images", +) diff --git a/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_event.h b/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_event.h new file mode 100644 index 00000000000..bbffe2938e4 --- /dev/null +++ b/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_event.h @@ -0,0 +1,7 @@ +#pragma once + +typedef enum { + //NfcRfidDetectorCustomEvent + NfcRfidDetectorCustomEventStartId = 100, + +} NfcRfidDetectorCustomEvent; diff --git a/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_types.h b/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_types.h new file mode 100644 index 00000000000..5d44b09b7f2 --- /dev/null +++ b/applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_types.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#define NFC_RFID_DETECTOR_VERSION_APP "0.1" +#define NFC_RFID_DETECTOR_DEVELOPED "SkorP" +#define NFC_RFID_DETECTOR_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" + +typedef enum { + NfcRfidDetectorViewVariableItemList, + NfcRfidDetectorViewSubmenu, + NfcRfidDetectorViewFieldPresence, + NfcRfidDetectorViewWidget, +} NfcRfidDetectorView; diff --git a/applications/external/nfc_rfid_detector/images/Modern_reader_18x34.png b/applications/external/nfc_rfid_detector/images/Modern_reader_18x34.png new file mode 100644 index 00000000000..b19c0f30c9f Binary files /dev/null and b/applications/external/nfc_rfid_detector/images/Modern_reader_18x34.png differ diff --git a/applications/external/nfc_rfid_detector/images/Move_flipper_26x39.png b/applications/external/nfc_rfid_detector/images/Move_flipper_26x39.png new file mode 100644 index 00000000000..ff4af9ff059 Binary files /dev/null and b/applications/external/nfc_rfid_detector/images/Move_flipper_26x39.png differ diff --git a/applications/external/nfc_rfid_detector/images/NFC_detect_45x30.png b/applications/external/nfc_rfid_detector/images/NFC_detect_45x30.png new file mode 100644 index 00000000000..9d8a6f2abf9 Binary files /dev/null and b/applications/external/nfc_rfid_detector/images/NFC_detect_45x30.png differ diff --git a/applications/external/nfc_rfid_detector/images/Rfid_detect_45x30.png b/applications/external/nfc_rfid_detector/images/Rfid_detect_45x30.png new file mode 100644 index 00000000000..35c205049bc Binary files /dev/null and b/applications/external/nfc_rfid_detector/images/Rfid_detect_45x30.png differ diff --git a/applications/external/nfc_rfid_detector/nfc_rfid_detector_10px.png b/applications/external/nfc_rfid_detector/nfc_rfid_detector_10px.png new file mode 100644 index 00000000000..7e875e028d5 Binary files /dev/null and b/applications/external/nfc_rfid_detector/nfc_rfid_detector_10px.png differ diff --git a/applications/external/nfc_rfid_detector/nfc_rfid_detector_app.c b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app.c new file mode 100644 index 00000000000..cba8b60856a --- /dev/null +++ b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app.c @@ -0,0 +1,108 @@ +#include "nfc_rfid_detector_app_i.h" + +#include +#include + +static bool nfc_rfid_detector_app_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +static bool nfc_rfid_detector_app_back_event_callback(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + return scene_manager_handle_back_event(app->scene_manager); +} + +static void nfc_rfid_detector_app_tick_event_callback(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + scene_manager_handle_tick_event(app->scene_manager); +} + +NfcRfidDetectorApp* nfc_rfid_detector_app_alloc() { + NfcRfidDetectorApp* app = malloc(sizeof(NfcRfidDetectorApp)); + + // GUI + app->gui = furi_record_open(RECORD_GUI); + + // View Dispatcher + app->view_dispatcher = view_dispatcher_alloc(); + app->scene_manager = scene_manager_alloc(&nfc_rfid_detector_scene_handlers, app); + view_dispatcher_enable_queue(app->view_dispatcher); + + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + view_dispatcher_set_custom_event_callback( + app->view_dispatcher, nfc_rfid_detector_app_custom_event_callback); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, nfc_rfid_detector_app_back_event_callback); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, nfc_rfid_detector_app_tick_event_callback, 100); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + // Open Notification record + app->notifications = furi_record_open(RECORD_NOTIFICATION); + + // SubMenu + app->submenu = submenu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, NfcRfidDetectorViewSubmenu, submenu_get_view(app->submenu)); + + // Widget + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, NfcRfidDetectorViewWidget, widget_get_view(app->widget)); + + // Field Presence + app->nfc_rfid_detector_field_presence = nfc_rfid_detector_view_field_presence_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + NfcRfidDetectorViewFieldPresence, + nfc_rfid_detector_view_field_presence_get_view(app->nfc_rfid_detector_field_presence)); + + scene_manager_next_scene(app->scene_manager, NfcRfidDetectorSceneStart); + + return app; +} + +void nfc_rfid_detector_app_free(NfcRfidDetectorApp* app) { + furi_assert(app); + + // Submenu + view_dispatcher_remove_view(app->view_dispatcher, NfcRfidDetectorViewSubmenu); + submenu_free(app->submenu); + + // Widget + view_dispatcher_remove_view(app->view_dispatcher, NfcRfidDetectorViewWidget); + widget_free(app->widget); + + // Field Presence + view_dispatcher_remove_view(app->view_dispatcher, NfcRfidDetectorViewFieldPresence); + nfc_rfid_detector_view_field_presence_free(app->nfc_rfid_detector_field_presence); + + // View dispatcher + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + + // Notifications + furi_record_close(RECORD_NOTIFICATION); + app->notifications = NULL; + + // Close records + furi_record_close(RECORD_GUI); + + free(app); +} + +int32_t nfc_rfid_detector_app(void* p) { + UNUSED(p); + NfcRfidDetectorApp* nfc_rfid_detector_app = nfc_rfid_detector_app_alloc(); + + view_dispatcher_run(nfc_rfid_detector_app->view_dispatcher); + + nfc_rfid_detector_app_free(nfc_rfid_detector_app); + + return 0; +} diff --git a/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.c b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.c new file mode 100644 index 00000000000..c59d40d50c5 --- /dev/null +++ b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.c @@ -0,0 +1,40 @@ +#include "nfc_rfid_detector_app_i.h" + +#include + +#define TAG "NfcRfidDetector" + +void nfc_rfid_detector_app_field_presence_start(NfcRfidDetectorApp* app) { + furi_assert(app); + + // start the field presence rfid detection + furi_hal_rfid_field_detect_start(); + + // start the field presence nfc detection + furi_hal_nfc_exit_sleep(); + furi_hal_nfc_field_detect_start(); +} + +void nfc_rfid_detector_app_field_presence_stop(NfcRfidDetectorApp* app) { + furi_assert(app); + + // stop the field presence rfid detection + furi_hal_rfid_field_detect_stop(); + + // stop the field presence nfc detection + furi_hal_nfc_start_sleep(); +} + +bool nfc_rfid_detector_app_field_presence_is_nfc(NfcRfidDetectorApp* app) { + furi_assert(app); + + // check if the field presence is nfc + return furi_hal_nfc_field_is_present(); +} + +bool nfc_rfid_detector_app_field_presence_is_rfid(NfcRfidDetectorApp* app, uint32_t* frequency) { + furi_assert(app); + + // check if the field presence is rfid + return furi_hal_rfid_field_is_present(frequency); +} \ No newline at end of file diff --git a/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.h b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.h new file mode 100644 index 00000000000..72cb126d4a3 --- /dev/null +++ b/applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.h @@ -0,0 +1,30 @@ +#pragma once + +#include "helpers/nfc_rfid_detector_types.h" +#include "helpers/nfc_rfid_detector_event.h" + +#include "scenes/nfc_rfid_detector_scene.h" +#include +#include +#include +#include +#include +#include +#include "views/nfc_rfid_detector_view_field_presence.h" + +typedef struct NfcRfidDetectorApp NfcRfidDetectorApp; + +struct NfcRfidDetectorApp { + Gui* gui; + ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; + NotificationApp* notifications; + Submenu* submenu; + Widget* widget; + NfcRfidDetectorFieldPresence* nfc_rfid_detector_field_presence; +}; + +void nfc_rfid_detector_app_field_presence_start(NfcRfidDetectorApp* app); +void nfc_rfid_detector_app_field_presence_stop(NfcRfidDetectorApp* app); +bool nfc_rfid_detector_app_field_presence_is_nfc(NfcRfidDetectorApp* app); +bool nfc_rfid_detector_app_field_presence_is_rfid(NfcRfidDetectorApp* app, uint32_t* frequency); \ No newline at end of file diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.c b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.c new file mode 100644 index 00000000000..d75eb2884fe --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.c @@ -0,0 +1,31 @@ +#include "../nfc_rfid_detector_app_i.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const nfc_rfid_detector_scene_on_enter_handlers[])(void*) = { +#include "nfc_rfid_detector_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const nfc_rfid_detector_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = + { +#include "nfc_rfid_detector_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const nfc_rfid_detector_scene_on_exit_handlers[])(void* context) = { +#include "nfc_rfid_detector_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers nfc_rfid_detector_scene_handlers = { + .on_enter_handlers = nfc_rfid_detector_scene_on_enter_handlers, + .on_event_handlers = nfc_rfid_detector_scene_on_event_handlers, + .on_exit_handlers = nfc_rfid_detector_scene_on_exit_handlers, + .scene_num = NfcRfidDetectorSceneNum, +}; diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.h b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.h new file mode 100644 index 00000000000..74d324b4d3b --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) NfcRfidDetectorScene##id, +typedef enum { +#include "nfc_rfid_detector_scene_config.h" + NfcRfidDetectorSceneNum, +} NfcRfidDetectorScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers nfc_rfid_detector_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "nfc_rfid_detector_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "nfc_rfid_detector_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "nfc_rfid_detector_scene_config.h" +#undef ADD_SCENE diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_about.c b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_about.c new file mode 100644 index 00000000000..ddcb8aac0fe --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_about.c @@ -0,0 +1,69 @@ +#include "../nfc_rfid_detector_app_i.h" + +void nfc_rfid_detector_scene_about_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcRfidDetectorApp* app = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void nfc_rfid_detector_scene_about_on_enter(void* context) { + NfcRfidDetectorApp* app = context; + + FuriString* temp_str; + temp_str = furi_string_alloc(); + furi_string_printf(temp_str, "\e#%s\n", "Information"); + + furi_string_cat_printf(temp_str, "Version: %s\n", NFC_RFID_DETECTOR_VERSION_APP); + furi_string_cat_printf(temp_str, "Developed by: %s\n", NFC_RFID_DETECTOR_DEVELOPED); + furi_string_cat_printf(temp_str, "Github: %s\n\n", NFC_RFID_DETECTOR_GITHUB); + + furi_string_cat_printf(temp_str, "\e#%s\n", "Description"); + furi_string_cat_printf( + temp_str, + "This application allows\nyou to determine what\ntype of electromagnetic\nfield the reader is using.\nFor LF RFID you can also\nsee the carrier frequency\n\n"); + + widget_add_text_box_element( + app->widget, + 0, + 0, + 128, + 14, + AlignCenter, + AlignBottom, + "\e#\e! \e!\n", + false); + widget_add_text_box_element( + app->widget, + 0, + 2, + 128, + 14, + AlignCenter, + AlignBottom, + "\e#\e! NFC/RFID detector \e!\n", + false); + widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str)); + furi_string_free(temp_str); + + view_dispatcher_switch_to_view(app->view_dispatcher, NfcRfidDetectorViewWidget); +} + +bool nfc_rfid_detector_scene_about_on_event(void* context, SceneManagerEvent event) { + NfcRfidDetectorApp* app = context; + bool consumed = false; + UNUSED(app); + UNUSED(event); + + return consumed; +} + +void nfc_rfid_detector_scene_about_on_exit(void* context) { + NfcRfidDetectorApp* app = context; + + // Clear views + widget_reset(app->widget); +} diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_config.h b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_config.h new file mode 100644 index 00000000000..ab49ad5c2cf --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_config.h @@ -0,0 +1,3 @@ +ADD_SCENE(nfc_rfid_detector, start, Start) +ADD_SCENE(nfc_rfid_detector, about, About) +ADD_SCENE(nfc_rfid_detector, field_presence, FieldPresence) diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_field_presence.c b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_field_presence.c new file mode 100644 index 00000000000..ec53b5a0a60 --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_field_presence.c @@ -0,0 +1,60 @@ +#include "../nfc_rfid_detector_app_i.h" +#include "../views/nfc_rfid_detector_view_field_presence.h" + +void nfc_rfid_detector_scene_field_presence_callback( + NfcRfidDetectorCustomEvent event, + void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +static const NotificationSequence notification_app_display_on = { + + &message_display_backlight_on, + NULL, +}; + +static void nfc_rfid_detector_scene_field_presence_update(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + + uint32_t frequency = 0; + bool nfc_field = nfc_rfid_detector_app_field_presence_is_nfc(app); + bool rfid_field = nfc_rfid_detector_app_field_presence_is_rfid(app, &frequency); + + if(nfc_field || rfid_field) + notification_message(app->notifications, ¬ification_app_display_on); + + nfc_rfid_detector_view_field_presence_update( + app->nfc_rfid_detector_field_presence, nfc_field, rfid_field, frequency); +} + +void nfc_rfid_detector_scene_field_presence_on_enter(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + + // Start detection of field presence + nfc_rfid_detector_app_field_presence_start(app); + + view_dispatcher_switch_to_view(app->view_dispatcher, NfcRfidDetectorViewFieldPresence); +} + +bool nfc_rfid_detector_scene_field_presence_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeTick) { + nfc_rfid_detector_scene_field_presence_update(app); + } + + return consumed; +} + +void nfc_rfid_detector_scene_field_presence_on_exit(void* context) { + furi_assert(context); + NfcRfidDetectorApp* app = context; + // Stop detection of field presence + nfc_rfid_detector_app_field_presence_stop(app); +} diff --git a/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_start.c b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_start.c new file mode 100644 index 00000000000..7b71bd97351 --- /dev/null +++ b/applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_start.c @@ -0,0 +1,58 @@ +#include "../nfc_rfid_detector_app_i.h" + +typedef enum { + SubmenuIndexNfcRfidDetectorFieldPresence, + SubmenuIndexNfcRfidDetectorAbout, +} SubmenuIndex; + +void nfc_rfid_detector_scene_start_submenu_callback(void* context, uint32_t index) { + NfcRfidDetectorApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void nfc_rfid_detector_scene_start_on_enter(void* context) { + UNUSED(context); + NfcRfidDetectorApp* app = context; + Submenu* submenu = app->submenu; + + submenu_add_item( + submenu, + "Detect field type", + SubmenuIndexNfcRfidDetectorFieldPresence, + nfc_rfid_detector_scene_start_submenu_callback, + app); + submenu_add_item( + submenu, + "About", + SubmenuIndexNfcRfidDetectorAbout, + nfc_rfid_detector_scene_start_submenu_callback, + app); + + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, NfcRfidDetectorSceneStart)); + + view_dispatcher_switch_to_view(app->view_dispatcher, NfcRfidDetectorViewSubmenu); +} + +bool nfc_rfid_detector_scene_start_on_event(void* context, SceneManagerEvent event) { + NfcRfidDetectorApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubmenuIndexNfcRfidDetectorAbout) { + scene_manager_next_scene(app->scene_manager, NfcRfidDetectorSceneAbout); + consumed = true; + } else if(event.event == SubmenuIndexNfcRfidDetectorFieldPresence) { + scene_manager_next_scene(app->scene_manager, NfcRfidDetectorSceneFieldPresence); + consumed = true; + } + scene_manager_set_scene_state(app->scene_manager, NfcRfidDetectorSceneStart, event.event); + } + + return consumed; +} + +void nfc_rfid_detector_scene_start_on_exit(void* context) { + NfcRfidDetectorApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.c b/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.c new file mode 100644 index 00000000000..e65eb8362b4 --- /dev/null +++ b/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.c @@ -0,0 +1,164 @@ +#include "nfc_rfid_detector_view_field_presence.h" +#include "../nfc_rfid_detector_app_i.h" +#include + +#include +#include + +#define FIELD_FOUND_WEIGHT 5 + +typedef enum { + NfcRfidDetectorTypeFieldPresenceNfc, + NfcRfidDetectorTypeFieldPresenceRfid, +} NfcRfidDetectorTypeFieldPresence; + +static const Icon* NfcRfidDetectorFieldPresenceIcons[] = { + [NfcRfidDetectorTypeFieldPresenceNfc] = &I_NFC_detect_45x30, + [NfcRfidDetectorTypeFieldPresenceRfid] = &I_Rfid_detect_45x30, +}; + +struct NfcRfidDetectorFieldPresence { + View* view; +}; + +typedef struct { + uint8_t nfc_field; + uint8_t rfid_field; + uint32_t rfid_frequency; +} NfcRfidDetectorFieldPresenceModel; + +void nfc_rfid_detector_view_field_presence_update( + NfcRfidDetectorFieldPresence* instance, + bool nfc_field, + bool rfid_field, + uint32_t rfid_frequency) { + furi_assert(instance); + with_view_model( + instance->view, + NfcRfidDetectorFieldPresenceModel * model, + { + if(nfc_field) { + model->nfc_field = FIELD_FOUND_WEIGHT; + } else if(model->nfc_field) { + model->nfc_field--; + } + if(rfid_field) { + model->rfid_field = FIELD_FOUND_WEIGHT; + model->rfid_frequency = rfid_frequency; + } else if(model->rfid_field) { + model->rfid_field--; + } + }, + true); +} + +void nfc_rfid_detector_view_field_presence_draw( + Canvas* canvas, + NfcRfidDetectorFieldPresenceModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + if(!model->nfc_field && !model->rfid_field) { + canvas_draw_icon(canvas, 0, 16, &I_Modern_reader_18x34); + canvas_draw_icon(canvas, 22, 12, &I_Move_flipper_26x39); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 56, 36, "Touch the reader"); + } else { + if(model->nfc_field) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 21, 10, "NFC"); + canvas_draw_icon( + canvas, + 9, + 17, + NfcRfidDetectorFieldPresenceIcons[NfcRfidDetectorTypeFieldPresenceNfc]); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 9, 62, "13,56 MHz"); + } + + if(model->rfid_field) { + char str[16]; + snprintf(str, sizeof(str), "%.02f KHz", (double)model->rfid_frequency / 1000); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 76, 10, "LF RFID"); + canvas_draw_icon( + canvas, + 71, + 17, + NfcRfidDetectorFieldPresenceIcons[NfcRfidDetectorTypeFieldPresenceRfid]); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 69, 62, str); + } + } +} + +bool nfc_rfid_detector_view_field_presence_input(InputEvent* event, void* context) { + furi_assert(context); + NfcRfidDetectorFieldPresence* instance = context; + UNUSED(instance); + + if(event->key == InputKeyBack) { + return false; + } + + return true; +} + +void nfc_rfid_detector_view_field_presence_enter(void* context) { + furi_assert(context); + NfcRfidDetectorFieldPresence* instance = context; + with_view_model( + instance->view, + NfcRfidDetectorFieldPresenceModel * model, + { + model->nfc_field = 0; + model->rfid_field = 0; + model->rfid_frequency = 0; + }, + true); +} + +void nfc_rfid_detector_view_field_presence_exit(void* context) { + furi_assert(context); + NfcRfidDetectorFieldPresence* instance = context; + UNUSED(instance); +} + +NfcRfidDetectorFieldPresence* nfc_rfid_detector_view_field_presence_alloc() { + NfcRfidDetectorFieldPresence* instance = malloc(sizeof(NfcRfidDetectorFieldPresence)); + + // View allocation and configuration + instance->view = view_alloc(); + + view_allocate_model( + instance->view, ViewModelTypeLocking, sizeof(NfcRfidDetectorFieldPresenceModel)); + view_set_context(instance->view, instance); + view_set_draw_callback( + instance->view, (ViewDrawCallback)nfc_rfid_detector_view_field_presence_draw); + view_set_input_callback(instance->view, nfc_rfid_detector_view_field_presence_input); + view_set_enter_callback(instance->view, nfc_rfid_detector_view_field_presence_enter); + view_set_exit_callback(instance->view, nfc_rfid_detector_view_field_presence_exit); + + with_view_model( + instance->view, + NfcRfidDetectorFieldPresenceModel * model, + { + model->nfc_field = 0; + model->rfid_field = 0; + model->rfid_frequency = 0; + }, + true); + return instance; +} + +void nfc_rfid_detector_view_field_presence_free(NfcRfidDetectorFieldPresence* instance) { + furi_assert(instance); + + view_free(instance->view); + free(instance); +} + +View* nfc_rfid_detector_view_field_presence_get_view(NfcRfidDetectorFieldPresence* instance) { + furi_assert(instance); + return instance->view; +} diff --git a/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.h b/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.h new file mode 100644 index 00000000000..0ddb4e2cd58 --- /dev/null +++ b/applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "../helpers/nfc_rfid_detector_types.h" +#include "../helpers/nfc_rfid_detector_event.h" + +typedef struct NfcRfidDetectorFieldPresence NfcRfidDetectorFieldPresence; + +void nfc_rfid_detector_view_field_presence_update( + NfcRfidDetectorFieldPresence* instance, + bool nfc_field, + bool rfid_field, + uint32_t rfid_frequency); + +NfcRfidDetectorFieldPresence* nfc_rfid_detector_view_field_presence_alloc(); + +void nfc_rfid_detector_view_field_presence_free(NfcRfidDetectorFieldPresence* instance); + +View* nfc_rfid_detector_view_field_presence_get_view(NfcRfidDetectorFieldPresence* instance); diff --git a/applications/external/picopass/views/dict_attack.h b/applications/external/picopass/views/dict_attack.h index d675c1eb40c..bdfa3e95200 100644 --- a/applications/external/picopass/views/dict_attack.h +++ b/applications/external/picopass/views/dict_attack.h @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; diff --git a/applications/external/signal_generator/scenes/signal_gen_scene_pwm.c b/applications/external/signal_generator/scenes/signal_gen_scene_pwm.c index 7ac3fadda4c..1cadb3a1a47 100644 --- a/applications/external/signal_generator/scenes/signal_gen_scene_pwm.c +++ b/applications/external/signal_generator/scenes/signal_gen_scene_pwm.c @@ -33,7 +33,13 @@ void signal_gen_scene_pwm_on_enter(void* context) { signal_gen_pwm_set_callback(app->pwm_view, signal_gen_pwm_callback, app); signal_gen_pwm_set_params(app->pwm_view, 0, DEFAULT_FREQ, DEFAULT_DUTY); - furi_hal_pwm_start(pwm_ch_id[0], DEFAULT_FREQ, DEFAULT_DUTY); + + if(!furi_hal_pwm_is_running(pwm_ch_id[0])) { + furi_hal_pwm_start(pwm_ch_id[0], DEFAULT_FREQ, DEFAULT_DUTY); + } else { + furi_hal_pwm_stop(pwm_ch_id[0]); + furi_hal_pwm_start(pwm_ch_id[0], DEFAULT_FREQ, DEFAULT_DUTY); + } } bool signal_gen_scene_pwm_on_event(void* context, SceneManagerEvent event) { @@ -46,8 +52,18 @@ bool signal_gen_scene_pwm_on_event(void* context, SceneManagerEvent event) { furi_hal_pwm_set_params(app->pwm_ch, app->pwm_freq, app->pwm_duty); } else if(event.event == SignalGenPwmEventChannelChange) { consumed = true; - furi_hal_pwm_stop(app->pwm_ch_prev); - furi_hal_pwm_start(app->pwm_ch, app->pwm_freq, app->pwm_duty); + // Stop previous channel PWM + if(furi_hal_pwm_is_running(app->pwm_ch_prev)) { + furi_hal_pwm_stop(app->pwm_ch_prev); + } + + // Start PWM and restart if it was starter already + if(furi_hal_pwm_is_running(app->pwm_ch)) { + furi_hal_pwm_stop(app->pwm_ch); + furi_hal_pwm_start(app->pwm_ch, app->pwm_freq, app->pwm_duty); + } else { + furi_hal_pwm_start(app->pwm_ch, app->pwm_freq, app->pwm_duty); + } } } return consumed; @@ -56,5 +72,8 @@ bool signal_gen_scene_pwm_on_event(void* context, SceneManagerEvent event) { void signal_gen_scene_pwm_on_exit(void* context) { SignalGenApp* app = context; variable_item_list_reset(app->var_item_list); - furi_hal_pwm_stop(app->pwm_ch); + + if(furi_hal_pwm_is_running(app->pwm_ch)) { + furi_hal_pwm_stop(app->pwm_ch); + } } diff --git a/applications/main/application.fam b/applications/main/application.fam index d74c004aaa3..e2b3dd43776 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -12,7 +12,6 @@ App( # "subghz", # "bad_usb", # "u2f", - # "fap_loader", # "archive", ], ) diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index 9a7973cb388..70137d6944d 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include static void @@ -367,7 +367,7 @@ void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { static bool archive_get_fap_meta(FuriString* file_path, FuriString* fap_name, uint8_t** icon_ptr) { Storage* storage = furi_record_open(RECORD_STORAGE); bool success = false; - if(fap_loader_load_name_and_icon(file_path, storage, icon_ptr, fap_name)) { + if(flipper_application_load_name_and_icon(file_path, storage, icon_ptr, fap_name)) { success = true; } furi_record_close(RECORD_STORAGE); diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index c28f91f5244..e02f7622a6d 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -11,17 +11,28 @@ #define SCENE_STATE_DEFAULT (0) #define SCENE_STATE_NEED_REFRESH (1) -static const char* flipper_app_name[] = { - [ArchiveFileTypeIButton] = "iButton", - [ArchiveFileTypeNFC] = "NFC", - [ArchiveFileTypeSubGhz] = "Sub-GHz", - [ArchiveFileTypeLFRFID] = "125 kHz RFID", - [ArchiveFileTypeInfrared] = "Infrared", - [ArchiveFileTypeBadUsb] = "Bad USB", - [ArchiveFileTypeU2f] = "U2F", - [ArchiveFileTypeUpdateManifest] = "UpdaterApp", - [ArchiveFileTypeApplication] = "Applications", -}; +const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) { + switch(file_type) { + case ArchiveFileTypeIButton: + return "iButton"; + case ArchiveFileTypeNFC: + return "NFC"; + case ArchiveFileTypeSubGhz: + return "Sub-GHz"; + case ArchiveFileTypeLFRFID: + return "125 kHz RFID"; + case ArchiveFileTypeInfrared: + return "Infrared"; + case ArchiveFileTypeBadUsb: + return "Bad USB"; + case ArchiveFileTypeU2f: + return "U2F"; + case ArchiveFileTypeUpdateManifest: + return "UpdaterApp"; + default: + return NULL; + } +} static void archive_loader_callback(const void* message, void* context) { furi_assert(message); @@ -39,20 +50,20 @@ static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selec UNUSED(browser); Loader* loader = furi_record_open(RECORD_LOADER); - LoaderStatus status; - if(selected->is_app) { - char* param = strrchr(furi_string_get_cstr(selected->path), '/'); - if(param != NULL) { - param++; + const char* app_name = archive_get_flipper_app_name(selected->type); + + if(app_name) { + if(selected->is_app) { + char* param = strrchr(furi_string_get_cstr(selected->path), '/'); + if(param != NULL) { + param++; + } + loader_start_with_gui_error(loader, app_name, param); + } else { + loader_start_with_gui_error(loader, app_name, furi_string_get_cstr(selected->path)); } - status = loader_start(loader, flipper_app_name[selected->type], param); } else { - status = loader_start( - loader, flipper_app_name[selected->type], furi_string_get_cstr(selected->path)); - } - - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); + loader_start_with_gui_error(loader, furi_string_get_cstr(selected->path), NULL); } furi_record_close(RECORD_LOADER); diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 2aca3c02ba4..3c2f1321540 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -334,9 +334,24 @@ static bool archive_view_input(InputEvent* event, void* context) { browser->view, ArchiveBrowserViewModel * model, { + int32_t scroll_speed = 1; + if(model->button_held_for_ticks > 5) { + if(model->button_held_for_ticks % 2) { + scroll_speed = 0; + } else { + scroll_speed = model->button_held_for_ticks > 9 ? 4 : 2; + } + } + if(event->key == InputKeyUp) { - model->item_idx = - ((model->item_idx - 1) + model->item_cnt) % model->item_cnt; + if(model->item_idx < scroll_speed) { + model->button_held_for_ticks = 0; + model->item_idx = model->item_cnt - 1; + } else { + model->item_idx = + ((model->item_idx - scroll_speed) + model->item_cnt) % + model->item_cnt; + } if(is_file_list_load_required(model)) { model->list_loading = true; browser->callback(ArchiveBrowserEventLoadPrevItems, browser->context); @@ -345,8 +360,15 @@ static bool archive_view_input(InputEvent* event, void* context) { browser->callback(ArchiveBrowserEventFavMoveUp, browser->context); } model->scroll_counter = 0; + model->button_held_for_ticks += 1; } else if(event->key == InputKeyDown) { - model->item_idx = (model->item_idx + 1) % model->item_cnt; + int32_t count = model->item_cnt; + if(model->item_idx + scroll_speed >= count) { + model->button_held_for_ticks = 0; + model->item_idx = 0; + } else { + model->item_idx = (model->item_idx + scroll_speed) % model->item_cnt; + } if(is_file_list_load_required(model)) { model->list_loading = true; browser->callback(ArchiveBrowserEventLoadNextItems, browser->context); @@ -355,6 +377,7 @@ static bool archive_view_input(InputEvent* event, void* context) { browser->callback(ArchiveBrowserEventFavMoveDown, browser->context); } model->scroll_counter = 0; + model->button_held_for_ticks += 1; } }, true); @@ -391,6 +414,14 @@ static bool archive_view_input(InputEvent* event, void* context) { } } + if(event->type == InputTypeRelease) { + with_view_model( + browser->view, + ArchiveBrowserViewModel * model, + { model->button_held_for_ticks = 0; }, + true); + } + return true; } diff --git a/applications/main/archive/views/archive_browser_view.h b/applications/main/archive/views/archive_browser_view.h index 0a000e5ac34..25490aedd3e 100644 --- a/applications/main/archive/views/archive_browser_view.h +++ b/applications/main/archive/views/archive_browser_view.h @@ -100,6 +100,8 @@ typedef struct { int32_t array_offset; int32_t list_offset; size_t scroll_counter; + + uint32_t button_held_for_ticks; } ArchiveBrowserViewModel; void archive_browser_set_callback( diff --git a/applications/main/fap_loader/application.fam b/applications/main/fap_loader/application.fam deleted file mode 100644 index b0e67cd42e3..00000000000 --- a/applications/main/fap_loader/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="fap_loader", - name="Applications", - apptype=FlipperAppType.APP, - entry_point="fap_loader_app", - cdefines=["APP_FAP_LOADER"], - requires=[ - "gui", - "storage", - "loader", - ], - stack_size=int(1.5 * 1024), - icon="A_Plugins_14", - order=90, -) diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c deleted file mode 100644 index 7af5244ae49..00000000000 --- a/applications/main/fap_loader/fap_loader_app.c +++ /dev/null @@ -1,216 +0,0 @@ -#include "fap_loader_app.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define TAG "FapLoader" - -struct FapLoader { - FlipperApplication* app; - Storage* storage; - DialogsApp* dialogs; - Gui* gui; - FuriString* fap_path; - ViewDispatcher* view_dispatcher; - Loading* loading; -}; - -bool fap_loader_load_name_and_icon( - FuriString* path, - Storage* storage, - uint8_t** icon_ptr, - FuriString* item_name) { - FlipperApplication* app = flipper_application_alloc(storage, firmware_api_interface); - - FlipperApplicationPreloadStatus preload_res = - flipper_application_preload_manifest(app, furi_string_get_cstr(path)); - - bool load_success = false; - - if(preload_res == FlipperApplicationPreloadStatusSuccess) { - const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); - if(manifest->has_icon) { - memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); - } - furi_string_set(item_name, manifest->name); - load_success = true; - } else { - FURI_LOG_E(TAG, "FAP Loader failed to preload %s", furi_string_get_cstr(path)); - load_success = false; - } - - flipper_application_free(app); - return load_success; -} - -static bool fap_loader_item_callback( - FuriString* path, - void* context, - uint8_t** icon_ptr, - FuriString* item_name) { - FapLoader* fap_loader = context; - furi_assert(fap_loader); - return fap_loader_load_name_and_icon(path, fap_loader->storage, icon_ptr, item_name); -} - -static bool fap_loader_run_selected_app(FapLoader* loader) { - furi_assert(loader); - - FuriString* error_message; - - error_message = furi_string_alloc_set("unknown error"); - - bool file_selected = false; - bool show_error = true; - do { - file_selected = true; - loader->app = flipper_application_alloc(loader->storage, firmware_api_interface); - size_t start = furi_get_tick(); - - FURI_LOG_I(TAG, "FAP Loader is loading %s", furi_string_get_cstr(loader->fap_path)); - - FlipperApplicationPreloadStatus preload_res = - flipper_application_preload(loader->app, furi_string_get_cstr(loader->fap_path)); - if(preload_res != FlipperApplicationPreloadStatusSuccess) { - const char* err_msg = flipper_application_preload_status_to_string(preload_res); - furi_string_printf(error_message, "Preload failed: %s", err_msg); - FURI_LOG_E( - TAG, - "FAP Loader failed to preload %s: %s", - furi_string_get_cstr(loader->fap_path), - err_msg); - break; - } - - FURI_LOG_I(TAG, "FAP Loader is mapping"); - FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); - if(load_status != FlipperApplicationLoadStatusSuccess) { - const char* err_msg = flipper_application_load_status_to_string(load_status); - furi_string_printf(error_message, "Load failed: %s", err_msg); - FURI_LOG_E( - TAG, - "FAP Loader failed to map to memory %s: %s", - furi_string_get_cstr(loader->fap_path), - err_msg); - break; - } - - FURI_LOG_I(TAG, "Loaded in %ums", (size_t)(furi_get_tick() - start)); - FURI_LOG_I(TAG, "FAP Loader is starting app"); - - FuriThread* thread = flipper_application_spawn(loader->app, NULL); - - /* This flag is set by the debugger - to break on app start */ - if(furi_hal_debug_is_gdb_session_active()) { - FURI_LOG_W(TAG, "Triggering BP for debugger"); - /* After hitting this, you can set breakpoints in your .fap's code - * Note that you have to toggle breakpoints that were set before */ - __asm volatile("bkpt 0"); - } - - FuriString* app_name = furi_string_alloc(); - path_extract_filename_no_ext(furi_string_get_cstr(loader->fap_path), app_name); - furi_thread_set_appid(thread, furi_string_get_cstr(app_name)); - furi_string_free(app_name); - - furi_thread_start(thread); - furi_thread_join(thread); - - show_error = false; - int ret = furi_thread_get_return_code(thread); - - FURI_LOG_I(TAG, "FAP app returned: %i", ret); - } while(0); - - if(show_error) { - DialogMessage* message = dialog_message_alloc(); - dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); - dialog_message_set_buttons(message, NULL, NULL, NULL); - - FuriString* buffer; - buffer = furi_string_alloc(); - furi_string_printf(buffer, "%s", furi_string_get_cstr(error_message)); - furi_string_replace(buffer, ":", "\n"); - dialog_message_set_text( - message, furi_string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter); - - dialog_message_show(loader->dialogs, message); - dialog_message_free(message); - furi_string_free(buffer); - } - - furi_string_free(error_message); - - if(file_selected) { - flipper_application_free(loader->app); - } - - return file_selected; -} - -static bool fap_loader_select_app(FapLoader* loader) { - const DialogsFileBrowserOptions browser_options = { - .extension = ".fap", - .skip_assets = true, - .icon = &I_unknown_10px, - .hide_ext = true, - .item_loader_callback = fap_loader_item_callback, - .item_loader_context = loader, - .base_path = EXT_PATH("apps"), - }; - - return dialog_file_browser_show( - loader->dialogs, loader->fap_path, loader->fap_path, &browser_options); -} - -static FapLoader* fap_loader_alloc(const char* path) { - FapLoader* loader = malloc(sizeof(FapLoader)); //-V799 - loader->fap_path = furi_string_alloc_set(path); - loader->storage = furi_record_open(RECORD_STORAGE); - loader->dialogs = furi_record_open(RECORD_DIALOGS); - loader->gui = furi_record_open(RECORD_GUI); - loader->view_dispatcher = view_dispatcher_alloc(); - loader->loading = loading_alloc(); - view_dispatcher_attach_to_gui( - loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); - view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading)); - return loader; -} //-V773 - -static void fap_loader_free(FapLoader* loader) { - view_dispatcher_remove_view(loader->view_dispatcher, 0); - loading_free(loader->loading); - view_dispatcher_free(loader->view_dispatcher); - furi_string_free(loader->fap_path); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_DIALOGS); - furi_record_close(RECORD_STORAGE); - free(loader); -} - -int32_t fap_loader_app(void* p) { - FapLoader* loader; - if(p) { - loader = fap_loader_alloc((const char*)p); - view_dispatcher_switch_to_view(loader->view_dispatcher, 0); - fap_loader_run_selected_app(loader); - } else { - loader = fap_loader_alloc(EXT_PATH("apps")); - while(fap_loader_select_app(loader)) { - view_dispatcher_switch_to_view(loader->view_dispatcher, 0); - fap_loader_run_selected_app(loader); - }; - } - - fap_loader_free(loader); - return 0; -} diff --git a/applications/main/fap_loader/fap_loader_app.h b/applications/main/fap_loader/fap_loader_app.h deleted file mode 100644 index 9ed725efe52..00000000000 --- a/applications/main/fap_loader/fap_loader_app.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct FapLoader FapLoader; - -/** - * @brief Load name and icon from FAP file. - * - * @param path Path to FAP file. - * @param storage Storage instance. - * @param icon_ptr Icon pointer. - * @param item_name Application name. - * @return true if icon and name were loaded successfully. - */ -bool fap_loader_load_name_and_icon( - FuriString* path, - Storage* storage, - uint8_t** icon_ptr, - FuriString* item_name); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index 7aa010ba662..320cd94bf7d 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -149,6 +149,10 @@ static void nfc_cli_apdu(Cli* cli, FuriString* args) { break; } resp_size = (tx_rx.rx_bits / 8) * 2; + if(!resp_size) { + printf("No response\r\n"); + break; + } resp_buffer = malloc(resp_size); uint8_to_hex_chars(tx_rx.rx_data, resp_buffer, resp_size); resp_buffer[resp_size] = 0; diff --git a/applications/main/nfc_old/application.fam b/applications/main/nfc_old/application.fam index b67b8e6b2d1..364a800e89b 100644 --- a/applications/main/nfc_old/application.fam +++ b/applications/main/nfc_old/application.fam @@ -1,5 +1,5 @@ App( - appid="nfc_old", + appid="nfc_app", name="NFC", apptype=FlipperAppType.APP, targets=["f7"], @@ -16,7 +16,7 @@ App( ) App( - appid="nfc_old_start", + appid="nfc_start", apptype=FlipperAppType.STARTUP, entry_point="nfc_on_system_start", requires=["nfc"], diff --git a/applications/main/nfc_old/nfc_app.c b/applications/main/nfc_old/nfc.c similarity index 94% rename from applications/main/nfc_old/nfc_app.c rename to applications/main/nfc_old/nfc.c index e9d070c98d2..56d98a8c61a 100644 --- a/applications/main/nfc_old/nfc_app.c +++ b/applications/main/nfc_old/nfc.c @@ -1,22 +1,22 @@ -#include "nfc_app_i.h" +#include "nfc_i.h" #include #include bool nfc_custom_event_callback(void* context, uint32_t event) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; return scene_manager_handle_custom_event(nfc->scene_manager, event); } bool nfc_back_event_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; return scene_manager_handle_back_event(nfc->scene_manager); } static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; furi_assert(nfc->rpc_ctx); @@ -33,8 +33,8 @@ static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { } } -NfcApp* nfc_app_alloc() { - NfcApp* nfc = malloc(sizeof(NfcApp)); +Nfc* nfc_alloc() { + Nfc* nfc = malloc(sizeof(Nfc)); nfc->worker = nfc_worker_alloc(); nfc->view_dispatcher = view_dispatcher_alloc(); @@ -107,7 +107,7 @@ NfcApp* nfc_app_alloc() { return nfc; } -void nfc_app_free(NfcApp* nfc) { +void nfc_free(Nfc* nfc) { furi_assert(nfc); if(nfc->rpc_state == NfcRpcStateEmulating) { @@ -192,7 +192,7 @@ void nfc_app_free(NfcApp* nfc) { free(nfc); } -void nfc_text_store_set(NfcApp* nfc, const char* text, ...) { +void nfc_text_store_set(Nfc* nfc, const char* text, ...) { va_list args; va_start(args, text); @@ -201,27 +201,27 @@ void nfc_text_store_set(NfcApp* nfc, const char* text, ...) { va_end(args); } -void nfc_text_store_clear(NfcApp* nfc) { +void nfc_text_store_clear(Nfc* nfc) { memset(nfc->text_store, 0, sizeof(nfc->text_store)); } -void nfc_blink_read_start(NfcApp* nfc) { +void nfc_blink_read_start(Nfc* nfc) { notification_message(nfc->notifications, &sequence_blink_start_cyan); } -void nfc_blink_emulate_start(NfcApp* nfc) { +void nfc_blink_emulate_start(Nfc* nfc) { notification_message(nfc->notifications, &sequence_blink_start_magenta); } -void nfc_blink_detect_start(NfcApp* nfc) { +void nfc_blink_detect_start(Nfc* nfc) { notification_message(nfc->notifications, &sequence_blink_start_yellow); } -void nfc_blink_stop(NfcApp* nfc) { +void nfc_blink_stop(Nfc* nfc) { notification_message(nfc->notifications, &sequence_blink_stop); } -bool nfc_save_file(NfcApp* nfc) { +bool nfc_save_file(Nfc* nfc) { furi_string_printf( nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION); bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path)); @@ -229,7 +229,7 @@ bool nfc_save_file(NfcApp* nfc) { } void nfc_show_loading_popup(void* context, bool show) { - NfcApp* nfc = context; + Nfc* nfc = context; TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); if(show) { @@ -266,7 +266,7 @@ static bool nfc_is_hal_ready() { int32_t nfc_app(void* p) { if(!nfc_is_hal_ready()) return 0; - NfcApp* nfc = nfc_app_alloc(); + Nfc* nfc = nfc_alloc(); char* args = p; // Check argument and run corresponding scene @@ -313,7 +313,7 @@ int32_t nfc_app(void* p) { view_dispatcher_run(nfc->view_dispatcher); - nfc_app_free(nfc); + nfc_free(nfc); return 0; } diff --git a/applications/main/nfc_old/nfc.h b/applications/main/nfc_old/nfc.h new file mode 100644 index 00000000000..e08be6a3aa9 --- /dev/null +++ b/applications/main/nfc_old/nfc.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct Nfc Nfc; diff --git a/applications/main/nfc_old/nfc_app.h b/applications/main/nfc_old/nfc_app.h deleted file mode 100644 index 0e456fd48b2..00000000000 --- a/applications/main/nfc_old/nfc_app.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -typedef struct NfcApp NfcApp; diff --git a/applications/main/nfc_old/nfc_cli.c b/applications/main/nfc_old/nfc_cli.c index da9e24cb9a7..0b7e7547548 100644 --- a/applications/main/nfc_old/nfc_cli.c +++ b/applications/main/nfc_old/nfc_cli.c @@ -7,16 +7,6 @@ #include #include -#include -#include - -#include - -#include -#include -#include -#include - static void nfc_cli_print_usage() { printf("Usage:\r\n"); printf("nfc \r\n"); @@ -29,11 +19,6 @@ static void nfc_cli_print_usage() { } } -static void nfc_cli_check(Cli* cli, FuriString* args) { - UNUSED(args); - UNUSED(cli); -} - static void nfc_cli_detect(Cli* cli, FuriString* args) { UNUSED(args); // Check if nfc worker is not busy @@ -159,6 +144,10 @@ static void nfc_cli_apdu(Cli* cli, FuriString* args) { break; } resp_size = (tx_rx.rx_bits / 8) * 2; + if(!resp_size) { + printf("No response\r\n"); + break; + } resp_buffer = malloc(resp_size); uint8_to_hex_chars(tx_rx.rx_data, resp_buffer, resp_size); resp_buffer[resp_size] = 0; @@ -186,10 +175,6 @@ static void nfc_cli(Cli* cli, FuriString* args, void* context) { nfc_cli_print_usage(); break; } - if(furi_string_cmp_str(cmd, "c") == 0) { - nfc_cli_check(cli, args); - break; - } if(furi_string_cmp_str(cmd, "detect") == 0) { nfc_cli_detect(cli, args); break; diff --git a/applications/main/nfc_old/nfc_app_i.h b/applications/main/nfc_old/nfc_i.h similarity index 86% rename from applications/main/nfc_old/nfc_app_i.h rename to applications/main/nfc_old/nfc_i.h index c361a5fc81f..f7e48990292 100644 --- a/applications/main/nfc_old/nfc_app_i.h +++ b/applications/main/nfc_old/nfc_i.h @@ -1,6 +1,6 @@ #pragma once -#include "nfc_app.h" +#include "nfc.h" #include #include @@ -52,7 +52,7 @@ typedef enum { NfcRpcStateEmulated, } NfcRpcState; -struct NfcApp { +struct Nfc { NfcWorker* worker; ViewDispatcher* view_dispatcher; Gui* gui; @@ -97,22 +97,22 @@ typedef enum { NfcViewDetectReader, } NfcView; -NfcApp* nfc_alloc(); +Nfc* nfc_alloc(); int32_t nfc_task(void* p); -void nfc_text_store_set(NfcApp* nfc, const char* text, ...); +void nfc_text_store_set(Nfc* nfc, const char* text, ...); -void nfc_text_store_clear(NfcApp* nfc); +void nfc_text_store_clear(Nfc* nfc); -void nfc_blink_read_start(NfcApp* nfc); +void nfc_blink_read_start(Nfc* nfc); -void nfc_blink_emulate_start(NfcApp* nfc); +void nfc_blink_emulate_start(Nfc* nfc); -void nfc_blink_detect_start(NfcApp* nfc); +void nfc_blink_detect_start(Nfc* nfc); -void nfc_blink_stop(NfcApp* nfc); +void nfc_blink_stop(Nfc* nfc); -bool nfc_save_file(NfcApp* nfc); +bool nfc_save_file(Nfc* nfc); void nfc_show_loading_popup(void* context, bool show); diff --git a/applications/main/nfc_old/scenes/nfc_scene_config.h b/applications/main/nfc_old/scenes/nfc_scene_config.h index a9da07dfda0..f11d1479838 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_config.h +++ b/applications/main/nfc_old/scenes/nfc_scene_config.h @@ -14,6 +14,13 @@ ADD_SCENE(nfc, file_select, FileSelect) ADD_SCENE(nfc, emulate_uid, EmulateUid) ADD_SCENE(nfc, nfca_read_success, NfcaReadSuccess) ADD_SCENE(nfc, nfca_menu, NfcaMenu) +ADD_SCENE(nfc, nfcv_menu, NfcVMenu) +ADD_SCENE(nfc, nfcv_unlock_menu, NfcVUnlockMenu) +ADD_SCENE(nfc, nfcv_key_input, NfcVKeyInput) +ADD_SCENE(nfc, nfcv_unlock, NfcVUnlock) +ADD_SCENE(nfc, nfcv_emulate, NfcVEmulate) +ADD_SCENE(nfc, nfcv_sniff, NfcVSniff) +ADD_SCENE(nfc, nfcv_read_success, NfcVReadSuccess) ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess) ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData) ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu) diff --git a/applications/main/nfc_old/scenes/nfc_scene_debug.c b/applications/main/nfc_old/scenes/nfc_scene_debug.c index f6705c880f3..ed079c2ed9a 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_debug.c +++ b/applications/main/nfc_old/scenes/nfc_scene_debug.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" enum SubmenuDebugIndex { SubmenuDebugIndexField, @@ -6,13 +6,13 @@ enum SubmenuDebugIndex { }; void nfc_scene_debug_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_debug_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -28,7 +28,7 @@ void nfc_scene_debug_on_enter(void* context) { } bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -48,7 +48,7 @@ bool nfc_scene_debug_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_debug_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_delete.c b/applications/main/nfc_old/scenes/nfc_scene_delete.c index a5debe5e1b4..0808db45a32 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_delete.c +++ b/applications/main/nfc_old/scenes/nfc_scene_delete.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_delete_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; // Setup Custom Widget view @@ -31,6 +31,8 @@ void nfc_scene_delete_on_enter(void* context) { nfc->widget, 64, 24, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); NfcProtocol protocol = nfc->dev->dev_data.protocol; + const char* nfc_type = "NFC-A"; + if(protocol == NfcDeviceProtocolEMV) { furi_string_set(temp_str, "EMV bank card"); } else if(protocol == NfcDeviceProtocolMifareUl) { @@ -39,19 +41,22 @@ void nfc_scene_delete_on_enter(void* context) { furi_string_set(temp_str, nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { furi_string_set(temp_str, "MIFARE DESFire"); + } else if(protocol == NfcDeviceProtocolNfcV) { + furi_string_set(temp_str, "ISO15693 tag"); + nfc_type = "NFC-V"; } else { furi_string_set(temp_str, "Unknown ISO tag"); } widget_add_string_element( nfc->widget, 64, 34, AlignCenter, AlignTop, FontSecondary, furi_string_get_cstr(temp_str)); - widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, "NFC-A"); + widget_add_string_element(nfc->widget, 64, 44, AlignCenter, AlignTop, FontSecondary, nfc_type); furi_string_free(temp_str); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget); } bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -71,7 +76,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_delete_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_delete_success.c b/applications/main/nfc_old/scenes/nfc_scene_delete_success.c index f0c22eec4d5..795363527fc 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_delete_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_delete_success.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_delete_success_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_delete_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_delete_success_on_enter(void* context) { } bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -38,7 +38,7 @@ bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_delete_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c b/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c index 85c698d0535..745946157b0 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c +++ b/applications/main/nfc_old/scenes/nfc_scene_detect_reader.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX (10U) @@ -12,19 +12,19 @@ static const NotificationSequence sequence_detect_reader = { bool nfc_detect_reader_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } void nfc_scene_detect_reader_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_detect_reader_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; detect_reader_set_callback(nfc->detect_reader, nfc_scene_detect_reader_callback, nfc); detect_reader_set_nonces_max(nfc->detect_reader, NFC_SCENE_DETECT_READER_PAIR_NONCES_MAX); @@ -48,7 +48,7 @@ void nfc_scene_detect_reader_on_enter(void* context) { } bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; uint32_t nonces_collected = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneDetectReader); @@ -89,7 +89,7 @@ bool nfc_scene_detect_reader_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_detect_reader_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_device_info.c b/applications/main/nfc_old/scenes/nfc_scene_device_info.c index 4ec17b1b055..5d51c0816c8 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_device_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_device_info.c @@ -1,15 +1,15 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "../helpers/nfc_emv_parser.h" void nfc_scene_device_info_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_device_info_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; FuriString* temp_str; @@ -67,7 +67,7 @@ void nfc_scene_device_info_on_enter(void* context) { } bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -80,7 +80,7 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_device_info_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear views widget_reset(nfc->widget); diff --git a/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c b/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c index 3b525c17e84..781c5a93254 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c +++ b/applications/main/nfc_old/scenes/nfc_scene_dict_not_found.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_dict_not_found_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_dict_not_found_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -26,7 +26,7 @@ void nfc_scene_dict_not_found_on_enter(void* context) { } bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -47,6 +47,6 @@ bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_dict_not_found_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; popup_reset(nfc->popup); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c b/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c index 81d00aeffc2..358ad2ab6f5 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c +++ b/applications/main/nfc_old/scenes/nfc_scene_emulate_apdu_sequence.c @@ -1,8 +1,8 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_emulate_apdu_sequence_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -23,7 +23,7 @@ bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent e } void nfc_scene_emulate_apdu_sequence_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c b/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c index 10435d2c755..7316eebe015 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c +++ b/applications/main/nfc_old/scenes/nfc_scene_emulate_uid.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_SCENE_EMULATE_UID_LOG_SIZE_MAX (200) @@ -10,14 +10,14 @@ enum { bool nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); return true; } void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } @@ -25,12 +25,12 @@ void nfc_scene_emulate_uid_widget_callback(GuiButtonType result, InputType type, void nfc_emulate_uid_textbox_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } // Add widget with device name or inform that data received -static void nfc_scene_emulate_uid_widget_config(NfcApp* nfc, bool data_received) { +static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) { FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; Widget* widget = nfc->widget; widget_reset(widget); @@ -57,7 +57,7 @@ static void nfc_scene_emulate_uid_widget_config(NfcApp* nfc, bool data_received) } void nfc_scene_emulate_uid_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup Widget nfc_scene_emulate_uid_widget_config(nfc, false); @@ -84,7 +84,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) { } bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcReaderRequestData* reader_data = &nfc->dev->dev_data.reader_data; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmulateUid); bool consumed = false; @@ -130,7 +130,7 @@ bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_emulate_uid_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c b/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c index 88d3355a0b7..eb1e10043bd 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_emv_menu.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" enum SubmenuIndex { SubmenuIndexInfo, }; void nfc_scene_emv_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_emv_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item(submenu, "Info", SubmenuIndexInfo, nfc_scene_emv_menu_submenu_callback, nfc); @@ -22,7 +22,7 @@ void nfc_scene_emv_menu_on_enter(void* context) { } bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -39,7 +39,7 @@ bool nfc_scene_emv_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_emv_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c index 00057a2ee4a..005b76cb211 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_emv_read_success.c @@ -1,18 +1,18 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "../helpers/nfc_emv_parser.h" void nfc_scene_emv_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_emv_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; EmvData* emv_data = &nfc->dev->dev_data.emv_data; // Setup Custom Widget view @@ -85,7 +85,7 @@ void nfc_scene_emv_read_success_on_enter(void* context) { } bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -104,7 +104,7 @@ bool nfc_scene_emv_read_success_on_event(void* context, SceneManagerEvent event) } void nfc_scene_emv_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c index 92933556d2a..3ce4f6de839 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c +++ b/applications/main/nfc_old/scenes/nfc_scene_exit_confirm.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_exit_confirm_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Exit"); @@ -22,7 +22,7 @@ void nfc_scene_exit_confirm_on_enter(void* context) { } bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -45,7 +45,7 @@ bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_exit_confirm_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c b/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c index 31106c76a4f..7f5bc7e7585 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc_old/scenes/nfc_scene_extra_actions.c @@ -1,19 +1,21 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" enum SubmenuIndex { SubmenuIndexReadCardType, SubmenuIndexMfClassicKeys, SubmenuIndexMfUltralightUnlock, + SubmenuIndexNfcVUnlock, + SubmenuIndexNfcVSniff, }; void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_extra_actions_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -34,13 +36,25 @@ void nfc_scene_extra_actions_on_enter(void* context) { SubmenuIndexMfUltralightUnlock, nfc_scene_extra_actions_submenu_callback, nfc); + submenu_add_item( + submenu, + "Unlock SLIX-L", + SubmenuIndexNfcVUnlock, + nfc_scene_extra_actions_submenu_callback, + nfc); + submenu_add_item( + submenu, + "Listen NfcV Reader", + SubmenuIndexNfcVSniff, + nfc_scene_extra_actions_submenu_callback, + nfc); submenu_set_selected_item( submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneExtraActions)); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); } bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -58,6 +72,12 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0); scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType); consumed = true; + } else if(event.event == SubmenuIndexNfcVUnlock) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlockMenu); + consumed = true; + } else if(event.event == SubmenuIndexNfcVSniff) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVSniff); + consumed = true; } scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event); } @@ -66,7 +86,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_extra_actions_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_field.c b/applications/main/nfc_old/scenes/nfc_scene_field.c index 893f4d03ff9..e3eb6a7088b 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_field.c +++ b/applications/main/nfc_old/scenes/nfc_scene_field.c @@ -1,7 +1,7 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_field_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; furi_hal_nfc_field_on(); @@ -25,7 +25,7 @@ bool nfc_scene_field_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_field_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; furi_hal_nfc_field_off(); notification_internal_message(nfc->notifications, &sequence_reset_blue); diff --git a/applications/main/nfc_old/scenes/nfc_scene_file_select.c b/applications/main/nfc_old/scenes/nfc_scene_file_select.c index 61ac593e0c4..374a933d1c7 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_file_select.c +++ b/applications/main/nfc_old/scenes/nfc_scene_file_select.c @@ -1,8 +1,8 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "nfc/nfc_device.h" void nfc_scene_file_select_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Process file_select return nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc); if(!furi_string_size(nfc->dev->load_path)) { diff --git a/applications/main/nfc_old/scenes/nfc_scene_generate_info.c b/applications/main/nfc_old/scenes/nfc_scene_generate_info.c index e877d771a6f..7b84ae43b11 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_generate_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_generate_info.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "lib/nfc/helpers/nfc_generators.h" void nfc_scene_generate_info_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_generate_info_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup dialog view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; @@ -34,7 +34,7 @@ void nfc_scene_generate_info_on_enter(void* context) { } bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -53,7 +53,7 @@ bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_generate_info_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean views dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c index b2be2f53a66..dcb02d3645a 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_data.c @@ -1,7 +1,7 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_data_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicType type = nfc->dev->dev_data.mf_classic_data.type; MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; TextBox* text_box = nfc->text_box; @@ -20,17 +20,17 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { int bytes_written = 0; for(int block_num = 0; block_num < card_blocks; block_num++) { - bool is_sec_trailer = mifare_classic_is_sector_trailer(block_num); + bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); if(is_sec_trailer) { - uint8_t sector_num = mifare_classic_get_sector_by_block(block_num); + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); MfClassicSectorTrailer* sec_tr = - mifare_classic_get_sector_trailer_by_sector(data, sector_num); + mf_classic_get_sector_trailer_by_sector(data, sector_num); // Key A for(size_t i = 0; i < sizeof(sec_tr->key_a); i += 2) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyA)) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", sec_tr->key_a[i], sec_tr->key_a[i + 1]); } else { @@ -43,7 +43,7 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mifare_classic_is_block_read(data, block_num)) { + if(mf_classic_is_block_read(data, block_num)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", @@ -59,7 +59,7 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mifare_classic_is_key_found(data, sector_num, MfClassicKeyB)) { + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", sec_tr->key_b[i], sec_tr->key_b[i + 1]); } else { @@ -73,7 +73,7 @@ void nfc_scene_mf_classic_data_on_enter(void* context) { if((bytes_written % 8 == 0) && (bytes_written != 0)) { furi_string_push_back(nfc->text_box_store, '\n'); } - if(mifare_classic_is_block_read(data, block_num)) { + if(mf_classic_is_block_read(data, block_num)) { furi_string_cat_printf( nfc->text_box_store, "%02X%02X ", @@ -98,7 +98,7 @@ bool nfc_scene_mf_classic_data_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_data_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view text_box_reset(nfc->text_box); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c index dd27b6c1b32..5bd24d7eac1 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_dict_attack.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include #define TAG "NfcMfClassicDictAttack" @@ -11,29 +11,29 @@ typedef enum { bool nfc_dict_attack_worker_callback(NfcWorkerEvent event, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } void nfc_dict_attack_dict_attack_result_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackSkip); } -static void nfc_scene_mf_classic_dict_attack_update_view(NfcApp* nfc) { +static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) { MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; uint8_t sectors_read = 0; uint8_t keys_found = 0; // Calculate found keys and read sectors - mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); dict_attack_set_keys_found(nfc->dict_attack, keys_found); dict_attack_set_sector_read(nfc->dict_attack, sectors_read); } -static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttackState state) { +static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) { MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; NfcWorkerState worker_state = NfcWorkerStateReady; @@ -88,7 +88,7 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(NfcApp* nfc, DictAttac } void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_scene_mf_classic_dict_attack_prepare_view(nfc, DictAttackStateIdle); view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); nfc_blink_read_start(nfc); @@ -96,7 +96,7 @@ void nfc_scene_mf_classic_dict_attack_on_enter(void* context) { } bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; bool consumed = false; @@ -111,7 +111,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent } else { notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } } else if(event.event == NfcWorkerEventAborted) { @@ -123,7 +123,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent notification_message(nfc->notifications, &sequence_success); scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicReadSuccess); // Counting failed attempts too - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; } } else if(event.event == NfcWorkerEventCardDetected) { @@ -172,7 +172,7 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c index 6cf7689052c..8c0f493e12b 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_emulate.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_MF_CLASSIC_DATA_NOT_CHANGED (0UL) #define NFC_MF_CLASSIC_DATA_CHANGED (1UL) bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); - NfcApp* nfc = context; + Nfc* nfc = context; scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_CHANGED); @@ -13,7 +13,7 @@ bool nfc_mf_classic_emulate_worker_callback(NfcWorkerEvent event, void* context) } void nfc_scene_mf_classic_emulate_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -38,7 +38,7 @@ void nfc_scene_mf_classic_emulate_on_enter(void* context) { } bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeBack) { @@ -60,7 +60,7 @@ bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_classic_emulate_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c index b7cc2f28345..8a7dc2c1839 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_keys_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_keys_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Load flipper dict keys total uint32_t flipper_dict_keys_total = 0; @@ -48,7 +48,7 @@ void nfc_scene_mf_classic_keys_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -65,7 +65,7 @@ bool nfc_scene_mf_classic_keys_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_keys_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c index 37b543b8d93..3a999f03114 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_add.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_classic_keys_add_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_mf_classic_keys_add_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -24,7 +24,7 @@ void nfc_scene_mf_classic_keys_add_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -52,7 +52,7 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve } void nfc_scene_mf_classic_keys_add_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c index 9f34c8eee0d..0ea3f59a45e 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_delete.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_keys_delete_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); uint32_t key_index = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_keys_delete_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; uint32_t key_index = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicKeysDelete); @@ -77,7 +77,7 @@ bool nfc_scene_mf_classic_keys_delete_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_classic_keys_delete_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c index 6a7be48a0bb..57f9fe65624 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_list.c @@ -1,22 +1,22 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_SCENE_MF_CLASSIC_KEYS_LIST_MAX (100) void nfc_scene_mf_classic_keys_list_submenu_callback(void* context, uint32_t index) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_classic_keys_list_popup_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } -void nfc_scene_mf_classic_keys_list_prepare(NfcApp* nfc, MfClassicDict* dict) { +void nfc_scene_mf_classic_keys_list_prepare(Nfc* nfc, MfClassicDict* dict) { Submenu* submenu = nfc->submenu; uint32_t index = 0; FuriString* temp_key; @@ -35,7 +35,7 @@ void nfc_scene_mf_classic_keys_list_prepare(NfcApp* nfc, MfClassicDict* dict) { } void nfc_scene_mf_classic_keys_list_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicDict* dict = mf_classic_dict_alloc(MfClassicDictTypeUser); MfClassicUserKeys_init(nfc->mfc_key_strs); if(dict) { @@ -71,7 +71,7 @@ void nfc_scene_mf_classic_keys_list_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventViewExit) { @@ -87,7 +87,7 @@ bool nfc_scene_mf_classic_keys_list_on_event(void* context, SceneManagerEvent ev } void nfc_scene_mf_classic_keys_list_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfClassicUserKeys_it_t it; for(MfClassicUserKeys_it(it, nfc->mfc_key_strs); !MfClassicUserKeys_end_p(it); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c index 5cc1ba63539..ab41989b2c7 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_keys_warn_duplicate.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_keys_warn_duplicate_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -28,7 +28,7 @@ void nfc_scene_mf_classic_keys_warn_duplicate_on_enter(void* context) { } bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -41,7 +41,7 @@ bool nfc_scene_mf_classic_keys_warn_duplicate_on_event(void* context, SceneManag } void nfc_scene_mf_classic_keys_warn_duplicate_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; popup_reset(nfc->popup); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c index 18e1a78aa80..9c416367646 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -9,20 +9,20 @@ enum SubmenuIndex { }; void nfc_scene_mf_classic_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_classic_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc); submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc); - if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { submenu_add_item( submenu, "Detect Reader", @@ -40,7 +40,7 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) { } bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -54,14 +54,14 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); + dolphin_deed(DolphinDeedNfcDetectReader); consumed = true; } else if(event.event == SubmenuIndexInfo) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo); @@ -75,7 +75,7 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c index bdc3b137eb2..444c9a540e7 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_read_success.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_mf_classic_read_success_widget_callback( } void nfc_scene_mf_classic_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; MfClassicData* mf_data = &dev_data->mf_classic_data; @@ -33,11 +33,11 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { for(size_t i = 0; i < dev_data->nfc_data.uid_len; i++) { furi_string_cat_printf(temp_str, " %02X", dev_data->nfc_data.uid[i]); } - uint8_t sectors_total = mifare_classic_get_total_sectors_num(mf_data->type); + uint8_t sectors_total = mf_classic_get_total_sectors_num(mf_data->type); uint8_t keys_total = sectors_total * 2; uint8_t keys_found = 0; uint8_t sectors_read = 0; - mifare_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); + mf_classic_get_read_sectors_and_keys(mf_data, §ors_read, &keys_found); furi_string_cat_printf(temp_str, "\nKeys Found: %d/%d", keys_found, keys_total); furi_string_cat_printf(temp_str, "\nSectors Read: %d/%d", sectors_read, sectors_total); } @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) { } bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -73,7 +73,7 @@ bool nfc_scene_mf_classic_read_success_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_classic_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c index 731c1e2683d..ffef1b7b9f0 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum { @@ -9,13 +9,13 @@ enum { bool nfc_mf_classic_update_worker_callback(NfcWorkerEvent event, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } -static void nfc_scene_mf_classic_update_setup_view(NfcApp* nfc) { +static void nfc_scene_mf_classic_update_setup_view(Nfc* nfc) { Popup* popup = nfc->popup; popup_reset(popup); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicUpdate); @@ -33,7 +33,7 @@ static void nfc_scene_mf_classic_update_setup_view(NfcApp* nfc) { } void nfc_scene_mf_classic_update_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dolphin_deed(DolphinDeedNfcEmulate); scene_manager_set_scene_state( @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_update_on_enter(void* context) { } bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -87,7 +87,7 @@ bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event } void nfc_scene_mf_classic_update_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_worker_stop(nfc->worker); scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfClassicUpdate, NfcSceneMfClassicUpdateStateCardSearch); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c index 1f367caa0bb..fb1868459d4 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_update_success.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_classic_update_success_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_mf_classic_update_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dolphin_deed(DolphinDeedNfcSave); notification_message(nfc->notifications, &sequence_success); @@ -24,7 +24,7 @@ void nfc_scene_mf_classic_update_success_on_enter(void* context) { } bool nfc_scene_mf_classic_update_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -37,7 +37,7 @@ bool nfc_scene_mf_classic_update_success_on_event(void* context, SceneManagerEve } void nfc_scene_mf_classic_update_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c index e074f8036c5..20ebfcc70a2 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum { @@ -9,13 +9,13 @@ enum { bool nfc_mf_classic_write_worker_callback(NfcWorkerEvent event, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } -static void nfc_scene_mf_classic_write_setup_view(NfcApp* nfc) { +static void nfc_scene_mf_classic_write_setup_view(Nfc* nfc) { Popup* popup = nfc->popup; popup_reset(popup); uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfClassicWrite); @@ -33,7 +33,7 @@ static void nfc_scene_mf_classic_write_setup_view(NfcApp* nfc) { } void nfc_scene_mf_classic_write_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dolphin_deed(DolphinDeedNfcEmulate); scene_manager_set_scene_state( @@ -51,7 +51,7 @@ void nfc_scene_mf_classic_write_on_enter(void* context) { } bool nfc_scene_mf_classic_write_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -80,7 +80,7 @@ bool nfc_scene_mf_classic_write_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_classic_write_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_worker_stop(nfc->worker); scene_manager_set_scene_state( diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c index 695a3c4a740..aeea6eef069 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_fail.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_write_fail_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_write_fail_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Widget* widget = nfc->widget; notification_message(nfc->notifications, &sequence_error); @@ -36,7 +36,7 @@ void nfc_scene_mf_classic_write_fail_on_enter(void* context) { } bool nfc_scene_mf_classic_write_fail_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -52,7 +52,7 @@ bool nfc_scene_mf_classic_write_fail_on_event(void* context, SceneManagerEvent e } void nfc_scene_mf_classic_write_fail_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c index 9acc14b12ec..00030d4fe8c 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_write_success.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_classic_write_success_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_mf_classic_write_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dolphin_deed(DolphinDeedNfcSave); notification_message(nfc->notifications, &sequence_success); @@ -24,7 +24,7 @@ void nfc_scene_mf_classic_write_success_on_enter(void* context) { } bool nfc_scene_mf_classic_write_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -37,7 +37,7 @@ bool nfc_scene_mf_classic_write_success_on_event(void* context, SceneManagerEven } void nfc_scene_mf_classic_write_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c index ac7d6593470..2c56270e36d 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_classic_wrong_card.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_classic_wrong_card_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Widget* widget = nfc->widget; notification_message(nfc->notifications, &sequence_error); @@ -35,7 +35,7 @@ void nfc_scene_mf_classic_wrong_card_on_enter(void* context) { } bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -47,7 +47,7 @@ bool nfc_scene_mf_classic_wrong_card_on_event(void* context, SceneManagerEvent e } void nfc_scene_mf_classic_wrong_card_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } \ No newline at end of file diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c index 2c856157270..882dc5fea8f 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_app.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define TAG "NfcSceneMfDesfireApp" @@ -10,11 +10,11 @@ enum SubmenuIndex { void nfc_scene_mf_desfire_popup_callback(void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } -MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(NfcApp* nfc) { +MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(Nfc* nfc) { uint32_t app_idx = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp) >> 1; MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head; @@ -25,13 +25,13 @@ MifareDesfireApplication* nfc_scene_mf_desfire_app_get_app(NfcApp* nfc) { } void nfc_scene_mf_desfire_app_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_desfire_app_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MifareDesfireApplication* app = nfc_scene_mf_desfire_app_get_app(nfc); if(!app) { popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42); @@ -69,7 +69,7 @@ void nfc_scene_mf_desfire_app_on_enter(void* context) { } bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireApp); @@ -110,7 +110,7 @@ bool nfc_scene_mf_desfire_app_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_mf_desfire_app_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear views popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c index e9e529909dc..c7caee8dc6d 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_data.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define TAG "NfcSceneMfDesfireData" @@ -13,13 +13,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_desfire_data_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = (NfcApp*)context; + Nfc* nfc = (Nfc*)context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_desfire_data_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; @@ -57,7 +57,7 @@ void nfc_scene_mf_desfire_data_on_enter(void* context) { } bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfDesfireData); MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; @@ -95,7 +95,7 @@ bool nfc_scene_mf_desfire_data_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_desfire_data_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear views text_box_reset(nfc->text_box); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c index b3ebe9a469a..9cebefedfa1 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_desfire_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_desfire_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -35,7 +35,7 @@ void nfc_scene_mf_desfire_menu_on_enter(void* context) { } bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -50,9 +50,9 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) } else if(event.event == SubmenuIndexEmulateUid) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexInfo) { @@ -65,7 +65,7 @@ bool nfc_scene_mf_desfire_menu_on_event(void* context, SceneManagerEvent event) } void nfc_scene_mf_desfire_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c index 919070595db..633549eb5d8 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_desfire_read_success.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_desfire_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,42 +13,47 @@ void nfc_scene_mf_desfire_read_success_widget_callback( } void nfc_scene_mf_desfire_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; Widget* widget = nfc->widget; // Prepare string for data display - FuriString* temp_str = furi_string_alloc_printf("\e#MIFARE DESfire\n"); - furi_string_cat_printf(temp_str, "UID:"); - for(size_t i = 0; i < nfc_data->uid_len; i++) { - furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); - } + FuriString* temp_str = NULL; + if(furi_string_size(nfc->dev->dev_data.parsed_data)) { + temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data); + } else { + temp_str = furi_string_alloc_printf("\e#MIFARE DESFire\n"); + furi_string_cat_printf(temp_str, "UID:"); + for(size_t i = 0; i < nfc_data->uid_len; i++) { + furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); + } - uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); - uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; - furi_string_cat_printf(temp_str, "\n%lu", bytes_total); - if(data->version.sw_storage & 1) { - furi_string_push_back(temp_str, '+'); - } - furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); - - uint16_t n_apps = 0; - uint16_t n_files = 0; - for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { - n_apps++; - for(MifareDesfireFile* file = app->file_head; file; file = file->next) { - n_files++; + uint32_t bytes_total = 1UL << (data->version.sw_storage >> 1); + uint32_t bytes_free = data->free_memory ? data->free_memory->bytes : 0; + furi_string_cat_printf(temp_str, "\n%lu", bytes_total); + if(data->version.sw_storage & 1) { + furi_string_push_back(temp_str, '+'); + } + furi_string_cat_printf(temp_str, " bytes, %lu bytes free\n", bytes_free); + + uint16_t n_apps = 0; + uint16_t n_files = 0; + for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { + n_apps++; + for(MifareDesfireFile* file = app->file_head; file; file = file->next) { + n_files++; + } + } + furi_string_cat_printf(temp_str, "%d Application", n_apps); + if(n_apps != 1) { + furi_string_push_back(temp_str, 's'); + } + furi_string_cat_printf(temp_str, ", %d file", n_files); + if(n_files != 1) { + furi_string_push_back(temp_str, 's'); } - } - furi_string_cat_printf(temp_str, "%d Application", n_apps); - if(n_apps != 1) { - furi_string_push_back(temp_str, 's'); - } - furi_string_cat_printf(temp_str, ", %d file", n_files); - if(n_files != 1) { - furi_string_push_back(temp_str, 's'); } notification_message_block(nfc->notifications, &sequence_set_green_255); @@ -67,7 +72,7 @@ void nfc_scene_mf_desfire_read_success_on_enter(void* context) { } bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -87,7 +92,7 @@ bool nfc_scene_mf_desfire_read_success_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_desfire_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c index 7d56cb1483e..8cd223ee64d 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_data.c @@ -1,7 +1,7 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_ultralight_data_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; TextBox* text_box = nfc->text_box; @@ -24,7 +24,7 @@ bool nfc_scene_mf_ultralight_data_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_ultralight_data_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view text_box_reset(nfc->text_box); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c index 192d67bef73..9d8f17f9a2c 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_emulate.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) #define NFC_MF_UL_DATA_CHANGED (1UL) bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* context) { UNUSED(event); - NfcApp* nfc = context; + Nfc* nfc = context; scene_manager_set_scene_state( nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_CHANGED); @@ -13,7 +13,7 @@ bool nfc_mf_ultralight_emulate_worker_callback(NfcWorkerEvent event, void* conte } void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view MfUltralightType type = nfc->dev->dev_data.mf_ul_data.type; @@ -43,7 +43,7 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) { } bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeBack) { @@ -65,7 +65,7 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e } void nfc_scene_mf_ultralight_emulate_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c index e8c87693d46..089187d5bc3 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_key_input.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_ultralight_key_input_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,7 +23,7 @@ void nfc_scene_mf_ultralight_key_input_on_enter(void* context) { } bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -36,7 +36,7 @@ bool nfc_scene_mf_ultralight_key_input_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_ultralight_key_input_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c index 6069ed356c8..b3bd780f4b4 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -9,17 +9,17 @@ enum SubmenuIndex { }; void nfc_scene_mf_ultralight_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_ultralight_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data; - if(!mf_ul_is_full_capture(data)) { + if(!mf_ul_is_full_capture(data) && data->type != MfUltralightTypeULC) { submenu_add_item( submenu, "Unlock", @@ -29,12 +29,14 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { } submenu_add_item( submenu, "Save", SubmenuIndexSave, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); - submenu_add_item( - submenu, - "Emulate", - SubmenuIndexEmulate, - nfc_scene_mf_ultralight_menu_submenu_callback, - nfc); + if(mf_ul_emulation_supported(data)) { + submenu_add_item( + submenu, + "Emulate", + SubmenuIndexEmulate, + nfc_scene_mf_ultralight_menu_submenu_callback, + nfc); + } submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_ultralight_menu_submenu_callback, nfc); @@ -45,7 +47,7 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) { } bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -58,9 +60,9 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even } else if(event.event == SubmenuIndexEmulate) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexUnlock) { @@ -80,7 +82,7 @@ bool nfc_scene_mf_ultralight_menu_on_event(void* context, SceneManagerEvent even } void nfc_scene_mf_ultralight_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c index 4d549989ab4..2ab5e3f3f44 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" typedef enum { NfcSceneMfUlReadStateIdle, @@ -8,7 +8,7 @@ typedef enum { } NfcSceneMfUlReadState; bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(event == NfcWorkerEventMfUltralightPassKey) { memcpy(nfc->dev->dev_data.mf_ul_data.auth_key, nfc->byte_input_store, 4); @@ -18,7 +18,7 @@ bool nfc_scene_mf_ultralight_read_auth_worker_callback(NfcWorkerEvent event, voi return true; } -void nfc_scene_mf_ultralight_read_auth_set_state(NfcApp* nfc, NfcSceneMfUlReadState state) { +void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState state) { uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth); if(curr_state != state) { @@ -53,7 +53,7 @@ void nfc_scene_mf_ultralight_read_auth_set_state(NfcApp* nfc, NfcSceneMfUlReadSt } void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_device_clear(nfc->dev); // Setup view @@ -69,7 +69,7 @@ void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) { } bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -104,7 +104,7 @@ bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent } void nfc_scene_mf_ultralight_read_auth_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c index c3ea1522fac..b125e999127 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_auth_result.c @@ -1,10 +1,10 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_ultralight_read_auth_result_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -12,7 +12,7 @@ void nfc_scene_mf_ultralight_read_auth_result_widget_callback( } void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup dialog view FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; @@ -74,7 +74,7 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) { } bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -107,7 +107,7 @@ bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManag } void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean views widget_reset(nfc->widget); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c index 60c8191e5a1..cb5ccd6e826 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_read_success.c @@ -1,10 +1,10 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mf_ultralight_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -12,7 +12,7 @@ void nfc_scene_mf_ultralight_read_success_widget_callback( } void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup widget view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; @@ -55,7 +55,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) { } bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -75,7 +75,7 @@ bool nfc_scene_mf_ultralight_read_success_on_event(void* context, SceneManagerEv } void nfc_scene_mf_ultralight_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c index 24f1703a28f..c59fe3a7d09 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_auto.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" bool nfc_scene_mf_ultralight_unlock_auto_worker_callback(NfcWorkerEvent event, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, event); return true; } void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view widget_add_string_multiline_element( @@ -35,7 +35,7 @@ void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) { } bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -53,7 +53,7 @@ bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEve } void nfc_scene_mf_ultralight_unlock_auto_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c index 5c0604d383c..484629b0bbe 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" enum SubmenuIndex { SubmenuIndexMfUlUnlockMenuAuto, @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; uint32_t state = @@ -50,7 +50,7 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) { } bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -77,7 +77,7 @@ bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEve } void nfc_scene_mf_ultralight_unlock_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 4c8a1c90ff9..af2eca0ce5d 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method; @@ -52,7 +52,7 @@ void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) { } bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; @@ -61,7 +61,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultRight) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); consumed = true; } else if(event.event == DialogExResultLeft) { if(auth_method == MfUltralightAuthMethodAuto) { @@ -79,7 +79,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultCenter) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth); - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); consumed = true; } } @@ -89,7 +89,7 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve } void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; dialog_ex_reset(nfc->dialog_ex); nfc_text_store_clear(nfc); diff --git a/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c b/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c index b6ca75ee933..04515f24ff6 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mfkey_complete.c @@ -1,14 +1,14 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_mfkey_complete_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mfkey_complete_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_add_string_element(nfc->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Complete!"); widget_add_string_multiline_element( @@ -26,7 +26,7 @@ void nfc_scene_mfkey_complete_on_enter(void* context) { } bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -43,7 +43,7 @@ bool nfc_scene_mfkey_complete_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_mfkey_complete_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c b/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c index 5e86f2376fd..6d9852f3e66 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_mfkey_nonces_info.c @@ -1,15 +1,15 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include void nfc_scene_mfkey_nonces_info_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } void nfc_scene_mfkey_nonces_info_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; FuriString* temp_str; temp_str = furi_string_alloc(); @@ -31,7 +31,7 @@ void nfc_scene_mfkey_nonces_info_on_enter(void* context) { } bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -48,7 +48,7 @@ bool nfc_scene_mfkey_nonces_info_on_event(void* context, SceneManagerEvent event } void nfc_scene_mfkey_nonces_info_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view widget_reset(nfc->widget); diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c index 734a9a8ce92..66a9174df47 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfc_data_info.c @@ -1,14 +1,91 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_nfc_data_info_widget_callback(GuiButtonType result, InputType type, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } } +void nfc_scene_slix_build_string( + FuriString* temp_str, + NfcVData* nfcv_data, + SlixTypeFeatures features, + const char* type) { + furi_string_cat_printf(temp_str, "Type: %s\n", type); + furi_string_cat_printf(temp_str, "Keys:\n"); + if(features & SlixFeatureRead) { + furi_string_cat_printf( + temp_str, + " Read %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyRead) ? "" : " (unset)"); + } + if(features & SlixFeatureWrite) { + furi_string_cat_printf( + temp_str, + " Write %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyWrite) ? "" : " (unset)"); + } + if(features & SlixFeaturePrivacy) { + furi_string_cat_printf( + temp_str, + " Privacy %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyPrivacy) ? "" : " (unset)"); + furi_string_cat_printf( + temp_str, + " Privacy mode %s\n", + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsPrivacy) ? "ENABLED" : "DISABLED"); + } + if(features & SlixFeatureDestroy) { + furi_string_cat_printf( + temp_str, + " Destroy %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyDestroy) ? "" : " (unset)"); + } + if(features & SlixFeatureEas) { + furi_string_cat_printf( + temp_str, + " EAS %08llX%s\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4), + (nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsHasKeyEas) ? "" : " (unset)"); + } + if(features & SlixFeatureSignature) { + furi_string_cat_printf( + temp_str, + "Signature %08llX...\n", + nfc_util_bytes2num(nfcv_data->sub_data.slix.signature, 4)); + } + furi_string_cat_printf( + temp_str, + "DSFID: %02X %s\n", + nfcv_data->dsfid, + (nfcv_data->security_status[0] & NfcVLockBitDsfid) ? "(locked)" : ""); + furi_string_cat_printf( + temp_str, + "AFI: %02X %s\n", + nfcv_data->afi, + (nfcv_data->security_status[0] & NfcVLockBitAfi) ? "(locked)" : ""); + furi_string_cat_printf( + temp_str, + "EAS: %s\n", + (nfcv_data->security_status[0] & NfcVLockBitEas) ? "locked" : "not locked"); + + if(features & SlixFeatureProtection) { + furi_string_cat_printf( + temp_str, + "PPL: %s\n", + (nfcv_data->security_status[0] & NfcVLockBitPpl) ? "locked" : "not locked"); + furi_string_cat_printf(temp_str, "Prot.ptr %02X\n", nfcv_data->sub_data.slix.pp_pointer); + furi_string_cat_printf(temp_str, "Prot.con %02X\n", nfcv_data->sub_data.slix.pp_condition); + } +} + void nfc_scene_nfc_data_info_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Widget* widget = nfc->widget; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; NfcDeviceData* dev_data = &nfc->dev->dev_data; @@ -76,95 +153,25 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } furi_string_cat_printf(temp_str, "\n"); - furi_string_cat_printf( - temp_str, - "DSFID: %02X %s\n", - nfcv_data->dsfid, - (nfcv_data->security_status[0] & NfcVLockBitDsfid) ? "(locked)" : ""); - furi_string_cat_printf( - temp_str, - "AFI: %02X %s\n", - nfcv_data->afi, - (nfcv_data->security_status[0] & NfcVLockBitAfi) ? "(locked)" : ""); - furi_string_cat_printf(temp_str, "IC Ref: %02X\n", nfcv_data->ic_ref); - furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num); - furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size); + furi_string_cat_printf(temp_str, "IC Ref: %d\n", nfcv_data->ic_ref); + furi_string_cat_printf(temp_str, "Blocks: %d\n", nfcv_data->block_num); + furi_string_cat_printf(temp_str, "Blocksize: %d\n", nfcv_data->block_size); switch(dev_data->nfcv_data.sub_type) { case NfcVTypePlain: furi_string_cat_printf(temp_str, "Type: Plain\n"); break; case NfcVTypeSlix: - furi_string_cat_printf(temp_str, "Type: SLIX\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " EAS %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + nfc_scene_slix_build_string(temp_str, nfcv_data, SlixFeatureSlix, "SLIX"); break; case NfcVTypeSlixS: - furi_string_cat_printf(temp_str, "Type: SLIX-S\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " Read %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4)); - furi_string_cat_printf( - temp_str, - " Write %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4)); - furi_string_cat_printf( - temp_str, - " Privacy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4)); - furi_string_cat_printf( - temp_str, - " Destroy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4)); - furi_string_cat_printf( - temp_str, - " EAS %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + nfc_scene_slix_build_string(temp_str, nfcv_data, SlixFeatureSlixS, "SLIX-S"); break; case NfcVTypeSlixL: - furi_string_cat_printf(temp_str, "Type: SLIX-L\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " Privacy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4)); - furi_string_cat_printf( - temp_str, - " Destroy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4)); - furi_string_cat_printf( - temp_str, - " EAS %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + nfc_scene_slix_build_string(temp_str, nfcv_data, SlixFeatureSlixL, "SLIX-L"); break; case NfcVTypeSlix2: - furi_string_cat_printf(temp_str, "Type: SLIX2\n"); - furi_string_cat_printf(temp_str, "Keys:\n"); - furi_string_cat_printf( - temp_str, - " Read %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_read, 4)); - furi_string_cat_printf( - temp_str, - " Write %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_write, 4)); - furi_string_cat_printf( - temp_str, - " Privacy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_privacy, 4)); - furi_string_cat_printf( - temp_str, - " Destroy %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_destroy, 4)); - furi_string_cat_printf( - temp_str, - " EAS %08llX\n", - nfc_util_bytes2num(nfcv_data->sub_data.slix.key_eas, 4)); + nfc_scene_slix_build_string(temp_str, nfcv_data, SlixFeatureSlix2, "SLIX2"); break; default: furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); @@ -253,11 +260,11 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } } else if(protocol == NfcDeviceProtocolMifareClassic) { MfClassicData* data = &dev_data->mf_classic_data; - uint8_t sectors_total = mifare_classic_get_total_sectors_num(data->type); + uint8_t sectors_total = mf_classic_get_total_sectors_num(data->type); uint8_t keys_total = sectors_total * 2; uint8_t keys_found = 0; uint8_t sectors_read = 0; - mifare_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); + mf_classic_get_read_sectors_and_keys(data, §ors_read, &keys_found); furi_string_cat_printf(temp_str, "\nKeys Found %d/%d", keys_found, keys_total); furi_string_cat_printf(temp_str, "\nSectors Read %d/%d", sectors_read, sectors_total); } @@ -271,7 +278,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { } bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcProtocol protocol = nfc->dev->dev_data.protocol; bool consumed = false; @@ -296,7 +303,7 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_nfc_data_info_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; widget_reset(nfc->widget); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c b/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c index 702325a782b..9779470a387 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfca_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_nfca_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_nfca_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -30,7 +30,7 @@ void nfc_scene_nfca_menu_on_enter(void* context) { } bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -43,9 +43,9 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { } else if(event.event == SubmenuIndexEmulateUid) { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddEmulate); + dolphin_deed(DolphinDeedNfcAddEmulate); } else { - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); } consumed = true; } else if(event.event == SubmenuIndexInfo) { @@ -61,7 +61,7 @@ bool nfc_scene_nfca_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_nfca_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view submenu_reset(nfc->submenu); diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c index 089ee067c11..a38f31a9813 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfca_read_success.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_nfca_read_success_widget_callback( GuiButtonType result, InputType type, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_nfca_read_success_widget_callback( } void nfc_scene_nfca_read_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view FuriHalNfcDevData* data = &nfc->dev->dev_data.nfc_data; @@ -45,7 +45,7 @@ void nfc_scene_nfca_read_success_on_enter(void* context) { } bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -64,7 +64,7 @@ bool nfc_scene_nfca_read_success_on_event(void* context, SceneManagerEvent event } void nfc_scene_nfca_read_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; notification_message_block(nfc->notifications, &sequence_reset_green); diff --git a/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c b/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c index bdf7692ccb2..04e60611d00 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_nfcv_read_success.c @@ -16,7 +16,6 @@ void nfc_scene_nfcv_read_success_on_enter(void* context) { Nfc* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; FuriHalNfcDevData* nfc_data = &nfc->dev->dev_data.nfc_data; - NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data; // Setup view Widget* widget = nfc->widget; widget_add_button_element( @@ -46,13 +45,12 @@ void nfc_scene_nfcv_read_success_on_enter(void* context) { furi_string_cat_printf(temp_str, "\e#ISO15693 (unknown)\n"); break; } - furi_string_cat_printf(temp_str, "UID:"); + furi_string_cat_printf(temp_str, "UID:\n"); for(size_t i = 0; i < nfc_data->uid_len; i++) { furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]); } furi_string_cat_printf(temp_str, "\n"); - furi_string_cat_printf(temp_str, "Blocks: %02X\n", nfcv_data->block_num); - furi_string_cat_printf(temp_str, "Blocksize: %02X\n", nfcv_data->block_size); + furi_string_cat_printf(temp_str, "(see More->Info for details)\n"); widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str)); furi_string_free(temp_str); diff --git a/applications/main/nfc_old/scenes/nfc_scene_read.c b/applications/main/nfc_old/scenes/nfc_scene_read.c index 57396a0e084..1690a955757 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_read.c +++ b/applications/main/nfc_old/scenes/nfc_scene_read.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include typedef enum { @@ -8,7 +8,7 @@ typedef enum { } NfcSceneReadState; bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event == NfcWorkerEventReadMfClassicLoadKeyCache) { consumed = nfc_device_load_key_cache(nfc->dev); @@ -19,7 +19,7 @@ bool nfc_scene_read_worker_callback(NfcWorkerEvent event, void* context) { return consumed; } -void nfc_scene_read_set_state(NfcApp* nfc, NfcSceneReadState state) { +void nfc_scene_read_set_state(Nfc* nfc, NfcSceneReadState state) { uint32_t curr_state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneRead); if(curr_state != state) { if(state == NfcSceneReadStateDetecting) { @@ -38,7 +38,7 @@ void nfc_scene_read_set_state(NfcApp* nfc, NfcSceneReadState state) { } void nfc_scene_read_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; nfc_device_clear(nfc->dev); // Setup view @@ -52,7 +52,7 @@ void nfc_scene_read_on_enter(void* context) { } bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -90,11 +90,6 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireReadSuccess); dolphin_deed(DolphinDeedNfcReadSuccess); consumed = true; - } else if(event.event == NfcWorkerEventReadBankCard) { - notification_message(nfc->notifications, &sequence_success); - scene_manager_next_scene(nfc->scene_manager, NfcSceneEmvReadSuccess); - DOLPHIN_DEED(DolphinDeedNfcReadSuccess); - consumed = true; } else if(event.event == NfcWorkerEventReadMfClassicDictAttackRequired) { if(mf_classic_dict_check_presence(MfClassicDictTypeSystem)) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicDictAttack); @@ -116,7 +111,7 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_read_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Stop worker nfc_worker_stop(nfc->worker); diff --git a/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c b/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c index 009de9c966f..ee80ee76883 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_read_card_success.c @@ -1,11 +1,11 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_read_card_success_widget_callback( GuiButtonType result, InputType type, void* context) { furi_assert(context); - NfcApp* nfc = context; + Nfc* nfc = context; if(type == InputTypeShort) { view_dispatcher_send_custom_event(nfc->view_dispatcher, result); @@ -13,7 +13,7 @@ void nfc_scene_read_card_success_widget_callback( } void nfc_scene_read_card_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; FuriString* temp_str; temp_str = furi_string_alloc(); @@ -39,7 +39,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { } bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -54,7 +54,7 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event } void nfc_scene_read_card_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view widget_reset(nfc->widget); diff --git a/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c b/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c index d763f2f723d..8023026c3da 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c +++ b/applications/main/nfc_old/scenes/nfc_scene_read_card_type.c @@ -1,22 +1,21 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "nfc_worker_i.h" enum SubmenuIndex { SubmenuIndexReadMifareClassic, SubmenuIndexReadMifareDesfire, SubmenuIndexReadMfUltralight, - SubmenuIndexReadEMV, SubmenuIndexReadNFCA, }; void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_read_card_type_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item( @@ -37,12 +36,6 @@ void nfc_scene_read_card_type_on_enter(void* context) { SubmenuIndexReadMfUltralight, nfc_scene_read_card_type_submenu_callback, nfc); - submenu_add_item( - submenu, - "Read EMV card", - SubmenuIndexReadEMV, - nfc_scene_read_card_type_submenu_callback, - nfc); submenu_add_item( submenu, "Read NFC-A data", @@ -56,7 +49,7 @@ void nfc_scene_read_card_type_on_enter(void* context) { } bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -75,11 +68,6 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); consumed = true; } - if(event.event == SubmenuIndexReadEMV) { - nfc->dev->dev_data.read_mode = NfcReadModeEMV; - scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); - consumed = true; - } if(event.event == SubmenuIndexReadNFCA) { nfc->dev->dev_data.read_mode = NfcReadModeNFCA; scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); @@ -91,7 +79,7 @@ bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_read_card_type_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_restore_original.c b/applications/main/nfc_old/scenes/nfc_scene_restore_original.c index f059eeac497..3ecf5c048e4 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_restore_original.c +++ b/applications/main/nfc_old/scenes/nfc_scene_restore_original.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_restore_original_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_restore_original_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_restore_original_on_enter(void* context) { } bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -38,7 +38,7 @@ bool nfc_scene_restore_original_on_event(void* context, SceneManagerEvent event) } void nfc_scene_restore_original_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c index e5570bd0df1..16b0953f809 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c +++ b/applications/main/nfc_old/scenes/nfc_scene_restore_original_confirm.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_restore_original_confirm_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_restore_original_confirm_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_header(dialog_ex, "Restore Card Data?", 64, 0, AlignCenter, AlignTop); @@ -23,7 +23,7 @@ void nfc_scene_restore_original_confirm_on_enter(void* context) { } bool nfc_scene_restore_original_confirm_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -46,7 +46,7 @@ bool nfc_scene_restore_original_confirm_on_event(void* context, SceneManagerEven } void nfc_scene_restore_original_confirm_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c b/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c index 9f37c41588b..5f4f7985e77 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c +++ b/applications/main/nfc_old/scenes/nfc_scene_retry_confirm.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_retry_confirm_dialog_callback(DialogExResult result, void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, result); } void nfc_scene_retry_confirm_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; DialogEx* dialog_ex = nfc->dialog_ex; dialog_ex_set_left_button_text(dialog_ex, "Retry"); @@ -22,7 +22,7 @@ void nfc_scene_retry_confirm_on_enter(void* context) { } bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -40,7 +40,7 @@ bool nfc_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_retry_confirm_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clean view dialog_ex_reset(nfc->dialog_ex); diff --git a/applications/main/nfc_old/scenes/nfc_scene_rpc.c b/applications/main/nfc_old/scenes/nfc_scene_rpc.c index fa01cf41dbd..d06ee756465 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_rpc.c +++ b/applications/main/nfc_old/scenes/nfc_scene_rpc.c @@ -1,7 +1,7 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_rpc_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Popup* popup = nfc->popup; popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom); @@ -16,14 +16,14 @@ void nfc_scene_rpc_on_enter(void* context) { static bool nfc_scene_rpc_emulate_callback(NfcWorkerEvent event, void* context) { UNUSED(event); - NfcApp* nfc = context; + Nfc* nfc = context; nfc->rpc_state = NfcRpcStateEmulated; return true; } bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; Popup* popup = nfc->popup; bool consumed = false; @@ -82,7 +82,7 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_rpc_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Popup* popup = nfc->popup; nfc_blink_stop(nfc); diff --git a/applications/main/nfc_old/scenes/nfc_scene_save_name.c b/applications/main/nfc_old/scenes/nfc_scene_save_name.c index 41fbb8833de..a7b97aac06b 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_save_name.c +++ b/applications/main/nfc_old/scenes/nfc_scene_save_name.c @@ -1,17 +1,17 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include #include #include #include void nfc_scene_save_name_text_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventTextInputDone); } void nfc_scene_save_name_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view TextInput* text_input = nfc->text_input; @@ -50,7 +50,7 @@ void nfc_scene_save_name_on_enter(void* context) { } bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -67,9 +67,9 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) { // Nothing, do not count editing as saving } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { - DOLPHIN_DEED(DolphinDeedNfcAddSave); + dolphin_deed(DolphinDeedNfcAddSave); } else { - DOLPHIN_DEED(DolphinDeedNfcSave); + dolphin_deed(DolphinDeedNfcSave); } consumed = true; } else { @@ -82,7 +82,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_save_name_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view void* validator_context = text_input_get_validator_callback_context(nfc->text_input); diff --git a/applications/main/nfc_old/scenes/nfc_scene_save_success.c b/applications/main/nfc_old/scenes/nfc_scene_save_success.c index 4c19f2f42e0..34919cbd863 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_save_success.c +++ b/applications/main/nfc_old/scenes/nfc_scene_save_success.c @@ -1,12 +1,12 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_save_success_popup_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); } void nfc_scene_save_success_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view Popup* popup = nfc->popup; @@ -20,7 +20,7 @@ void nfc_scene_save_success_on_enter(void* context) { } bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -41,7 +41,7 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_save_success_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view popup_reset(nfc->popup); diff --git a/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c b/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c index 04576033858..b3205554a43 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc_old/scenes/nfc_scene_saved_menu.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include enum SubmenuIndex { @@ -16,13 +16,13 @@ enum SubmenuIndex { }; void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_saved_menu_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; if(nfc->dev->format == NfcDeviceSaveFormatUid || @@ -42,13 +42,15 @@ void nfc_scene_saved_menu_on_enter(void* context) { nfc); } } else if( - nfc->dev->format == NfcDeviceSaveFormatMifareUl || + (nfc->dev->format == NfcDeviceSaveFormatMifareUl && + mf_ul_emulation_supported(&nfc->dev->dev_data.mf_ul_data)) || + nfc->dev->format == NfcDeviceSaveFormatNfcV || nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { submenu_add_item( submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); } if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { - if(!mifare_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { + if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) { submenu_add_item( submenu, "Detect Reader", @@ -72,6 +74,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { submenu_add_item( submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc); if(nfc->dev->format == NfcDeviceSaveFormatMifareUl && + nfc->dev->dev_data.mf_ul_data.type != MfUltralightTypeULC && !mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) { submenu_add_item( submenu, @@ -105,7 +108,7 @@ void nfc_scene_saved_menu_on_enter(void* context) { } bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; NfcDeviceData* dev_data = &nfc->dev->dev_data; bool consumed = false; @@ -116,14 +119,16 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightEmulate); } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate); + } else if(nfc->dev->format == NfcDeviceSaveFormatNfcV) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVEmulate); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); } - DOLPHIN_DEED(DolphinDeedNfcEmulate); + dolphin_deed(DolphinDeedNfcEmulate); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); + dolphin_deed(DolphinDeedNfcDetectReader); consumed = true; } else if(event.event == SubmenuIndexWrite) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite); @@ -146,6 +151,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { application_info_present = true; } else if( dev_data->protocol == NfcDeviceProtocolMifareClassic || + dev_data->protocol == NfcDeviceProtocolMifareDesfire || dev_data->protocol == NfcDeviceProtocolMifareUl) { application_info_present = nfc_supported_card_verify_and_parse(dev_data); } @@ -174,7 +180,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_saved_menu_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c b/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c index 4e0e11e7877..d079b380475 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c +++ b/applications/main/nfc_old/scenes/nfc_scene_set_atqa.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_set_atqa_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_atqa_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,7 +23,7 @@ void nfc_scene_set_atqa_on_enter(void* context) { } bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -36,7 +36,7 @@ bool nfc_scene_set_atqa_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_atqa_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_sak.c b/applications/main/nfc_old/scenes/nfc_scene_set_sak.c index 2c4a230cc4f..60a1e1494b8 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_set_sak.c +++ b/applications/main/nfc_old/scenes/nfc_scene_set_sak.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_set_sak_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_sak_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -23,7 +23,7 @@ void nfc_scene_set_sak_on_enter(void* context) { } bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -36,7 +36,7 @@ bool nfc_scene_set_sak_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_sak_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_type.c b/applications/main/nfc_old/scenes/nfc_scene_set_type.c index 9e417939d62..cadf2eb69ef 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_set_type.c +++ b/applications/main/nfc_old/scenes/nfc_scene_set_type.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "lib/nfc/helpers/nfc_generators.h" enum SubmenuIndex { @@ -8,13 +8,13 @@ enum SubmenuIndex { }; void nfc_scene_set_type_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_set_type_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; // Clear device name nfc_device_set_name(nfc->dev, ""); @@ -35,7 +35,7 @@ void nfc_scene_set_type_on_enter(void* context) { } bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -62,7 +62,7 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_type_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/scenes/nfc_scene_set_uid.c b/applications/main/nfc_old/scenes/nfc_scene_set_uid.c index 4c2dc7d0493..54606b68eec 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_set_uid.c +++ b/applications/main/nfc_old/scenes/nfc_scene_set_uid.c @@ -1,13 +1,13 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" void nfc_scene_set_uid_byte_input_callback(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone); } void nfc_scene_set_uid_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Setup view ByteInput* byte_input = nfc->byte_input; @@ -24,7 +24,7 @@ void nfc_scene_set_uid_on_enter(void* context) { } bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = (NfcApp*)context; + Nfc* nfc = (Nfc*)context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -46,7 +46,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_set_uid_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; // Clear view byte_input_set_result_callback(nfc->byte_input, NULL, NULL, NULL, NULL, 0); diff --git a/applications/main/nfc_old/scenes/nfc_scene_start.c b/applications/main/nfc_old/scenes/nfc_scene_start.c index d528e2bb680..c9e8bf78cf5 100644 --- a/applications/main/nfc_old/scenes/nfc_scene_start.c +++ b/applications/main/nfc_old/scenes/nfc_scene_start.c @@ -1,4 +1,4 @@ -#include "../nfc_app_i.h" +#include "../nfc_i.h" #include "nfc_worker_i.h" #include @@ -12,13 +12,13 @@ enum SubmenuIndex { }; void nfc_scene_start_submenu_callback(void* context, uint32_t index) { - NfcApp* nfc = context; + Nfc* nfc = context; view_dispatcher_send_custom_event(nfc->view_dispatcher, index); } void nfc_scene_start_on_enter(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; Submenu* submenu = nfc->submenu; submenu_add_item(submenu, "Read", SubmenuIndexRead, nfc_scene_start_submenu_callback, nfc); @@ -43,7 +43,7 @@ void nfc_scene_start_on_enter(void* context) { } bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { - NfcApp* nfc = context; + Nfc* nfc = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { @@ -51,7 +51,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); nfc->dev->dev_data.read_mode = NfcReadModeAuto; scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); - DOLPHIN_DEED(DolphinDeedNfcRead); + dolphin_deed(DolphinDeedNfcRead); consumed = true; } else if(event.event == SubmenuIndexDetectReader) { scene_manager_set_scene_state( @@ -60,7 +60,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { if(sd_exist) { nfc_device_data_clear(&nfc->dev->dev_data); scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader); - DOLPHIN_DEED(DolphinDeedNfcDetectReader); + dolphin_deed(DolphinDeedNfcDetectReader); } else { scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); } @@ -92,7 +92,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { } void nfc_scene_start_on_exit(void* context) { - NfcApp* nfc = context; + Nfc* nfc = context; submenu_reset(nfc->submenu); } diff --git a/applications/main/nfc_old/views/dict_attack.c b/applications/main/nfc_old/views/dict_attack.c index dd6b919f089..8f4bd063e8b 100644 --- a/applications/main/nfc_old/views/dict_attack.c +++ b/applications/main/nfc_old/views/dict_attack.c @@ -169,7 +169,7 @@ void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) DictAttackViewModel * model, { model->state = DictAttackStateRead; - model->sectors_total = mifare_classic_get_total_sectors_num(type); + model->sectors_total = mf_classic_get_total_sectors_num(type); model->keys_total = model->sectors_total * 2; }, true); diff --git a/applications/main/nfc_old/views/dict_attack.h b/applications/main/nfc_old/views/dict_attack.h index 181cbbae557..73b98a1b827 100644 --- a/applications/main/nfc_old/views/dict_attack.h +++ b/applications/main/nfc_old/views/dict_attack.h @@ -3,7 +3,7 @@ #include #include -#include +#include typedef struct DictAttack DictAttack; diff --git a/applications/main/subghz/helpers/subghz_chat.c b/applications/main/subghz/helpers/subghz_chat.c index dbf34c97051..bbe219fd2f7 100644 --- a/applications/main/subghz/helpers/subghz_chat.c +++ b/applications/main/subghz/helpers/subghz_chat.c @@ -76,12 +76,15 @@ void subghz_chat_worker_free(SubGhzChatWorker* instance) { free(instance); } -bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency) { +bool subghz_chat_worker_start( + SubGhzChatWorker* instance, + const SubGhzDevice* device, + uint32_t frequency) { furi_assert(instance); furi_assert(!instance->worker_running); bool res = false; - if(subghz_tx_rx_worker_start(instance->subghz_txrx, frequency)) { + if(subghz_tx_rx_worker_start(instance->subghz_txrx, device, frequency)) { furi_message_queue_reset(instance->event_queue); subghz_tx_rx_worker_set_callback_have_read( instance->subghz_txrx, subghz_chat_worker_update_rx_event_chat, instance); diff --git a/applications/main/subghz/helpers/subghz_chat.h b/applications/main/subghz/helpers/subghz_chat.h index b418bbdbffc..2c454b75d98 100644 --- a/applications/main/subghz/helpers/subghz_chat.h +++ b/applications/main/subghz/helpers/subghz_chat.h @@ -1,5 +1,6 @@ #pragma once #include "../subghz_i.h" +#include #include typedef struct SubGhzChatWorker SubGhzChatWorker; @@ -20,7 +21,10 @@ typedef struct { SubGhzChatWorker* subghz_chat_worker_alloc(Cli* cli); void subghz_chat_worker_free(SubGhzChatWorker* instance); -bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency); +bool subghz_chat_worker_start( + SubGhzChatWorker* instance, + const SubGhzDevice* device, + uint32_t frequency); void subghz_chat_worker_stop(SubGhzChatWorker* instance); bool subghz_chat_worker_is_running(SubGhzChatWorker* instance); SubGhzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance); diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h b/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h index b94ebe3809d..df53143d23f 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_log_item_array.h @@ -27,10 +27,15 @@ TUPLE_DEF2( (rssi_max, uint8_t)) /* Register globally the oplist */ #define M_OPL_SubGhzFrequencyAnalyzerLogItem_t() \ - TUPLE_OPLIST(SubGhzFrequencyAnalyzerLogItem, M_POD_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST) + TUPLE_OPLIST( \ + SubGhzFrequencyAnalyzerLogItem, \ + M_DEFAULT_OPLIST, \ + M_DEFAULT_OPLIST, \ + M_DEFAULT_OPLIST, \ + M_DEFAULT_OPLIST) /* Define the array, register the oplist and define further algorithms on it */ -ARRAY_DEF(SubGhzFrequencyAnalyzerLogItemArray, SubGhzFrequencyAnalyzerLogItem_t) +ARRAY_DEF(SubGhzFrequencyAnalyzerLogItemArray, SubGhzFrequencyAnalyzerLogItem_t) //-V779 #define M_OPL_SubGhzFrequencyAnalyzerLogItemArray_t() \ ARRAY_OPLIST(SubGhzFrequencyAnalyzerLogItemArray, M_OPL_SubGhzFrequencyAnalyzerLogItem_t()) ALGO_DEF(SubGhzFrequencyAnalyzerLogItemArray, SubGhzFrequencyAnalyzerLogItemArray_t) diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.c b/applications/main/subghz/helpers/subghz_threshold_rssi.c index 04a06bc1736..07d7bccf93d 100644 --- a/applications/main/subghz/helpers/subghz_threshold_rssi.c +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.c @@ -32,9 +32,8 @@ float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) { return instance->threshold_rssi; } -SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) { +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance, float rssi) { furi_assert(instance); - float rssi = furi_hal_subghz_get_rssi(); SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false}; if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) { diff --git a/applications/main/subghz/helpers/subghz_threshold_rssi.h b/applications/main/subghz/helpers/subghz_threshold_rssi.h index e28092acbc0..1d588e271b3 100644 --- a/applications/main/subghz/helpers/subghz_threshold_rssi.h +++ b/applications/main/subghz/helpers/subghz_threshold_rssi.h @@ -38,6 +38,7 @@ float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance); /** Check threshold * * @param instance Pointer to a SubGhzThresholdRssi + * @param rssi Current RSSI * @return SubGhzThresholdRssiData */ -SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance); +SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance, float rssi); diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index 1517cb99892..b911f443459 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -1,9 +1,26 @@ #include "subghz_txrx_i.h" #include +#include +#include #define TAG "SubGhz" +static void subghz_txrx_radio_device_power_on(SubGhzTxRx* instance) { + UNUSED(instance); + uint8_t attempts = 0; + while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { + furi_hal_power_enable_otg(); + //CC1101 power-up time + furi_delay_ms(10); + } +} + +static void subghz_txrx_radio_device_power_off(SubGhzTxRx* instance) { + UNUSED(instance); + if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg(); +} + SubGhzTxRx* subghz_txrx_alloc() { SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx)); instance->setting = subghz_setting_alloc(); @@ -23,16 +40,15 @@ SubGhzTxRx* subghz_txrx_alloc() { instance->fff_data = flipper_format_string_alloc(); instance->environment = subghz_environment_alloc(); - instance->is_database_loaded = subghz_environment_load_keystore( - instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore( - instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + instance->is_database_loaded = + subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_NAME); + subghz_environment_load_keystore(instance->environment, SUBGHZ_KEYSTORE_DIR_USER_NAME); subghz_environment_set_came_atomo_rainbow_table_file_name( - instance->environment, EXT_PATH("subghz/assets/came_atomo")); + instance->environment, SUBGHZ_CAME_ATOMO_DIR_NAME); subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - instance->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + instance->environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME); subghz_environment_set_nice_flor_s_rainbow_table_file_name( - instance->environment, EXT_PATH("subghz/assets/nice_flor_s")); + instance->environment, SUBGHZ_NICE_FLOR_S_DIR_NAME); subghz_environment_set_protocol_registry( instance->environment, (void*)&subghz_protocol_registry); instance->receiver = subghz_receiver_alloc_init(instance->environment); @@ -43,18 +59,32 @@ SubGhzTxRx* subghz_txrx_alloc() { instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); subghz_worker_set_context(instance->worker, instance->receiver); + //set default device External + subghz_devices_init(); + instance->radio_device_type = SubGhzRadioDeviceTypeInternal; + instance->radio_device_type = + subghz_txrx_radio_device_set(instance, SubGhzRadioDeviceTypeExternalCC1101); + return instance; } void subghz_txrx_free(SubGhzTxRx* instance) { furi_assert(instance); + if(instance->radio_device_type != SubGhzRadioDeviceTypeInternal) { + subghz_txrx_radio_device_power_off(instance); + subghz_devices_end(instance->radio_device); + } + + subghz_devices_deinit(); + subghz_worker_free(instance->worker); subghz_receiver_free(instance->receiver); subghz_environment_free(instance->environment); flipper_format_free(instance->fff_data); furi_string_free(instance->preset->name); subghz_setting_free(instance->setting); + free(instance->preset); free(instance); } @@ -122,29 +152,26 @@ void subghz_txrx_get_frequency_and_modulation( static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) { furi_assert(instance); - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_custom_preset(preset_data); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + subghz_devices_reset(instance->radio_device); + subghz_devices_idle(instance->radio_device); + subghz_devices_load_preset(instance->radio_device, FuriHalSubGhzPresetCustom, preset_data); instance->txrx_state = SubGhzTxRxStateIDLE; } static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { furi_assert(instance); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect RX frequency."); - } + furi_assert( instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); - furi_hal_subghz_flush_rx(); + subghz_devices_idle(instance->radio_device); + + uint32_t value = subghz_devices_set_frequency(instance->radio_device, frequency); + subghz_devices_flush_rx(instance->radio_device); subghz_txrx_speaker_on(instance); - furi_hal_subghz_rx(); - furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker); + subghz_devices_start_async_rx( + instance->radio_device, subghz_worker_rx_callback, instance->worker); subghz_worker_start(instance->worker); instance->txrx_state = SubGhzTxRxStateRx; return value; @@ -153,7 +180,7 @@ static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { static void subghz_txrx_idle(SubGhzTxRx* instance) { furi_assert(instance); furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); + subghz_devices_idle(instance->radio_device); subghz_txrx_speaker_off(instance); instance->txrx_state = SubGhzTxRxStateIDLE; } @@ -164,30 +191,26 @@ static void subghz_txrx_rx_end(SubGhzTxRx* instance) { if(subghz_worker_is_running(instance->worker)) { subghz_worker_stop(instance->worker); - furi_hal_subghz_stop_async_rx(); + subghz_devices_stop_async_rx(instance->radio_device); } - furi_hal_subghz_idle(); + subghz_devices_idle(instance->radio_device); subghz_txrx_speaker_off(instance); instance->txrx_state = SubGhzTxRxStateIDLE; } void subghz_txrx_sleep(SubGhzTxRx* instance) { furi_assert(instance); - furi_hal_subghz_sleep(); + subghz_devices_sleep(instance->radio_device); instance->txrx_state = SubGhzTxRxStateSleep; } static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { furi_assert(instance); - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - furi_crash("SubGhz: Incorrect TX frequency."); - } furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); - furi_hal_subghz_idle(); - furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_write(&gpio_cc1101_g0, false); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); - bool ret = furi_hal_subghz_tx(); + subghz_devices_idle(instance->radio_device); + subghz_devices_set_frequency(instance->radio_device, frequency); + + bool ret = subghz_devices_set_tx(instance->radio_device); if(ret) { subghz_txrx_speaker_on(instance); instance->txrx_state = SubGhzTxRxStateTx; @@ -249,8 +272,8 @@ SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* if(ret == SubGhzTxRxStartTxStateOk) { //Start TX - furi_hal_subghz_start_async_tx( - subghz_transmitter_yield, instance->transmitter); + subghz_devices_start_async_tx( + instance->radio_device, subghz_transmitter_yield, instance->transmitter); } } else { ret = SubGhzTxRxStartTxStateErrorParserOthers; @@ -293,7 +316,7 @@ static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { furi_assert(instance); furi_assert(instance->txrx_state == SubGhzTxRxStateTx); //Stop TX - furi_hal_subghz_stop_async_tx(); + subghz_devices_stop_async_tx(instance->radio_device); subghz_transmitter_stop(instance->transmitter); subghz_transmitter_free(instance->transmitter); @@ -306,7 +329,6 @@ static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { subghz_txrx_idle(instance); subghz_txrx_speaker_off(instance); //Todo: Show message - // notification_message(notifications, &sequence_reset_red); } FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) { @@ -356,7 +378,7 @@ void subghz_txrx_hopper_update(SubGhzTxRx* instance) { float rssi = -127.0f; if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) { // See RSSI Calculation timings in CC1101 17.3 RSSI - rssi = furi_hal_subghz_get_rssi(); + rssi = subghz_devices_get_rssi(instance->radio_device); // Stay if RSSI is high enough if(rssi > -90.0f) { @@ -414,7 +436,7 @@ void subghz_txrx_speaker_on(SubGhzTxRx* instance) { furi_assert(instance); if(instance->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_acquire(30)) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_speaker); } else { instance->speaker_state = SubGhzSpeakerStateDisable; } @@ -425,7 +447,7 @@ void subghz_txrx_speaker_off(SubGhzTxRx* instance) { furi_assert(instance); if(instance->speaker_state != SubGhzSpeakerStateDisable) { if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); + subghz_devices_set_async_mirror_pin(instance->radio_device, NULL); furi_hal_speaker_release(); if(instance->speaker_state == SubGhzSpeakerStateShutdown) instance->speaker_state = SubGhzSpeakerStateDisable; @@ -437,7 +459,7 @@ void subghz_txrx_speaker_mute(SubGhzTxRx* instance) { furi_assert(instance); if(instance->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(NULL); + subghz_devices_set_async_mirror_pin(instance->radio_device, NULL); } } } @@ -446,7 +468,7 @@ void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) { furi_assert(instance); if(instance->speaker_state == SubGhzSpeakerStateEnable) { if(furi_hal_speaker_is_mine()) { - furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + subghz_devices_set_async_mirror_pin(instance->radio_device, &gpio_speaker); } } } @@ -519,3 +541,66 @@ void subghz_txrx_set_raw_file_encoder_worker_callback_end( callback, context); } + +bool subghz_txrx_radio_device_is_external_connected(SubGhzTxRx* instance, const char* name) { + furi_assert(instance); + + bool is_connect = false; + bool is_otg_enabled = furi_hal_power_is_otg_enabled(); + + if(!is_otg_enabled) { + subghz_txrx_radio_device_power_on(instance); + } + + const SubGhzDevice* device = subghz_devices_get_by_name(name); + if(device) { + is_connect = subghz_devices_is_connect(device); + } + + if(!is_otg_enabled) { + subghz_txrx_radio_device_power_off(instance); + } + return is_connect; +} + +SubGhzRadioDeviceType + subghz_txrx_radio_device_set(SubGhzTxRx* instance, SubGhzRadioDeviceType radio_device_type) { + furi_assert(instance); + + if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 && + subghz_txrx_radio_device_is_external_connected(instance, SUBGHZ_DEVICE_CC1101_EXT_NAME)) { + subghz_txrx_radio_device_power_on(instance); + instance->radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME); + subghz_devices_begin(instance->radio_device); + instance->radio_device_type = SubGhzRadioDeviceTypeExternalCC1101; + } else { + subghz_txrx_radio_device_power_off(instance); + if(instance->radio_device_type != SubGhzRadioDeviceTypeInternal) { + subghz_devices_end(instance->radio_device); + } + instance->radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); + instance->radio_device_type = SubGhzRadioDeviceTypeInternal; + } + + return instance->radio_device_type; +} + +SubGhzRadioDeviceType subghz_txrx_radio_device_get(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->radio_device_type; +} + +float subghz_txrx_radio_device_get_rssi(SubGhzTxRx* instance) { + furi_assert(instance); + return subghz_devices_get_rssi(instance->radio_device); +} + +const char* subghz_txrx_radio_device_get_name(SubGhzTxRx* instance) { + furi_assert(instance); + return subghz_devices_get_name(instance->radio_device); +} + +bool subghz_txrx_radio_device_is_frequecy_valid(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + return subghz_devices_is_frequency_valid(instance->radio_device, frequency); +} \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index 0f2daf05d49..e49789206f0 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -7,6 +7,7 @@ #include #include #include +#include typedef struct SubGhzTxRx SubGhzTxRx; @@ -288,3 +289,48 @@ void subghz_txrx_set_raw_file_encoder_worker_callback_end( SubGhzTxRx* instance, SubGhzProtocolEncoderRAWCallbackEnd callback, void* context); + +/* Checking if an external radio device is connected +* +* @param instance Pointer to a SubGhzTxRx +* @param name Name of external radio device +* @return bool True if is connected to the external radio device +*/ +bool subghz_txrx_radio_device_is_external_connected(SubGhzTxRx* instance, const char* name); + +/* Set the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @param radio_device_type Radio device type +* @return SubGhzRadioDeviceType Type of installed radio device +*/ +SubGhzRadioDeviceType + subghz_txrx_radio_device_set(SubGhzTxRx* instance, SubGhzRadioDeviceType radio_device_type); + +/* Get the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @return SubGhzRadioDeviceType Type of installed radio device +*/ +SubGhzRadioDeviceType subghz_txrx_radio_device_get(SubGhzTxRx* instance); + +/* Get RSSI the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @return float RSSI +*/ +float subghz_txrx_radio_device_get_rssi(SubGhzTxRx* instance); + +/* Get name the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @return const char* Name of installed radio device +*/ +const char* subghz_txrx_radio_device_get_name(SubGhzTxRx* instance); + +/* Get get intelligence whether frequency the selected radio device to use +* +* @param instance Pointer to a SubGhzTxRx +* @return bool True if the frequency is valid +*/ +bool subghz_txrx_radio_device_is_frequecy_valid(SubGhzTxRx* instance, uint32_t frequency); \ No newline at end of file diff --git a/applications/main/subghz/helpers/subghz_txrx_i.h b/applications/main/subghz/helpers/subghz_txrx_i.h index bd0ad8b7be3..b7d74fd492f 100644 --- a/applications/main/subghz/helpers/subghz_txrx_i.h +++ b/applications/main/subghz/helpers/subghz_txrx_i.h @@ -21,6 +21,8 @@ struct SubGhzTxRx { SubGhzTxRxState txrx_state; SubGhzSpeakerState speaker_state; + const SubGhzDevice* radio_device; + SubGhzRadioDeviceType radio_device_type; SubGhzTxRxNeedSaveCallback need_save_callback; void* need_save_context; diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 46bf940f469..8beb7b9ed09 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -35,6 +35,13 @@ typedef enum { SubGhzSpeakerStateEnable, } SubGhzSpeakerState; +/** SubGhzRadioDeviceType */ +typedef enum { + SubGhzRadioDeviceTypeAuto, + SubGhzRadioDeviceTypeInternal, + SubGhzRadioDeviceTypeExternalCC1101, +} SubGhzRadioDeviceType; + /** SubGhzRxKeyState state */ typedef enum { SubGhzRxKeyStateIDLE, diff --git a/applications/main/subghz/scenes/subghz_scene_config.h b/applications/main/subghz/scenes/subghz_scene_config.h index 86a30731792..97aa946e8ad 100644 --- a/applications/main/subghz/scenes/subghz_scene_config.h +++ b/applications/main/subghz/scenes/subghz_scene_config.h @@ -24,3 +24,4 @@ ADD_SCENE(subghz, delete_raw, DeleteRAW) ADD_SCENE(subghz, need_saving, NeedSaving) ADD_SCENE(subghz, rpc, Rpc) ADD_SCENE(subghz, region_info, RegionInfo) +ADD_SCENE(subghz, radio_settings, RadioSettings) diff --git a/applications/main/subghz/scenes/subghz_scene_radio_setting.c b/applications/main/subghz/scenes/subghz_scene_radio_setting.c new file mode 100644 index 00000000000..0a47d5bfdbd --- /dev/null +++ b/applications/main/subghz/scenes/subghz_scene_radio_setting.c @@ -0,0 +1,70 @@ +#include "../subghz_i.h" +#include +#include + +enum SubGhzRadioSettingIndex { + SubGhzRadioSettingIndexDevice, +}; + +#define RADIO_DEVICE_COUNT 2 +const char* const radio_device_text[RADIO_DEVICE_COUNT] = { + "Internal", + "External", +}; + +const uint32_t radio_device_value[RADIO_DEVICE_COUNT] = { + SubGhzRadioDeviceTypeInternal, + SubGhzRadioDeviceTypeExternalCC1101, +}; + +static void subghz_scene_radio_settings_set_device(VariableItem* item) { + SubGhz* subghz = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + if(!subghz_txrx_radio_device_is_external_connected( + subghz->txrx, SUBGHZ_DEVICE_CC1101_EXT_NAME) && + radio_device_value[index] == SubGhzRadioDeviceTypeExternalCC1101) { + //ToDo correct if there is more than 1 module + index = 0; + } + variable_item_set_current_value_text(item, radio_device_text[index]); + subghz_txrx_radio_device_set(subghz->txrx, radio_device_value[index]); +} + +void subghz_scene_radio_settings_on_enter(void* context) { + SubGhz* subghz = context; + VariableItem* item; + uint8_t value_index; + + uint8_t value_count_device = RADIO_DEVICE_COUNT; + if(subghz_txrx_radio_device_get(subghz->txrx) == SubGhzRadioDeviceTypeInternal && + !subghz_txrx_radio_device_is_external_connected(subghz->txrx, SUBGHZ_DEVICE_CC1101_EXT_NAME)) + value_count_device = 1; + item = variable_item_list_add( + subghz->variable_item_list, + "Module", + value_count_device, + subghz_scene_radio_settings_set_device, + subghz); + value_index = value_index_uint32( + subghz_txrx_radio_device_get(subghz->txrx), radio_device_value, value_count_device); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, radio_device_text[value_index]); + + view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); +} + +bool subghz_scene_radio_settings_on_event(void* context, SceneManagerEvent event) { + SubGhz* subghz = context; + bool consumed = false; + UNUSED(subghz); + UNUSED(event); + + return consumed; +} + +void subghz_scene_radio_settings_on_exit(void* context) { + SubGhz* subghz = context; + variable_item_list_set_selected_item(subghz->variable_item_list, 0); + variable_item_list_reset(subghz->variable_item_list); +} diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index a29f86a078c..58e4b042954 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -48,6 +48,9 @@ static void subghz_scene_read_raw_update_statusbar(void* context) { furi_string_free(frequency_str); furi_string_free(modulation_str); + + subghz_read_raw_set_radio_device_type( + subghz->subghz_read_raw, subghz_txrx_radio_device_get(subghz->txrx)); } void subghz_scene_read_raw_callback(SubGhzCustomEvent event, void* context) { @@ -238,7 +241,9 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { furi_string_printf( temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION); subghz_protocol_raw_gen_fff_data( - subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str)); + subghz_txrx_get_fff_data(subghz->txrx), + furi_string_get_cstr(temp_str), + subghz_txrx_radio_device_get_name(subghz->txrx)); furi_string_free(temp_str); if(spl_count > 0) { @@ -298,8 +303,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { subghz_read_raw_update_sample_write( subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write(decoder_raw)); - SubGhzThresholdRssiData ret_rssi = - subghz_threshold_get_rssi_data(subghz->threshold_rssi); + SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data( + subghz->threshold_rssi, subghz_txrx_radio_device_get_rssi(subghz->txrx)); subghz_read_raw_add_data_rssi( subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above); subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 6771f8213b5..6ab443579bb 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -56,6 +56,9 @@ static void subghz_scene_receiver_update_statusbar(void* context) { subghz->state_notifications = SubGhzNotificationStateIDLE; } furi_string_free(history_stat_str); + + subghz_view_receiver_set_radio_device_type( + subghz->subghz_receiver, subghz_txrx_radio_device_get(subghz->txrx)); } void subghz_scene_receiver_callback(SubGhzCustomEvent event, void* context) { @@ -189,7 +192,8 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_scene_receiver_update_statusbar(subghz); } - SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi); + SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data( + subghz->threshold_rssi, subghz_txrx_radio_device_get_rssi(subghz->txrx)); subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi); subghz_protocol_decoder_bin_raw_data_input_rssi( diff --git a/applications/main/subghz/scenes/subghz_scene_save_name.c b/applications/main/subghz/scenes/subghz_scene_save_name.c index 7d0a4f4f8b7..86eddfe8e97 100644 --- a/applications/main/subghz/scenes/subghz_scene_save_name.c +++ b/applications/main/subghz/scenes/subghz_scene_save_name.c @@ -122,7 +122,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) { SubGhzCustomEventManagerNoSet) { subghz_protocol_raw_gen_fff_data( subghz_txrx_get_fff_data(subghz->txrx), - furi_string_get_cstr(subghz->file_path)); + furi_string_get_cstr(subghz->file_path), + subghz_txrx_radio_device_get_name(subghz->txrx)); scene_manager_set_scene_state( subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet); } else { diff --git a/applications/main/subghz/scenes/subghz_scene_start.c b/applications/main/subghz/scenes/subghz_scene_start.c index 0ab5f123ed1..ce631b39812 100644 --- a/applications/main/subghz/scenes/subghz_scene_start.c +++ b/applications/main/subghz/scenes/subghz_scene_start.c @@ -8,7 +8,8 @@ enum SubmenuIndex { SubmenuIndexAddManually, SubmenuIndexFrequencyAnalyzer, SubmenuIndexReadRAW, - SubmenuIndexShowRegionInfo + SubmenuIndexShowRegionInfo, + SubmenuIndexRadioSetting, }; void subghz_scene_start_submenu_callback(void* context, uint32_t index) { @@ -49,6 +50,12 @@ void subghz_scene_start_on_enter(void* context) { SubmenuIndexShowRegionInfo, subghz_scene_start_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Radio Settings", + SubmenuIndexRadioSetting, + subghz_scene_start_submenu_callback, + subghz); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { submenu_add_item( subghz->submenu, "Test", SubmenuIndexTest, subghz_scene_start_submenu_callback, subghz); @@ -104,6 +111,11 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) { subghz->scene_manager, SubGhzSceneStart, SubmenuIndexShowRegionInfo); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRegionInfo); return true; + } else if(event.event == SubmenuIndexRadioSetting) { + scene_manager_set_scene_state( + subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRadioSetting); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRadioSettings); + return true; } } return false; diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index 274dd61ad37..f83e44a0a1d 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -35,6 +35,8 @@ bool subghz_scene_transmitter_update_data_show(void* context) { furi_string_free(modulation_str); furi_string_free(key_str); } + subghz_view_transmitter_set_radio_device_type( + subghz->subghz_transmitter, subghz_txrx_radio_device_get(subghz->txrx)); return ret; } diff --git a/applications/main/subghz/subghz_cli.c b/applications/main/subghz/subghz_cli.c index 60845ac9986..bc7be507e73 100644 --- a/applications/main/subghz/subghz_cli.c +++ b/applications/main/subghz/subghz_cli.c @@ -10,6 +10,10 @@ #include #include #include +#include +#include +#include +#include #include "helpers/subghz_chat.h" @@ -24,6 +28,19 @@ #define SUBGHZ_REGION_FILENAME "/int/.region_data" +static void subghz_cli_radio_device_power_on() { + uint8_t attempts = 0; + while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { + furi_hal_power_enable_otg(); + //CC1101 power-up time + furi_delay_ms(10); + } +} + +static void subghz_cli_radio_device_power_off() { + if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg(); +} + void subghz_cli_command_tx_carrier(Cli* cli, FuriString* args, void* context) { UNUSED(context); uint32_t frequency = 433920000; @@ -44,7 +61,7 @@ void subghz_cli_command_tx_carrier(Cli* cli, FuriString* args, void* context) { } furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); frequency = furi_hal_subghz_set_frequency_and_path(frequency); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); @@ -88,7 +105,7 @@ void subghz_cli_command_rx_carrier(Cli* cli, FuriString* args, void* context) { } furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); frequency = furi_hal_subghz_set_frequency_and_path(frequency); printf("Receiving at frequency %lu Hz\r\n", frequency); printf("Press CTRL+C to stop\r\n"); @@ -109,44 +126,70 @@ void subghz_cli_command_rx_carrier(Cli* cli, FuriString* args, void* context) { furi_hal_subghz_sleep(); } +static const SubGhzDevice* subghz_cli_command_get_device(uint32_t device_ind) { + const SubGhzDevice* device = NULL; + switch(device_ind) { + case 1: + subghz_cli_radio_device_power_on(); + device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME); + break; + + default: + device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); + break; + } + return device; +} + void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) { UNUSED(context); uint32_t frequency = 433920000; uint32_t key = 0x0074BADE; uint32_t repeat = 10; uint32_t te = 403; + uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT if(furi_string_size(args)) { - int ret = - sscanf(furi_string_get_cstr(args), "%lx %lu %lu %lu", &key, &frequency, &te, &repeat); - if(ret != 4) { + int ret = sscanf( + furi_string_get_cstr(args), + "%lx %lu %lu %lu %lu", + &key, + &frequency, + &te, + &repeat, + &device_ind); + if(ret != 5) { printf( - "sscanf returned %d, key: %lx, frequency: %lu, te:%lu, repeat: %lu\r\n", + "sscanf returned %d, key: %lx, frequency: %lu, te: %lu, repeat: %lu, device: %lu\r\n ", ret, key, frequency, te, - repeat); + repeat, + device_ind); cli_print_usage( "subghz tx", - "<3 Byte Key: in hex> ", + "<3 Byte Key: in hex> ", furi_string_get_cstr(args)); return; } - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - printf( - "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", - frequency); - return; - } } - + subghz_devices_init(); + const SubGhzDevice* device = subghz_cli_command_get_device(device_ind); + if(!subghz_devices_is_frequency_valid(device, frequency)) { + printf( + "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", frequency); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + return; + } printf( - "Transmitting at %lu, key %lx, te %lu, repeat %lu. Press CTRL+C to stop\r\n", + "Transmitting at %lu, key %lx, te %lu, repeat %lu device %lu. Press CTRL+C to stop\r\n", frequency, key, te, - repeat); + repeat, + device_ind); FuriString* flipper_format_string = furi_string_alloc_printf( "Protocol: Princeton\n" @@ -170,25 +213,29 @@ void subghz_cli_command_tx(Cli* cli, FuriString* args, void* context) { SubGhzTransmitter* transmitter = subghz_transmitter_alloc_init(environment, "Princeton"); subghz_transmitter_deserialize(transmitter, flipper_format); - furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); - frequency = furi_hal_subghz_set_frequency_and_path(frequency); + subghz_devices_begin(device); + subghz_devices_reset(device); + subghz_devices_load_preset(device, FuriHalSubGhzPresetOok650Async, NULL); + frequency = subghz_devices_set_frequency(device, frequency); furi_hal_power_suppress_charge_enter(); - - if(furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter)) { - while(!(furi_hal_subghz_is_async_tx_complete() || cli_cmd_interrupt_received(cli))) { + if(subghz_devices_start_async_tx(device, subghz_transmitter_yield, transmitter)) { + while(!(subghz_devices_is_async_complete_tx(device) || cli_cmd_interrupt_received(cli))) { printf("."); fflush(stdout); furi_delay_ms(333); } - furi_hal_subghz_stop_async_tx(); + subghz_devices_stop_async_tx(device); } else { printf("Transmission on this frequency is restricted in your region\r\n"); } - furi_hal_subghz_sleep(); + subghz_devices_sleep(device); + subghz_devices_end(device); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + furi_hal_power_suppress_charge_exit(); flipper_format_free(flipper_format); @@ -233,21 +280,29 @@ static void subghz_cli_command_rx_callback( void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { UNUSED(context); uint32_t frequency = 433920000; + uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT if(furi_string_size(args)) { - int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency); - if(ret != 1) { - printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency); - cli_print_usage("subghz rx", "", furi_string_get_cstr(args)); - return; - } - if(!furi_hal_subghz_is_frequency_valid(frequency)) { + int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &frequency, &device_ind); + if(ret != 2) { printf( - "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", - frequency); + "sscanf returned %d, frequency: %lu device: %lu\r\n", ret, frequency, device_ind); + cli_print_usage( + "subghz rx", + " ", + furi_string_get_cstr(args)); return; } } + subghz_devices_init(); + const SubGhzDevice* device = subghz_cli_command_get_device(device_ind); + if(!subghz_devices_is_frequency_valid(device, frequency)) { + printf( + "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", frequency); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + return; + } // Allocate context and buffers SubGhzCliCommandRx* instance = malloc(sizeof(SubGhzCliCommandRx)); @@ -256,14 +311,14 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { furi_check(instance->stream); SubGhzEnvironment* environment = subghz_environment_alloc(); - subghz_environment_load_keystore(environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); - subghz_environment_load_keystore(environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_NAME); + subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_USER_NAME); subghz_environment_set_came_atomo_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/came_atomo")); + environment, SUBGHZ_CAME_ATOMO_DIR_NAME); subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/alutech_at_4n")); + environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME); subghz_environment_set_nice_flor_s_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/nice_flor_s")); + environment, SUBGHZ_NICE_FLOR_S_DIR_NAME); subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry); SubGhzReceiver* receiver = subghz_receiver_alloc_init(environment); @@ -271,18 +326,21 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { subghz_receiver_set_rx_callback(receiver, subghz_cli_command_rx_callback, instance); // Configure radio - furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); - frequency = furi_hal_subghz_set_frequency_and_path(frequency); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + subghz_devices_begin(device); + subghz_devices_reset(device); + subghz_devices_load_preset(device, FuriHalSubGhzPresetOok650Async, NULL); + frequency = subghz_devices_set_frequency(device, frequency); furi_hal_power_suppress_charge_enter(); // Prepare and start RX - furi_hal_subghz_start_async_rx(subghz_cli_command_rx_capture_callback, instance); + subghz_devices_start_async_rx(device, subghz_cli_command_rx_capture_callback, instance); // Wait for packets to arrive - printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency); + printf( + "Listening at frequency: %lu device: %lu. Press CTRL+C to stop\r\n", + frequency, + device_ind); LevelDuration level_duration; while(!cli_cmd_interrupt_received(cli)) { int ret = furi_stream_buffer_receive( @@ -300,8 +358,11 @@ void subghz_cli_command_rx(Cli* cli, FuriString* args, void* context) { } // Shutdown radio - furi_hal_subghz_stop_async_rx(); - furi_hal_subghz_sleep(); + subghz_devices_stop_async_rx(device); + subghz_devices_sleep(device); + subghz_devices_end(device); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); furi_hal_power_suppress_charge_exit(); @@ -341,7 +402,7 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { // Configure radio furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok270Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_270khz_async_regs); frequency = furi_hal_subghz_set_frequency_and_path(frequency); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); @@ -389,6 +450,7 @@ void subghz_cli_command_rx_raw(Cli* cli, FuriString* args, void* context) { furi_stream_buffer_free(instance->stream); free(instance); } + void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { UNUSED(context); FuriString* file_name; @@ -442,25 +504,23 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { SubGhzCliCommandRx* instance = malloc(sizeof(SubGhzCliCommandRx)); SubGhzEnvironment* environment = subghz_environment_alloc(); - if(subghz_environment_load_keystore( - environment, EXT_PATH("subghz/assets/keeloq_mfcodes"))) { + if(subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_NAME)) { printf("SubGhz decode_raw: Load_keystore keeloq_mfcodes \033[0;32mOK\033[0m\r\n"); } else { printf("SubGhz decode_raw: Load_keystore keeloq_mfcodes \033[0;31mERROR\033[0m\r\n"); } - if(subghz_environment_load_keystore( - environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"))) { + if(subghz_environment_load_keystore(environment, SUBGHZ_KEYSTORE_DIR_USER_NAME)) { printf("SubGhz decode_raw: Load_keystore keeloq_mfcodes_user \033[0;32mOK\033[0m\r\n"); } else { printf( "SubGhz decode_raw: Load_keystore keeloq_mfcodes_user \033[0;31mERROR\033[0m\r\n"); } subghz_environment_set_came_atomo_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/came_atomo")); + environment, SUBGHZ_CAME_ATOMO_DIR_NAME); subghz_environment_set_alutech_at_4n_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/alutech_at_4n")); + environment, SUBGHZ_ALUTECH_AT_4N_DIR_NAME); subghz_environment_set_nice_flor_s_rainbow_table_file_name( - environment, EXT_PATH("subghz/assets/nice_flor_s")); + environment, SUBGHZ_NICE_FLOR_S_DIR_NAME); subghz_environment_set_protocol_registry(environment, (void*)&subghz_protocol_registry); SubGhzReceiver* receiver = subghz_receiver_alloc_init(environment); @@ -468,7 +528,8 @@ void subghz_cli_command_decode_raw(Cli* cli, FuriString* args, void* context) { subghz_receiver_set_rx_callback(receiver, subghz_cli_command_rx_callback, instance); SubGhzFileEncoderWorker* file_worker_encoder = subghz_file_encoder_worker_alloc(); - if(subghz_file_encoder_worker_start(file_worker_encoder, furi_string_get_cstr(file_name))) { + if(subghz_file_encoder_worker_start( + file_worker_encoder, furi_string_get_cstr(file_name), NULL)) { //the worker needs a file in order to open and read part of the file furi_delay_ms(100); } @@ -510,10 +571,11 @@ static void subghz_cli_command_print_usage() { printf("subghz \r\n"); printf("Cmd list:\r\n"); - printf("\tchat \t - Chat with other Flippers\r\n"); printf( - "\ttx <3 byte Key: in hex> \t - Transmitting key\r\n"); - printf("\trx \t - Receive\r\n"); + "\tchat \t - Chat with other Flippers\r\n"); + printf( + "\ttx <3 byte Key: in hex> \t - Transmitting key\r\n"); + printf("\trx \t - Receive\r\n"); printf("\trx_raw \t - Receive RAW\r\n"); printf("\tdecode_raw \t - Testing\r\n"); @@ -611,21 +673,29 @@ static void subghz_cli_command_encrypt_raw(Cli* cli, FuriString* args) { static void subghz_cli_command_chat(Cli* cli, FuriString* args) { uint32_t frequency = 433920000; + uint32_t device_ind = 0; // 0 - CC1101_INT, 1 - CC1101_EXT if(furi_string_size(args)) { - int ret = sscanf(furi_string_get_cstr(args), "%lu", &frequency); - if(ret != 1) { - printf("sscanf returned %d, frequency: %lu\r\n", ret, frequency); - cli_print_usage("subghz chat", "", furi_string_get_cstr(args)); - return; - } - if(!furi_hal_subghz_is_frequency_valid(frequency)) { - printf( - "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", - frequency); + int ret = sscanf(furi_string_get_cstr(args), "%lu %lu", &frequency, &device_ind); + if(ret != 2) { + printf("sscanf returned %d, Frequency: %lu\r\n", ret, frequency); + printf("sscanf returned %d, Device: %lu\r\n", ret, device_ind); + cli_print_usage( + "subghz chat", + " ", + furi_string_get_cstr(args)); return; } } + subghz_devices_init(); + const SubGhzDevice* device = subghz_cli_command_get_device(device_ind); + if(!subghz_devices_is_frequency_valid(device, frequency)) { + printf( + "Frequency must be in " SUBGHZ_FREQUENCY_RANGE_STR " range, not %lu\r\n", frequency); + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + return; + } if(!furi_hal_region_is_frequency_allowed(frequency)) { printf( "In your region, only reception on this frequency (%lu) is allowed,\r\n" @@ -635,7 +705,8 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { } SubGhzChatWorker* subghz_chat = subghz_chat_worker_alloc(cli); - if(!subghz_chat_worker_start(subghz_chat, frequency)) { + + if(!subghz_chat_worker_start(subghz_chat, device, frequency)) { printf("Startup error SubGhzChatWorker\r\n"); if(subghz_chat_worker_is_running(subghz_chat)) { @@ -781,6 +852,10 @@ static void subghz_cli_command_chat(Cli* cli, FuriString* args) { furi_string_free(name); furi_string_free(output); furi_string_free(sysmsg); + + subghz_devices_deinit(); + subghz_cli_radio_device_power_off(); + furi_hal_power_suppress_charge_exit(); furi_record_close(RECORD_NOTIFICATION); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 8036ed5f7ac..55036846cae 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -115,7 +115,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { break; } - if(!furi_hal_subghz_is_frequency_valid(temp_data32)) { + if(!subghz_txrx_radio_device_is_frequecy_valid(subghz->txrx, temp_data32)) { FURI_LOG_E(TAG, "Frequency not supported"); break; } @@ -163,7 +163,8 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) { if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) { //if RAW subghz->load_type_file = SubGhzLoadTypeFileRaw; - subghz_protocol_raw_gen_fff_data(fff_data, file_path); + subghz_protocol_raw_gen_fff_data( + fff_data, file_path, subghz_txrx_radio_device_get_name(subghz->txrx)); } else { subghz->load_type_file = SubGhzLoadTypeFileKey; stream_copy_full( diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index f84ddfed086..e1014b81109 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -62,6 +62,7 @@ typedef struct { uint16_t history_item; SubGhzViewReceiverBarShow bar_show; uint8_t u_rssi; + SubGhzRadioDeviceType device_type; } SubGhzViewReceiverModel; void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { @@ -173,6 +174,17 @@ void subghz_view_receiver_add_data_statusbar( true); } +void subghz_view_receiver_set_radio_device_type( + SubGhzViewReceiver* subghz_receiver, + SubGhzRadioDeviceType device_type) { + furi_assert(subghz_receiver); + with_view_model( + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->device_type = device_type; }, + true); +} + static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { canvas_set_color(canvas, ColorBlack); canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT); @@ -190,9 +202,9 @@ static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool s static void subghz_view_rssi_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { for(uint8_t i = 1; i < model->u_rssi; i++) { if(i % 5) { - canvas_draw_dot(canvas, 46 + i, 50); - canvas_draw_dot(canvas, 47 + i, 51); canvas_draw_dot(canvas, 46 + i, 52); + canvas_draw_dot(canvas, 47 + i, 53); + canvas_draw_dot(canvas, 46 + i, 54); } } } @@ -232,22 +244,28 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { canvas_set_color(canvas, ColorBlack); if(model->history_item == 0) { - canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); + canvas_draw_icon(canvas, 0, 0, &I_Scanning_short_96x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 44, "Scanning..."); canvas_set_font(canvas, FontSecondary); } + if(model->device_type == SubGhzRadioDeviceTypeInternal) { + canvas_draw_icon(canvas, 108, 0, &I_Internal_antenna_20x12); + } else { + canvas_draw_icon(canvas, 108, 0, &I_External_antenna_20x12); + } + subghz_view_rssi_draw(canvas, model); switch(model->bar_show) { case SubGhzViewReceiverBarShowLock: - canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); - canvas_draw_str(canvas, 74, 62, "Locked"); + canvas_draw_icon(canvas, 64, 56, &I_Lock_7x8); + canvas_draw_str(canvas, 74, 64, "Locked"); break; case SubGhzViewReceiverBarShowToUnlockPress: - canvas_draw_str(canvas, 44, 62, furi_string_get_cstr(model->frequency_str)); - canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); - canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str)); + canvas_draw_str(canvas, 44, 64, furi_string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 79, 64, furi_string_get_cstr(model->preset_str)); + canvas_draw_str(canvas, 97, 64, furi_string_get_cstr(model->history_stat_str)); canvas_set_font(canvas, FontSecondary); elements_bold_rounded_frame(canvas, 14, 8, 99, 48); elements_multiline_text(canvas, 65, 26, "To unlock\npress:"); @@ -258,13 +276,13 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) { canvas_draw_dot(canvas, 17, 61); break; case SubGhzViewReceiverBarShowUnlock: - canvas_draw_icon(canvas, 64, 55, &I_Unlock_7x8); - canvas_draw_str(canvas, 74, 62, "Unlocked"); + canvas_draw_icon(canvas, 64, 56, &I_Unlock_7x8); + canvas_draw_str(canvas, 74, 64, "Unlocked"); break; default: - canvas_draw_str(canvas, 44, 62, furi_string_get_cstr(model->frequency_str)); - canvas_draw_str(canvas, 79, 62, furi_string_get_cstr(model->preset_str)); - canvas_draw_str(canvas, 96, 62, furi_string_get_cstr(model->history_stat_str)); + canvas_draw_str(canvas, 44, 64, furi_string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 79, 64, furi_string_get_cstr(model->preset_str)); + canvas_draw_str(canvas, 97, 64, furi_string_get_cstr(model->history_stat_str)); break; } } diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index 5119105e93b..c91c069386c 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -29,6 +29,10 @@ void subghz_view_receiver_add_data_statusbar( const char* preset_str, const char* history_stat_str); +void subghz_view_receiver_set_radio_device_type( + SubGhzViewReceiver* subghz_receiver, + SubGhzRadioDeviceType device_type); + void subghz_view_receiver_add_item_to_menu( SubGhzViewReceiver* subghz_receiver, const char* name, diff --git a/applications/main/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c index 325664f4a9c..d90401678a8 100644 --- a/applications/main/subghz/views/subghz_frequency_analyzer.c +++ b/applications/main/subghz/views/subghz_frequency_analyzer.c @@ -177,7 +177,8 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel } subghz_frequency_analyzer_log_frequency_draw(canvas, model); } else { - canvas_draw_str(canvas, 20, 8, "Frequency Analyzer"); + canvas_draw_str(canvas, 0, 8, "Frequency Analyzer"); + canvas_draw_icon(canvas, 108, 0, &I_Internal_antenna_20x12); canvas_draw_str(canvas, 0, 64, "RSSI"); subghz_frequency_analyzer_draw_rssi(canvas, model->rssi, 20, 64); diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index 2ff598b6058..88ac129ca9e 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -29,6 +29,7 @@ typedef struct { uint8_t ind_sin; SubGhzReadRAWStatus status; float raw_threshold_rssi; + SubGhzRadioDeviceType device_type; } SubGhzReadRAWModel; void subghz_read_raw_set_callback( @@ -56,6 +57,14 @@ void subghz_read_raw_add_data_statusbar( true); } +void subghz_read_raw_set_radio_device_type( + SubGhzReadRAW* instance, + SubGhzRadioDeviceType device_type) { + furi_assert(instance); + with_view_model( + instance->view, SubGhzReadRAWModel * model, { model->device_type = device_type; }, true); +} + void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool trace) { furi_assert(instance); uint8_t u_rssi = 0; @@ -279,11 +288,16 @@ void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) { uint8_t graphics_mode = 1; canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 5, 7, furi_string_get_cstr(model->frequency_str)); - canvas_draw_str(canvas, 40, 7, furi_string_get_cstr(model->preset_str)); + canvas_draw_str(canvas, 0, 9, furi_string_get_cstr(model->frequency_str)); + canvas_draw_str(canvas, 35, 9, furi_string_get_cstr(model->preset_str)); canvas_draw_str_aligned( - canvas, 126, 0, AlignRight, AlignTop, furi_string_get_cstr(model->sample_write)); + canvas, 106, 2, AlignRight, AlignTop, furi_string_get_cstr(model->sample_write)); + if(model->device_type == SubGhzRadioDeviceTypeInternal) { + canvas_draw_icon(canvas, 108, 0, &I_Internal_antenna_20x12); + } else { + canvas_draw_icon(canvas, 108, 0, &I_External_antenna_20x12); + } canvas_draw_line(canvas, 0, 14, 115, 14); canvas_draw_line(canvas, 0, 48, 115, 48); canvas_draw_line(canvas, 115, 14, 115, 48); diff --git a/applications/main/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h index 31aa9db6fdd..83403e9750c 100644 --- a/applications/main/subghz/views/subghz_read_raw.h +++ b/applications/main/subghz/views/subghz_read_raw.h @@ -1,6 +1,7 @@ #pragma once #include +#include "../helpers/subghz_types.h" #include "../helpers/subghz_custom_event.h" #define SUBGHZ_RAW_THRESHOLD_MIN -90.0f @@ -36,6 +37,10 @@ void subghz_read_raw_add_data_statusbar( const char* frequency_str, const char* preset_str); +void subghz_read_raw_set_radio_device_type( + SubGhzReadRAW* instance, + SubGhzRadioDeviceType device_type); + void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample); void subghz_read_raw_stop_send(SubGhzReadRAW* instance); diff --git a/applications/main/subghz/views/subghz_test_carrier.c b/applications/main/subghz/views/subghz_test_carrier.c index e533a6aac4e..254a4127bc4 100644 --- a/applications/main/subghz/views/subghz_test_carrier.c +++ b/applications/main/subghz/views/subghz_test_carrier.c @@ -1,6 +1,7 @@ #include "subghz_test_carrier.h" #include "../subghz_i.h" #include "../helpers/subghz_testing.h" +#include #include #include @@ -138,7 +139,7 @@ void subghz_test_carrier_enter(void* context) { SubGhzTestCarrier* subghz_test_carrier = context; furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); diff --git a/applications/main/subghz/views/subghz_test_packet.c b/applications/main/subghz/views/subghz_test_packet.c index 43502180cea..bc2c474b513 100644 --- a/applications/main/subghz/views/subghz_test_packet.c +++ b/applications/main/subghz/views/subghz_test_packet.c @@ -1,6 +1,7 @@ #include "subghz_test_packet.h" #include "../subghz_i.h" #include "../helpers/subghz_testing.h" +#include #include #include @@ -194,7 +195,7 @@ void subghz_test_packet_enter(void* context) { SubGhzTestPacket* instance = context; furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); with_view_model( instance->view, diff --git a/applications/main/subghz/views/subghz_test_static.c b/applications/main/subghz/views/subghz_test_static.c index 6abefda763e..197af21fb5f 100644 --- a/applications/main/subghz/views/subghz_test_static.c +++ b/applications/main/subghz/views/subghz_test_static.c @@ -1,6 +1,7 @@ #include "subghz_test_static.h" #include "../subghz_i.h" #include "../helpers/subghz_testing.h" +#include #include #include @@ -141,7 +142,7 @@ void subghz_test_static_enter(void* context) { SubGhzTestStatic* instance = context; furi_hal_subghz_reset(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); furi_hal_gpio_write(&gpio_cc1101_g0, false); diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 86dc17a38f7..2a876f8c268 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -15,6 +15,7 @@ typedef struct { FuriString* preset_str; FuriString* key_str; bool show_button; + SubGhzRadioDeviceType device_type; } SubGhzViewTransmitterModel; void subghz_view_transmitter_set_callback( @@ -46,6 +47,17 @@ void subghz_view_transmitter_add_data_to_show( true); } +void subghz_view_transmitter_set_radio_device_type( + SubGhzViewTransmitter* subghz_transmitter, + SubGhzRadioDeviceType device_type) { + furi_assert(subghz_transmitter); + with_view_model( + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { model->device_type = device_type; }, + true); +} + static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) { const uint8_t button_height = 12; const uint8_t vertical_offset = 3; @@ -56,7 +68,7 @@ static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_offset; const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset; - const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40; + const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 44; const uint8_t y = canvas_height(canvas); canvas_draw_box(canvas, x, y - button_height, button_width, button_height); @@ -88,7 +100,14 @@ void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* mo canvas, 0, 0, AlignLeft, AlignTop, furi_string_get_cstr(model->key_str)); canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str)); canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str)); - if(model->show_button) subghz_view_transmitter_button_right(canvas, "Send"); + if(model->show_button) { + if(model->device_type == SubGhzRadioDeviceTypeInternal) { + canvas_draw_icon(canvas, 108, 39, &I_Internal_antenna_20x12); + } else { + canvas_draw_icon(canvas, 108, 39, &I_External_antenna_20x12); + } + subghz_view_transmitter_button_right(canvas, "Send"); + } } bool subghz_view_transmitter_input(InputEvent* event, void* context) { diff --git a/applications/main/subghz/views/transmitter.h b/applications/main/subghz/views/transmitter.h index 06aae7c6bf7..19da3145c95 100644 --- a/applications/main/subghz/views/transmitter.h +++ b/applications/main/subghz/views/transmitter.h @@ -1,6 +1,7 @@ #pragma once #include +#include "../helpers/subghz_types.h" #include "../helpers/subghz_custom_event.h" typedef struct SubGhzViewTransmitter SubGhzViewTransmitter; @@ -12,6 +13,10 @@ void subghz_view_transmitter_set_callback( SubGhzViewTransmitterCallback callback, void* context); +void subghz_view_transmitter_set_radio_device_type( + SubGhzViewTransmitter* subghz_transmitter, + SubGhzRadioDeviceType device_type); + SubGhzViewTransmitter* subghz_view_transmitter_alloc(); void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter); diff --git a/applications/services/applications.h b/applications/services/applications.h index 85f73674232..45b050a06ec 100644 --- a/applications/services/applications.h +++ b/applications/services/applications.h @@ -4,9 +4,9 @@ #include typedef enum { - FlipperApplicationFlagDefault = 0, - FlipperApplicationFlagInsomniaSafe = (1 << 0), -} FlipperApplicationFlag; + FlipperInternalApplicationFlagDefault = 0, + FlipperInternalApplicationFlagInsomniaSafe = (1 << 0), +} FlipperInternalApplicationFlag; typedef struct { const FuriThreadCallback app; @@ -14,48 +14,41 @@ typedef struct { const char* appid; const size_t stack_size; const Icon* icon; - const FlipperApplicationFlag flags; -} FlipperApplication; + const FlipperInternalApplicationFlag flags; +} FlipperInternalApplication; -typedef void (*FlipperOnStartHook)(void); +typedef void (*FlipperInternalOnStartHook)(void); extern const char* FLIPPER_AUTORUN_APP_NAME; /* Services list * Spawned on startup */ -extern const FlipperApplication FLIPPER_SERVICES[]; +extern const FlipperInternalApplication FLIPPER_SERVICES[]; extern const size_t FLIPPER_SERVICES_COUNT; /* Apps list * Spawned by loader */ -extern const FlipperApplication FLIPPER_APPS[]; +extern const FlipperInternalApplication FLIPPER_APPS[]; extern const size_t FLIPPER_APPS_COUNT; /* On system start hooks * Called by loader, after OS initialization complete */ -extern const FlipperOnStartHook FLIPPER_ON_SYSTEM_START[]; +extern const FlipperInternalOnStartHook FLIPPER_ON_SYSTEM_START[]; extern const size_t FLIPPER_ON_SYSTEM_START_COUNT; /* System apps * Can only be spawned by loader by name */ -extern const FlipperApplication FLIPPER_SYSTEM_APPS[]; +extern const FlipperInternalApplication FLIPPER_SYSTEM_APPS[]; extern const size_t FLIPPER_SYSTEM_APPS_COUNT; -/* Separate scene app holder - * Spawned by loader - */ -extern const FlipperApplication FLIPPER_SCENE; -extern const FlipperApplication FLIPPER_SCENE_APPS[]; -extern const size_t FLIPPER_SCENE_APPS_COUNT; - -extern const FlipperApplication FLIPPER_ARCHIVE; +extern const FlipperInternalApplication FLIPPER_ARCHIVE; /* Settings list * Spawned by loader */ -extern const FlipperApplication FLIPPER_SETTINGS_APPS[]; +extern const FlipperInternalApplication FLIPPER_SETTINGS_APPS[]; extern const size_t FLIPPER_SETTINGS_APPS_COUNT; diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index e1da649408b..1233af8938f 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -36,6 +36,7 @@ static void desktop_loader_callback(const void* message, void* context) { view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopGlobalAfterAppFinished); } } + static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) { UNUSED(context); furi_assert(canvas); diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index d19b5560f94..ae39ec22376 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -16,8 +16,6 @@ #define SNAKE_GAME_APP EXT_PATH("/apps/Games/snake_game.fap") #define CLOCK_APP EXT_PATH("/apps/Tools/clock.fap") -#define FAP_LOADER_APP_NAME "Applications" - static void desktop_scene_main_new_idle_animation_callback(void* context) { furi_assert(context); Desktop* desktop = context; @@ -40,7 +38,8 @@ static void desktop_scene_main_interact_animation_callback(void* context) { } #ifdef APP_ARCHIVE -static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* flipper_app) { +static void + desktop_switch_to_app(Desktop* desktop, const FlipperInternalApplication* flipper_app) { furi_assert(desktop); furi_assert(flipper_app); furi_assert(flipper_app->app); @@ -67,30 +66,16 @@ static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* fl #endif static void desktop_scene_main_open_app_or_profile(Desktop* desktop, const char* path) { - do { - LoaderStatus status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, path); - if(status == LoaderStatusOk) break; - FURI_LOG_E(TAG, "loader_start failed: %d", status); - - status = loader_start(desktop->loader, "Passport", NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } - } while(false); + if(loader_start_with_gui_error(desktop->loader, path, NULL) != LoaderStatusOk) { + loader_start(desktop->loader, "Passport", NULL, NULL); + } } static void desktop_scene_main_start_favorite(Desktop* desktop, FavoriteApp* application) { - LoaderStatus status = LoaderStatusErrorInternal; - if(application->is_external) { - status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, application->name_or_path); - } else if(strlen(application->name_or_path) > 0) { - status = loader_start(desktop->loader, application->name_or_path, NULL); + if(strlen(application->name_or_path) > 0) { + loader_start_with_gui_error(desktop->loader, application->name_or_path, NULL); } else { - status = loader_start(desktop->loader, FAP_LOADER_APP_NAME, NULL); - } - - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); + loader_start(desktop->loader, LOADER_APPLICATIONS_NAME, NULL, NULL); } } @@ -148,10 +133,7 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; case DesktopMainEventOpenPowerOff: { - LoaderStatus status = loader_start(desktop->loader, "Power", "off"); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + loader_start(desktop->loader, "Power", "off", NULL); consumed = true; break; } @@ -176,18 +158,12 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; case DesktopAnimationEventInteractAnimation: if(!animation_manager_interact_process(desktop->animation_manager)) { - LoaderStatus status = loader_start(desktop->loader, "Passport", NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + loader_start(desktop->loader, "Passport", NULL, NULL); } consumed = true; break; case DesktopMainEventOpenPassport: { - LoaderStatus status = loader_start(desktop->loader, "Passport", NULL); - if(status != LoaderStatusOk) { - FURI_LOG_E(TAG, "loader_start failed: %d", status); - } + loader_start(desktop->loader, "Passport", NULL, NULL); break; } case DesktopMainEventOpenGame: { diff --git a/applications/services/dialogs/dialogs.c b/applications/services/dialogs/dialogs.c index 3908ca31b58..10c08a991b3 100644 --- a/applications/services/dialogs/dialogs.c +++ b/applications/services/dialogs/dialogs.c @@ -9,12 +9,13 @@ void dialog_file_browser_set_basic_options( const char* extension, const Icon* icon) { options->extension = extension; + options->base_path = NULL; options->skip_assets = true; + options->hide_dot_files = true; options->icon = icon; options->hide_ext = true; options->item_loader_callback = NULL; options->item_loader_context = NULL; - options->base_path = NULL; } static DialogsApp* dialogs_app_alloc() { diff --git a/applications/services/dialogs/dialogs.h b/applications/services/dialogs/dialogs.h index 4c1b675a644..39b15c67c2e 100644 --- a/applications/services/dialogs/dialogs.h +++ b/applications/services/dialogs/dialogs.h @@ -16,7 +16,8 @@ typedef struct DialogsApp DialogsApp; /****************** FILE BROWSER ******************/ /** - * File browser dialog extra options + * File browser dialog extra options. + * This can be default-initialized using {@link dialog_file_browser_set_basic_options}. * @param extension file extension to be offered for selection * @param base_path root folder path for navigation with back key * @param skip_assets true - do not show assets folders @@ -38,8 +39,10 @@ typedef struct { } DialogsFileBrowserOptions; /** - * Initialize file browser dialog options - * and set default values + * Initialize file browser dialog options and set default values. + * This is guaranteed to initialize all fields + * so it is safe to pass pointer to uninitialized {@code options} + * and assume that the data behind it becomes fully initialized after the call. * @param options pointer to options structure * @param extension file extension to filter * @param icon file icon pointer, NULL for default icon diff --git a/applications/services/dialogs/dialogs_i.h b/applications/services/dialogs/dialogs_i.h index 76495d31b0a..29417b41b52 100644 --- a/applications/services/dialogs/dialogs_i.h +++ b/applications/services/dialogs/dialogs_i.h @@ -1,7 +1,7 @@ #pragma once #include "dialogs.h" #include "dialogs_message.h" -#include "view_holder.h" +#include #include #ifdef __cplusplus diff --git a/applications/services/gui/modules/file_browser.c b/applications/services/gui/modules/file_browser.c index d12a00ba598..c764a1cf7e3 100644 --- a/applications/services/gui/modules/file_browser.c +++ b/applications/services/gui/modules/file_browser.c @@ -118,6 +118,8 @@ typedef struct { const Icon* file_icon; bool hide_ext; size_t scroll_counter; + + uint32_t button_held_for_ticks; } FileBrowserModel; static const Icon* BrowserItemIcons[] = { @@ -589,9 +591,24 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { browser->view, FileBrowserModel * model, { + int32_t scroll_speed = 1; + if(model->button_held_for_ticks > 5) { + if(model->button_held_for_ticks % 2) { + scroll_speed = 0; + } else { + scroll_speed = model->button_held_for_ticks > 9 ? 5 : 3; + } + } + if(event->key == InputKeyUp) { - model->item_idx = - ((model->item_idx - 1) + model->item_cnt) % model->item_cnt; + if(model->item_idx < scroll_speed) { + model->button_held_for_ticks = 0; + model->item_idx = model->item_cnt - 1; + } else { + model->item_idx = + ((model->item_idx - scroll_speed) + model->item_cnt) % + model->item_cnt; + } if(browser_is_list_load_required(model)) { model->list_loading = true; int32_t load_offset = CLAMP( @@ -602,8 +619,16 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { browser->worker, load_offset, ITEM_LIST_LEN_MAX); } model->scroll_counter = 0; + + model->button_held_for_ticks += 1; } else if(event->key == InputKeyDown) { - model->item_idx = (model->item_idx + 1) % model->item_cnt; + int32_t count = model->item_cnt; + if(model->item_idx + scroll_speed >= count) { + model->button_held_for_ticks = 0; + model->item_idx = 0; + } else { + model->item_idx = (model->item_idx + scroll_speed) % model->item_cnt; + } if(browser_is_list_load_required(model)) { model->list_loading = true; int32_t load_offset = CLAMP( @@ -614,11 +639,19 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { browser->worker, load_offset, ITEM_LIST_LEN_MAX); } model->scroll_counter = 0; + + model->button_held_for_ticks += 1; } }, true); browser_update_offset(browser); consumed = true; + } else if(event->type == InputTypeRelease) { + with_view_model( + browser->view, + FileBrowserModel * model, + { model->button_held_for_ticks = 0; }, + true); } } else if(event->key == InputKeyOk) { if(event->type == InputTypeShort) { diff --git a/applications/services/gui/modules/submenu.c b/applications/services/gui/modules/submenu.c index 9d81c30b688..3ba35edde07 100644 --- a/applications/services/gui/modules/submenu.c +++ b/applications/services/gui/modules/submenu.c @@ -63,7 +63,7 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) { SubmenuModel* model = _model; const uint8_t item_height = 16; - const uint8_t item_width = 123; + uint8_t item_width = canvas_width(canvas) - 5; canvas_clear(canvas); diff --git a/applications/services/gui/modules/text_box.c b/applications/services/gui/modules/text_box.c index 01ccdbf52b5..0e4aae9446b 100644 --- a/applications/services/gui/modules/text_box.c +++ b/applications/services/gui/modules/text_box.c @@ -6,6 +6,8 @@ struct TextBox { View* view; + + uint16_t button_held_for_ticks; }; typedef struct { @@ -19,36 +21,52 @@ typedef struct { bool formatted; } TextBoxModel; -static void text_box_process_down(TextBox* text_box) { +static void text_box_process_down(TextBox* text_box, uint8_t lines) { with_view_model( text_box->view, TextBoxModel * model, { - if(model->scroll_pos < model->scroll_num - 1) { - model->scroll_pos++; - // Search next line start - while(*model->text_pos++ != '\n') - ; + if(model->scroll_pos < model->scroll_num - lines) { + model->scroll_pos += lines; + for(uint8_t i = 0; i < lines; i++) { + // Search next line start + while(*model->text_pos++ != '\n') + ; + } + } else if(lines > 1) { + lines = model->scroll_num - model->scroll_pos - 1; + model->scroll_pos = model->scroll_num - 1; + for(uint8_t i = 0; i < lines; i++) { + // Search next line start + while(*model->text_pos++ != '\n') + ; + } } }, true); } -static void text_box_process_up(TextBox* text_box) { +static void text_box_process_up(TextBox* text_box, uint8_t lines) { with_view_model( text_box->view, TextBoxModel * model, { - if(model->scroll_pos > 0) { - model->scroll_pos--; - // Reach last symbol of previous line - model->text_pos--; - // Search previous line start - while((model->text_pos != model->text) && (*(--model->text_pos) != '\n')) - ; - if(*model->text_pos == '\n') { - model->text_pos++; + if(model->scroll_pos > lines - 1) { + model->scroll_pos -= lines; + for(uint8_t i = 0; i < lines; i++) { + // Reach last symbol of previous line + model->text_pos--; + // Search previous line start + while((model->text_pos != model->text) && (*(--model->text_pos) != '\n')) + ; + if(*model->text_pos == '\n') { + model->text_pos++; + } } + } else if(lines > 1) { + lines = model->scroll_pos; + model->scroll_pos = 0; + model->text_pos = (char*)model->text; } }, true); @@ -120,14 +138,28 @@ static bool text_box_view_input_callback(InputEvent* event, void* context) { TextBox* text_box = context; bool consumed = false; - if(event->type == InputTypeShort) { + if(event->type == InputTypeShort || event->type == InputTypeRepeat) { + int32_t scroll_speed = 1; + if(text_box->button_held_for_ticks > 5) { + if(text_box->button_held_for_ticks % 2) { + scroll_speed = 0; + } else { + scroll_speed = text_box->button_held_for_ticks > 9 ? 5 : 3; + } + } + if(event->key == InputKeyDown) { - text_box_process_down(text_box); + text_box_process_down(text_box, scroll_speed); consumed = true; } else if(event->key == InputKeyUp) { - text_box_process_up(text_box); + text_box_process_up(text_box, scroll_speed); consumed = true; } + + text_box->button_held_for_ticks++; + } else if(event->type == InputTypeRelease) { + text_box->button_held_for_ticks = 0; + consumed = true; } return consumed; } diff --git a/applications/services/dialogs/view_holder.c b/applications/services/gui/view_holder.c similarity index 100% rename from applications/services/dialogs/view_holder.c rename to applications/services/gui/view_holder.c diff --git a/applications/services/dialogs/view_holder.h b/applications/services/gui/view_holder.h similarity index 100% rename from applications/services/dialogs/view_holder.h rename to applications/services/gui/view_holder.h diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index f385efdf95a..ab7876a0366 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -1,20 +1,27 @@ #include "loader.h" #include "loader_i.h" -#include "loader_menu.h" #include +#include #include +#include +#include +#include +#include + #define TAG "Loader" #define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF // api -LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { +LoaderStatus + loader_start(Loader* loader, const char* name, const char* args, FuriString* error_message) { LoaderMessage message; LoaderMessageLoaderStatusResult result; message.type = LoaderMessageTypeStartByName; message.start.name = name; message.start.args = args; + message.start.error_message = error_message; message.api_lock = api_lock_alloc_locked(); message.status_value = &result; furi_message_queue_put(loader->queue, &message, FuriWaitForever); @@ -22,6 +29,31 @@ LoaderStatus loader_start(Loader* loader, const char* name, const char* args) { return result.value; } +LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args) { + FuriString* error_message = furi_string_alloc(); + LoaderStatus status = loader_start(loader, name, args, error_message); + + // TODO: we have many places where we can emit a double start, ex: desktop, menu + // so i prefer to not show LoaderStatusErrorAppStarted error message for now + if(status == LoaderStatusErrorUnknownApp || status == LoaderStatusErrorInternal) { + DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); + dialog_message_set_buttons(message, NULL, NULL, NULL); + + furi_string_replace(error_message, ":", "\n"); + dialog_message_set_text( + message, furi_string_get_cstr(error_message), 64, 32, AlignCenter, AlignCenter); + + dialog_message_show(dialogs, message); + dialog_message_free(message); + furi_record_close(RECORD_DIALOGS); + } + + furi_string_free(error_message); + return status; +} + bool loader_lock(Loader* loader) { LoaderMessage message; LoaderMessageBoolResult result; @@ -73,27 +105,26 @@ static void loader_menu_closed_callback(void* context) { furi_message_queue_put(loader->queue, &message, FuriWaitForever); } -static void loader_menu_click_callback(const char* name, void* context) { +static void loader_applications_closed_callback(void* context) { Loader* loader = context; - loader_start(loader, name, NULL); + LoaderMessage message; + message.type = LoaderMessageTypeApplicationsClosed; + furi_message_queue_put(loader->queue, &message, FuriWaitForever); } static void loader_thread_state_callback(FuriThreadState thread_state, void* context) { furi_assert(context); Loader* loader = context; - LoaderEvent event; if(thread_state == FuriThreadStateRunning) { + LoaderEvent event; event.type = LoaderEventTypeApplicationStarted; furi_pubsub_publish(loader->pubsub, &event); } else if(thread_state == FuriThreadStateStopped) { LoaderMessage message; message.type = LoaderMessageTypeAppClosed; furi_message_queue_put(loader->queue, &message, FuriWaitForever); - - event.type = LoaderEventTypeApplicationStopped; - furi_pubsub_publish(loader->pubsub, &event); } } @@ -104,16 +135,17 @@ static Loader* loader_alloc() { loader->pubsub = furi_pubsub_alloc(); loader->queue = furi_message_queue_alloc(1, sizeof(LoaderMessage)); loader->loader_menu = NULL; + loader->loader_applications = NULL; loader->app.args = NULL; - loader->app.name = NULL; loader->app.thread = NULL; loader->app.insomniac = false; + loader->app.fap = NULL; return loader; } -static FlipperApplication const* loader_find_application_by_name_in_list( +static FlipperInternalApplication const* loader_find_application_by_name_in_list( const char* name, - const FlipperApplication* 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) { @@ -123,8 +155,8 @@ static FlipperApplication const* loader_find_application_by_name_in_list( return NULL; } -static const FlipperApplication* loader_find_application_by_name(const char* name) { - const FlipperApplication* application = NULL; +static const FlipperInternalApplication* loader_find_application_by_name(const char* name) { + const FlipperInternalApplication* application = NULL; application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT); if(!application) { application = loader_find_application_by_name_in_list( @@ -138,25 +170,7 @@ static const FlipperApplication* loader_find_application_by_name(const char* nam return application; } -static void - loader_start_internal_app(Loader* loader, const FlipperApplication* app, const char* args) { - FURI_LOG_I(TAG, "Starting %s", app->name); - - // store args - furi_assert(loader->app.args == NULL); - if(args && strlen(args) > 0) { - loader->app.args = strdup(args); - } - - // store name - furi_assert(loader->app.name == NULL); - loader->app.name = strdup(app->name); - - // setup app thread - loader->app.thread = - furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); - furi_thread_set_appid(loader->app.thread, app->appid); - +static void loader_start_app_thread(Loader* loader, FlipperInternalApplicationFlag flags) { // setup heap trace FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode(); if(mode > FuriHalRtcHeapTrackModeNone) { @@ -166,14 +180,14 @@ static void } // setup insomnia - if(!(app->flags & FlipperApplicationFlagInsomniaSafe)) { + if(!(flags & FlipperInternalApplicationFlagInsomniaSafe)) { furi_hal_power_insomnia_enter(); loader->app.insomniac = true; } else { loader->app.insomniac = false; } - // setup app thread callbacks + // setup thread state callbacks furi_thread_set_state_context(loader->app.thread, loader); furi_thread_set_state_callback(loader->app.thread, loader_thread_state_callback); @@ -181,42 +195,206 @@ static void furi_thread_start(loader->app.thread); } +static void loader_start_internal_app( + Loader* loader, + const FlipperInternalApplication* app, + const char* args) { + FURI_LOG_I(TAG, "Starting %s", app->name); + + // store args + furi_assert(loader->app.args == NULL); + if(args && strlen(args) > 0) { + loader->app.args = strdup(args); + } + + loader->app.thread = + furi_thread_alloc_ex(app->name, app->stack_size, app->app, loader->app.args); + furi_thread_set_appid(loader->app.thread, app->appid); + + loader_start_app_thread(loader, app->flags); +} + +static void loader_log_status_error( + LoaderStatus status, + FuriString* error_message, + const char* format, + va_list args) { + if(error_message) { + furi_string_vprintf(error_message, format, args); + FURI_LOG_E(TAG, "Status [%d]: %s", status, furi_string_get_cstr(error_message)); + } else { + FuriString* tmp = furi_string_alloc(); + FURI_LOG_E(TAG, "Status [%d]: %s", status, furi_string_get_cstr(tmp)); + furi_string_free(tmp); + } +} + +static LoaderStatus loader_make_status_error( + LoaderStatus status, + FuriString* error_message, + const char* format, + ...) { + va_list args; + va_start(args, format); + loader_log_status_error(status, error_message, format, args); + va_end(args); + return status; +} + +static LoaderStatus loader_make_success_status(FuriString* error_message) { + if(error_message) { + furi_string_set(error_message, "App started"); + } + + return LoaderStatusOk; +} + +static LoaderStatus loader_start_external_app( + Loader* loader, + Storage* storage, + const char* path, + const char* args, + FuriString* error_message) { + LoaderStatus status = loader_make_success_status(error_message); + + do { + loader->app.fap = flipper_application_alloc(storage, firmware_api_interface); + size_t start = furi_get_tick(); + + FURI_LOG_I(TAG, "Loading %s", path); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload(loader->app.fap, path); + if(preload_res != FlipperApplicationPreloadStatusSuccess) { + const char* err_msg = flipper_application_preload_status_to_string(preload_res); + status = loader_make_status_error( + LoaderStatusErrorInternal, error_message, "Preload failed %s: %s", path, err_msg); + break; + } + + FURI_LOG_I(TAG, "Mapping"); + FlipperApplicationLoadStatus load_status = + flipper_application_map_to_memory(loader->app.fap); + if(load_status != FlipperApplicationLoadStatusSuccess) { + const char* err_msg = flipper_application_load_status_to_string(load_status); + status = loader_make_status_error( + LoaderStatusErrorInternal, error_message, "Load failed %s: %s", path, err_msg); + break; + } + + FURI_LOG_I(TAG, "Loaded in %zums", (size_t)(furi_get_tick() - start)); + FURI_LOG_I(TAG, "Starting app"); + + loader->app.thread = flipper_application_alloc_thread(loader->app.fap, args); + FuriString* app_name = furi_string_alloc(); + path_extract_filename_no_ext(path, app_name); + furi_thread_set_appid(loader->app.thread, furi_string_get_cstr(app_name)); + furi_string_free(app_name); + + /* This flag is set by the debugger - to break on app start */ + if(furi_hal_debug_is_gdb_session_active()) { + FURI_LOG_W(TAG, "Triggering BP for debugger"); + /* After hitting this, you can set breakpoints in your .fap's code + * Note that you have to toggle breakpoints that were set before */ + __asm volatile("bkpt 0"); + } + + loader_start_app_thread(loader, FlipperInternalApplicationFlagDefault); + } while(0); + + if(status != LoaderStatusOk) { + flipper_application_free(loader->app.fap); + loader->app.fap = NULL; + } + + return status; +} + // process messages static void loader_do_menu_show(Loader* loader) { if(!loader->loader_menu) { - loader->loader_menu = loader_menu_alloc(); - loader_menu_set_closed_callback(loader->loader_menu, loader_menu_closed_callback, loader); - loader_menu_set_click_callback(loader->loader_menu, loader_menu_click_callback, loader); - loader_menu_start(loader->loader_menu); + loader->loader_menu = loader_menu_alloc(loader_menu_closed_callback, loader); } } static void loader_do_menu_closed(Loader* loader) { if(loader->loader_menu) { - loader_menu_stop(loader->loader_menu); loader_menu_free(loader->loader_menu); loader->loader_menu = NULL; } } +static void loader_do_applications_show(Loader* loader) { + if(!loader->loader_applications) { + loader->loader_applications = + loader_applications_alloc(loader_applications_closed_callback, loader); + } +} + +static void loader_do_applications_closed(Loader* loader) { + if(loader->loader_applications) { + loader_applications_free(loader->loader_applications); + loader->loader_applications = NULL; + } +} + static bool loader_do_is_locked(Loader* loader) { return loader->app.thread != NULL; } -static LoaderStatus loader_do_start_by_name(Loader* loader, const char* name, const char* args) { - if(loader_do_is_locked(loader)) { - return LoaderStatusErrorAppStarted; - } +static LoaderStatus loader_do_start_by_name( + Loader* loader, + const char* name, + const char* args, + FuriString* error_message) { + LoaderStatus status; + do { + // check lock + if(loader_do_is_locked(loader)) { + const char* current_thread_name = + furi_thread_get_name(furi_thread_get_id(loader->app.thread)); + status = loader_make_status_error( + LoaderStatusErrorAppStarted, + error_message, + "Loader is locked, please close the \"%s\" first", + current_thread_name); + break; + } + + // check internal apps + { + const FlipperInternalApplication* app = loader_find_application_by_name(name); + if(app) { + loader_start_internal_app(loader, app, args); + status = loader_make_success_status(error_message); + break; + } + } - const FlipperApplication* app = loader_find_application_by_name(name); + // check Applications + if(strcmp(name, LOADER_APPLICATIONS_NAME) == 0) { + loader_do_applications_show(loader); + status = loader_make_success_status(error_message); + break; + } - if(!app) { - return LoaderStatusErrorUnknownApp; - } + // check external apps + { + Storage* storage = furi_record_open(RECORD_STORAGE); + if(storage_file_exists(storage, name)) { + status = loader_start_external_app(loader, storage, name, args, error_message); + furi_record_close(RECORD_STORAGE); + break; + } + furi_record_close(RECORD_STORAGE); + } - loader_start_internal_app(loader, app, args); - return LoaderStatusOk; + status = loader_make_status_error( + LoaderStatusErrorUnknownApp, error_message, "Application \"%s\" not found", name); + } while(false); + + return status; } static bool loader_do_lock(Loader* loader) { @@ -229,13 +407,16 @@ static bool loader_do_lock(Loader* loader) { } static void loader_do_unlock(Loader* loader) { - furi_assert(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); + furi_check(loader->app.thread == (FuriThread*)LOADER_MAGIC_THREAD_VALUE); loader->app.thread = NULL; } static void loader_do_app_closed(Loader* loader) { furi_assert(loader->app.thread); - FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + + furi_thread_join(loader->app.thread); + FURI_LOG_I(TAG, "App returned: %li", furi_thread_get_return_code(loader->app.thread)); + if(loader->app.args) { free(loader->app.args); loader->app.args = NULL; @@ -245,12 +426,20 @@ static void loader_do_app_closed(Loader* loader) { furi_hal_power_insomnia_exit(); } - free(loader->app.name); - loader->app.name = NULL; + if(loader->app.fap) { + flipper_application_free(loader->app.fap); + loader->app.fap = NULL; + loader->app.thread = NULL; + } else { + furi_thread_free(loader->app.thread); + loader->app.thread = NULL; + } - furi_thread_join(loader->app.thread); - furi_thread_free(loader->app.thread); - loader->app.thread = NULL; + FURI_LOG_I(TAG, "Application stopped. Free heap: %zu", memmgr_get_free_heap()); + + LoaderEvent event; + event.type = LoaderEventTypeApplicationStopped; + furi_pubsub_publish(loader->pubsub, &event); } // app @@ -266,7 +455,7 @@ int32_t loader_srv(void* p) { } if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) { - loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL); + loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL, NULL); } LoaderMessage message; @@ -274,8 +463,8 @@ int32_t loader_srv(void* p) { if(furi_message_queue_get(loader->queue, &message, FuriWaitForever) == FuriStatusOk) { switch(message.type) { case LoaderMessageTypeStartByName: - message.status_value->value = - loader_do_start_by_name(loader, message.start.name, message.start.args); + message.status_value->value = loader_do_start_by_name( + loader, message.start.name, message.start.args, message.start.error_message); api_lock_unlock(message.api_lock); break; case LoaderMessageTypeShowMenu: @@ -297,6 +486,10 @@ int32_t loader_srv(void* p) { break; case LoaderMessageTypeUnlock: loader_do_unlock(loader); + break; + case LoaderMessageTypeApplicationsClosed: + loader_do_applications_closed(loader); + break; } } } diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index e3a691b768c..9fc4059f2d9 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -6,6 +6,7 @@ extern "C" { #endif #define RECORD_LOADER "loader" +#define LOADER_APPLICATIONS_NAME "Applications" typedef struct Loader Loader; @@ -25,28 +26,57 @@ typedef struct { LoaderEventType type; } LoaderEvent; -/** Start application - * @param name - application name - * @param args - application arguments - * @retval true on success +/** + * @brief Start application + * @param[in] instance loader instance + * @param[in] name application name + * @param[in] args application arguments + * @param[out] error_message detailed error message, can be NULL + * @return LoaderStatus */ -LoaderStatus loader_start(Loader* instance, const char* name, const char* args); +LoaderStatus + loader_start(Loader* instance, const char* name, const char* args, FuriString* error_message); -/** Lock application start - * @retval true on success +/** + * @brief Start application with GUI error message + * @param[in] instance loader instance + * @param[in] name application name + * @param[in] args application arguments + * @return LoaderStatus + */ +LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const char* args); + +/** + * @brief Lock application start + * @param[in] instance loader instance + * @return true on success */ bool loader_lock(Loader* instance); -/** Unlock application start */ +/** + * @brief Unlock application start + * @param[in] instance loader instance + */ void loader_unlock(Loader* instance); -/** Get loader lock status */ +/** + * @brief Check if loader is locked + * @param[in] instance loader instance + * @return true if locked + */ bool loader_is_locked(Loader* instance); -/** Show primary loader */ +/** + * @brief Show loader menu + * @param[in] instance loader instance + */ void loader_show_menu(Loader* instance); -/** Show primary loader */ +/** + * @brief Get loader pubsub + * @param[in] instance loader instance + * @return FuriPubSub* + */ FuriPubSub* loader_get_pubsub(Loader* instance); #ifdef __cplusplus diff --git a/applications/services/loader/loader_applications.c b/applications/services/loader/loader_applications.c new file mode 100644 index 00000000000..1801edef9f9 --- /dev/null +++ b/applications/services/loader/loader_applications.c @@ -0,0 +1,146 @@ +#include "loader.h" +#include "loader_applications.h" +#include +#include +#include +#include +#include +#include + +#define TAG "LoaderApplications" + +struct LoaderApplications { + FuriThread* thread; + void (*closed_cb)(void*); + void* context; +}; + +static int32_t loader_applications_thread(void* p); + +LoaderApplications* loader_applications_alloc(void (*closed_cb)(void*), void* context) { + LoaderApplications* loader_applications = malloc(sizeof(LoaderApplications)); + loader_applications->thread = + furi_thread_alloc_ex(TAG, 512, loader_applications_thread, (void*)loader_applications); + loader_applications->closed_cb = closed_cb; + loader_applications->context = context; + furi_thread_start(loader_applications->thread); + return loader_applications; +} + +void loader_applications_free(LoaderApplications* loader_applications) { + furi_assert(loader_applications); + furi_thread_join(loader_applications->thread); + furi_thread_free(loader_applications->thread); + free(loader_applications); +} + +typedef struct { + FuriString* fap_path; + DialogsApp* dialogs; + Storage* storage; +} LoaderApplicationsApp; + +static LoaderApplicationsApp* loader_applications_app_alloc() { + LoaderApplicationsApp* app = malloc(sizeof(LoaderApplicationsApp)); //-V799 + app->fap_path = furi_string_alloc_set(EXT_PATH("apps")); + app->dialogs = furi_record_open(RECORD_DIALOGS); + app->storage = furi_record_open(RECORD_STORAGE); + return app; +} //-V773 + +static void loader_applications_app_free(LoaderApplicationsApp* loader_applications_app) { + furi_assert(loader_applications_app); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_STORAGE); + furi_string_free(loader_applications_app->fap_path); + free(loader_applications_app); +} + +static bool loader_applications_item_callback( + FuriString* path, + void* context, + uint8_t** icon_ptr, + FuriString* item_name) { + LoaderApplicationsApp* loader_applications_app = context; + furi_assert(loader_applications_app); + return flipper_application_load_name_and_icon( + path, loader_applications_app->storage, icon_ptr, item_name); +} + +static bool loader_applications_select_app(LoaderApplicationsApp* loader_applications_app) { + const DialogsFileBrowserOptions browser_options = { + .extension = ".fap", + .skip_assets = true, + .icon = &I_unknown_10px, + .hide_ext = true, + .item_loader_callback = loader_applications_item_callback, + .item_loader_context = loader_applications_app, + .base_path = EXT_PATH("apps"), + }; + + return dialog_file_browser_show( + loader_applications_app->dialogs, + loader_applications_app->fap_path, + loader_applications_app->fap_path, + &browser_options); +} + +#define APPLICATION_STOP_EVENT 1 + +static void loader_pubsub_callback(const void* message, void* context) { + const LoaderEvent* event = message; + const FuriThreadId thread_id = (FuriThreadId)context; + + if(event->type == LoaderEventTypeApplicationStopped) { + furi_thread_flags_set(thread_id, APPLICATION_STOP_EVENT); + } +} + +static void loader_applications_start_app(const char* name) { + // start loading animation + Gui* gui = furi_record_open(RECORD_GUI); + ViewHolder* view_holder = view_holder_alloc(); + Loading* loading = loading_alloc(); + + view_holder_attach_to_gui(view_holder, gui); + view_holder_set_view(view_holder, loading_get_view(loading)); + view_holder_start(view_holder); + + // load app + FuriThreadId thread_id = furi_thread_get_current_id(); + Loader* loader = furi_record_open(RECORD_LOADER); + FuriPubSubSubscription* subscription = + furi_pubsub_subscribe(loader_get_pubsub(loader), loader_pubsub_callback, thread_id); + + LoaderStatus status = loader_start_with_gui_error(loader, name, NULL); + + if(status == LoaderStatusOk) { + furi_thread_flags_wait(APPLICATION_STOP_EVENT, FuriFlagWaitAny, FuriWaitForever); + } + + furi_pubsub_unsubscribe(loader_get_pubsub(loader), subscription); + furi_record_close(RECORD_LOADER); + + // stop loading animation + view_holder_stop(view_holder); + view_holder_free(view_holder); + loading_free(loading); + furi_record_close(RECORD_GUI); +} + +static int32_t loader_applications_thread(void* p) { + LoaderApplications* loader_applications = p; + LoaderApplicationsApp* loader_applications_app = loader_applications_app_alloc(); + + while(loader_applications_select_app(loader_applications_app)) { + loader_applications_start_app(furi_string_get_cstr(loader_applications_app->fap_path)); + } + + loader_applications_app_free(loader_applications_app); + + if(loader_applications->closed_cb) { + loader_applications->closed_cb(loader_applications->context); + } + + return 0; +} \ No newline at end of file diff --git a/applications/services/loader/loader_applications.h b/applications/services/loader/loader_applications.h new file mode 100644 index 00000000000..6b132af0559 --- /dev/null +++ b/applications/services/loader/loader_applications.h @@ -0,0 +1,16 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LoaderApplications LoaderApplications; + +LoaderApplications* loader_applications_alloc(void (*closed_cb)(void*), void* context); + +void loader_applications_free(LoaderApplications* loader_applications); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/services/loader/loader_cli.c b/applications/services/loader/loader_cli.c index 2d460221578..af3ebf9e002 100644 --- a/applications/services/loader/loader_cli.c +++ b/applications/services/loader/loader_cli.c @@ -50,21 +50,11 @@ static void loader_cli_open(FuriString* args, Loader* loader) { const char* app_name_str = furi_string_get_cstr(app_name); - LoaderStatus status = loader_start(loader, app_name_str, args_str); - - switch(status) { - case LoaderStatusOk: - break; - case LoaderStatusErrorAppStarted: - printf("Can't start, application is running"); - break; - case LoaderStatusErrorUnknownApp: - printf("%s doesn't exists\r\n", app_name_str); - break; - case LoaderStatusErrorInternal: - printf("Internal error\r\n"); - break; + FuriString* error_message = furi_string_alloc(); + if(loader_start(loader, app_name_str, args_str, error_message) != LoaderStatusOk) { + printf("%s\r\n", furi_string_get_cstr(error_message)); } + furi_string_free(error_message); } while(false); furi_string_free(app_name); diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 2e3f10dad02..688b8fb665c 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -1,20 +1,23 @@ #pragma once #include #include +#include #include "loader.h" #include "loader_menu.h" +#include "loader_applications.h" typedef struct { char* args; - char* name; FuriThread* thread; bool insomniac; + FlipperApplication* fap; } LoaderAppData; struct Loader { FuriPubSub* pubsub; FuriMessageQueue* queue; LoaderMenu* loader_menu; + LoaderApplications* loader_applications; LoaderAppData app; }; @@ -23,6 +26,7 @@ typedef enum { LoaderMessageTypeAppClosed, LoaderMessageTypeShowMenu, LoaderMessageTypeMenuClosed, + LoaderMessageTypeApplicationsClosed, LoaderMessageTypeLock, LoaderMessageTypeUnlock, LoaderMessageTypeIsLocked, @@ -31,6 +35,7 @@ typedef enum { typedef struct { const char* name; const char* args; + FuriString* error_message; } LoaderMessageStartByName; typedef struct { diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c index ec853661fbb..28283f85cd2 100644 --- a/applications/services/loader/loader_menu.c +++ b/applications/services/loader/loader_menu.c @@ -5,106 +5,76 @@ #include #include +#include "loader.h" #include "loader_menu.h" #define TAG "LoaderMenu" struct LoaderMenu { - Gui* gui; - ViewDispatcher* view_dispatcher; - Menu* primary_menu; - Submenu* settings_menu; - - void (*closed_callback)(void*); - void* closed_callback_context; - - void (*click_callback)(const char*, void*); - void* click_callback_context; - FuriThread* thread; + void (*closed_cb)(void*); + void* context; }; -typedef enum { - LoaderMenuViewPrimary, - LoaderMenuViewSettings, -} LoaderMenuView; - static int32_t loader_menu_thread(void* p); -LoaderMenu* loader_menu_alloc() { +LoaderMenu* loader_menu_alloc(void (*closed_cb)(void*), void* context) { LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); - loader_menu->gui = furi_record_open(RECORD_GUI); - loader_menu->view_dispatcher = view_dispatcher_alloc(); - loader_menu->primary_menu = menu_alloc(); - loader_menu->settings_menu = submenu_alloc(); - loader_menu->thread = NULL; - return loader_menu; -} - -void loader_menu_free(LoaderMenu* loader_menu) { - furi_assert(loader_menu); - // check if thread is running - furi_assert(!loader_menu->thread); - - submenu_free(loader_menu->settings_menu); - menu_free(loader_menu->primary_menu); - view_dispatcher_free(loader_menu->view_dispatcher); - furi_record_close(RECORD_GUI); - free(loader_menu); -} - -void loader_menu_start(LoaderMenu* loader_menu) { - furi_assert(loader_menu); - furi_assert(!loader_menu->thread); + loader_menu->closed_cb = closed_cb; + loader_menu->context = context; loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); furi_thread_start(loader_menu->thread); + return loader_menu; } -void loader_menu_stop(LoaderMenu* loader_menu) { +void loader_menu_free(LoaderMenu* loader_menu) { furi_assert(loader_menu); - furi_assert(loader_menu->thread); - view_dispatcher_stop(loader_menu->view_dispatcher); furi_thread_join(loader_menu->thread); furi_thread_free(loader_menu->thread); - loader_menu->thread = NULL; + free(loader_menu); } -void loader_menu_set_closed_callback( - LoaderMenu* loader_menu, - void (*callback)(void*), - void* context) { - loader_menu->closed_callback = callback; - loader_menu->closed_callback_context = context; -} +typedef enum { + LoaderMenuViewPrimary, + LoaderMenuViewSettings, +} LoaderMenuView; + +typedef struct { + Gui* gui; + ViewDispatcher* view_dispatcher; + Menu* primary_menu; + Submenu* settings_menu; +} LoaderMenuApp; -void loader_menu_set_click_callback( - LoaderMenu* loader_menu, - void (*callback)(const char*, void*), - void* context) { - loader_menu->click_callback = callback; - loader_menu->click_callback_context = context; +static void loader_menu_start(const char* name) { + Loader* loader = furi_record_open(RECORD_LOADER); + loader_start_with_gui_error(loader, name, NULL); + furi_record_close(RECORD_LOADER); } static void loader_menu_callback(void* context, uint32_t index) { - LoaderMenu* loader_menu = context; + UNUSED(context); const char* name = FLIPPER_APPS[index].name; - if(loader_menu->click_callback) { - loader_menu->click_callback(name, loader_menu->click_callback_context); - } + loader_menu_start(name); +} + +static void loader_menu_applications_callback(void* context, uint32_t index) { + UNUSED(index); + UNUSED(context); + const char* name = LOADER_APPLICATIONS_NAME; + loader_menu_start(name); } static void loader_menu_settings_menu_callback(void* context, uint32_t index) { - LoaderMenu* loader_menu = context; + UNUSED(context); const char* name = FLIPPER_SETTINGS_APPS[index].name; - if(loader_menu->click_callback) { - loader_menu->click_callback(name, loader_menu->click_callback_context); - } + loader_menu_start(name); } static void loader_menu_switch_to_settings(void* context, uint32_t index) { UNUSED(index); - LoaderMenu* loader_menu = context; - view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + LoaderMenuApp* app = context; + view_dispatcher_switch_to_view(app->view_dispatcher, LoaderMenuViewSettings); } static uint32_t loader_menu_switch_to_primary(void* context) { @@ -117,30 +87,32 @@ static uint32_t loader_menu_exit(void* context) { return VIEW_NONE; } -static void loader_menu_build_menu(LoaderMenu* loader_menu) { +static void loader_menu_build_menu(LoaderMenuApp* app, LoaderMenu* menu) { size_t i; for(i = 0; i < FLIPPER_APPS_COUNT; i++) { menu_add_item( - loader_menu->primary_menu, + app->primary_menu, FLIPPER_APPS[i].name, FLIPPER_APPS[i].icon, i, loader_menu_callback, - (void*)loader_menu); + (void*)menu); } menu_add_item( - loader_menu->primary_menu, - "Settings", - &A_Settings_14, + app->primary_menu, "Settings", &A_Settings_14, i++, loader_menu_switch_to_settings, app); + menu_add_item( + app->primary_menu, + LOADER_APPLICATIONS_NAME, + &A_Plugins_14, i++, - loader_menu_switch_to_settings, - loader_menu); + loader_menu_applications_callback, + (void*)menu); }; -static void loader_menu_build_submenu(LoaderMenu* loader_menu) { +static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_menu) { for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { submenu_add_item( - loader_menu->settings_menu, + app->settings_menu, FLIPPER_SETTINGS_APPS[i].name, i, loader_menu_settings_menu_callback, @@ -148,40 +120,59 @@ static void loader_menu_build_submenu(LoaderMenu* loader_menu) { } } -static int32_t loader_menu_thread(void* p) { - LoaderMenu* loader_menu = p; - furi_assert(loader_menu); - - loader_menu_build_menu(loader_menu); - loader_menu_build_submenu(loader_menu); +static LoaderMenuApp* loader_menu_app_alloc(LoaderMenu* loader_menu) { + LoaderMenuApp* app = malloc(sizeof(LoaderMenuApp)); + app->gui = furi_record_open(RECORD_GUI); + app->view_dispatcher = view_dispatcher_alloc(); + app->primary_menu = menu_alloc(); + app->settings_menu = submenu_alloc(); - view_dispatcher_attach_to_gui( - loader_menu->view_dispatcher, loader_menu->gui, ViewDispatcherTypeFullscreen); + loader_menu_build_menu(app, loader_menu); + loader_menu_build_submenu(app, loader_menu); // Primary menu - View* primary_view = menu_get_view(loader_menu->primary_menu); - view_set_context(primary_view, loader_menu->primary_menu); + View* primary_view = menu_get_view(app->primary_menu); + view_set_context(primary_view, app->primary_menu); view_set_previous_callback(primary_view, loader_menu_exit); - view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary, primary_view); + view_dispatcher_add_view(app->view_dispatcher, LoaderMenuViewPrimary, primary_view); // Settings menu - View* settings_view = submenu_get_view(loader_menu->settings_menu); - view_set_context(settings_view, loader_menu->settings_menu); + View* settings_view = submenu_get_view(app->settings_menu); + view_set_context(settings_view, app->settings_menu); view_set_previous_callback(settings_view, loader_menu_switch_to_primary); - view_dispatcher_add_view(loader_menu->view_dispatcher, LoaderMenuViewSettings, settings_view); + view_dispatcher_add_view(app->view_dispatcher, LoaderMenuViewSettings, settings_view); - view_dispatcher_enable_queue(loader_menu->view_dispatcher); - view_dispatcher_switch_to_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_enable_queue(app->view_dispatcher); + view_dispatcher_switch_to_view(app->view_dispatcher, LoaderMenuViewPrimary); - // run view dispatcher - view_dispatcher_run(loader_menu->view_dispatcher); + return app; +} + +static void loader_menu_app_free(LoaderMenuApp* app) { + view_dispatcher_remove_view(app->view_dispatcher, LoaderMenuViewPrimary); + view_dispatcher_remove_view(app->view_dispatcher, LoaderMenuViewSettings); + view_dispatcher_free(app->view_dispatcher); - view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewPrimary); - view_dispatcher_remove_view(loader_menu->view_dispatcher, LoaderMenuViewSettings); + menu_free(app->primary_menu); + submenu_free(app->settings_menu); + furi_record_close(RECORD_GUI); + free(app); +} - if(loader_menu->closed_callback) { - loader_menu->closed_callback(loader_menu->closed_callback_context); +static int32_t loader_menu_thread(void* p) { + LoaderMenu* loader_menu = p; + furi_assert(loader_menu); + + LoaderMenuApp* app = loader_menu_app_alloc(loader_menu); + + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_run(app->view_dispatcher); + + if(loader_menu->closed_cb) { + loader_menu->closed_cb(loader_menu->context); } + loader_menu_app_free(app); + return 0; } \ No newline at end of file diff --git a/applications/services/loader/loader_menu.h b/applications/services/loader/loader_menu.h index 7405b87be77..528fe7d291c 100644 --- a/applications/services/loader/loader_menu.h +++ b/applications/services/loader/loader_menu.h @@ -7,24 +7,10 @@ extern "C" { typedef struct LoaderMenu LoaderMenu; -LoaderMenu* loader_menu_alloc(); +LoaderMenu* loader_menu_alloc(void (*closed_cb)(void*), void* context); void loader_menu_free(LoaderMenu* loader_menu); -void loader_menu_start(LoaderMenu* loader_menu); - -void loader_menu_stop(LoaderMenu* loader_menu); - -void loader_menu_set_closed_callback( - LoaderMenu* loader_menu, - void (*callback)(void*), - void* context); - -void loader_menu_set_click_callback( - LoaderMenu* loader_menu, - void (*callback)(const char*, void*), - void* context); - #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/applications/services/rpc/rpc_app.c b/applications/services/rpc/rpc_app.c index cc18b6cec37..bf44ed2deed 100644 --- a/applications/services/rpc/rpc_app.c +++ b/applications/services/rpc/rpc_app.c @@ -52,7 +52,7 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context) snprintf(args_temp, RPC_SYSTEM_APP_TEMP_ARGS_SIZE, "RPC %08lX", (uint32_t)rpc_app); app_args = args_temp; } - LoaderStatus status = loader_start(loader, app_name, app_args); + LoaderStatus status = loader_start(loader, app_name, app_args, NULL); if(status == LoaderStatusErrorAppStarted) { result = PB_CommandStatus_ERROR_APP_SYSTEM_LOCKED; } else if(status == LoaderStatusErrorInternal) { diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 4b5c4792123..698cfae1b81 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -3,7 +3,6 @@ #include "desktop_settings_scene.h" #include #include -#include #define EXTERNAL_APPLICATION_NAME ("[External Application]") #define EXTERNAL_APPLICATION_INDEX (FLIPPER_APPS_COUNT + 1) @@ -65,7 +64,6 @@ void desktop_settings_scene_favorite_on_enter(void* context) { } } -#ifdef APP_FAP_LOADER submenu_add_item( submenu, EXTERNAL_APPLICATION_NAME, @@ -75,7 +73,6 @@ void desktop_settings_scene_favorite_on_enter(void* context) { if(curr_favorite_app->is_external) { pre_select_item = EXTERNAL_APPLICATION_INDEX; } -#endif submenu_set_header( submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:"); 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 9c91b926680..25893f01106 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 @@ -172,7 +172,7 @@ static void storage_move_to_sd_mount_callback(const void* message, void* context if(storage_event->type == StorageEventTypeCardMount) { Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "StorageMoveToSd", NULL); + loader_start(loader, "StorageMoveToSd", NULL, NULL); furi_record_close(RECORD_LOADER); } } diff --git a/applications/system/updater/cli/updater_cli.c b/applications/system/updater/cli/updater_cli.c index 659c431f701..cebdc4d7cab 100644 --- a/applications/system/updater/cli/updater_cli.c +++ b/applications/system/updater/cli/updater_cli.c @@ -99,7 +99,7 @@ static void updater_start_app(void* context, uint32_t arg) { * So, accessing its record would cause a deadlock */ Loader* loader = furi_record_open(RECORD_LOADER); - loader_start(loader, "UpdaterApp", NULL); + loader_start(loader, "UpdaterApp", NULL, NULL); furi_record_close(RECORD_LOADER); } diff --git a/assets/icons/SubGhz/External_antenna_20x12.png b/assets/icons/SubGhz/External_antenna_20x12.png new file mode 100644 index 00000000000..940087071a1 Binary files /dev/null and b/assets/icons/SubGhz/External_antenna_20x12.png differ diff --git a/assets/icons/SubGhz/Internal_antenna_20x12.png b/assets/icons/SubGhz/Internal_antenna_20x12.png new file mode 100644 index 00000000000..a8a5be09fb8 Binary files /dev/null and b/assets/icons/SubGhz/Internal_antenna_20x12.png differ diff --git a/assets/icons/SubGhz/Scanning_123x52.png b/assets/icons/SubGhz/Scanning_123x52.png deleted file mode 100644 index ec785948d03..00000000000 Binary files a/assets/icons/SubGhz/Scanning_123x52.png and /dev/null differ diff --git a/assets/icons/SubGhz/Scanning_short_96x52.png b/assets/icons/SubGhz/Scanning_short_96x52.png new file mode 100644 index 00000000000..718d0e695a2 Binary files /dev/null and b/assets/icons/SubGhz/Scanning_short_96x52.png differ diff --git a/assets/resources/badusb/assets/layouts/fr-FR-mac.kl b/assets/resources/badusb/assets/layouts/fr-FR-mac.kl index 0906936547c..2887aae0fda 100644 Binary files a/assets/resources/badusb/assets/layouts/fr-FR-mac.kl and b/assets/resources/badusb/assets/layouts/fr-FR-mac.kl differ diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 142c49243c3..c7b1aaf7e87 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -470,3 +470,40 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 4467 4390 571 1583 572 505 595 1560 572 1583 572 505 572 505 596 1559 596 482 596 481 597 1559 626 451 655 422 625 1529 596 1559 596 481 572 1582 573 1583 571 505 572 1583 595 1560 594 1561 592 1562 594 1561 593 1562 593 484 593 1563 592 485 592 485 592 485 592 485 593 484 593 485 592 485 592 1562 593 485 592 1563 592 1562 593 1562 594 483 593 485 593 1562 592 485 593 1561 593 484 593 484 593 484 593 1562 593 1562 592 5163 4462 4370 592 1563 593 484 592 1563 592 1563 592 485 592 485 593 1562 593 484 593 485 592 1562 593 484 593 485 592 1562 593 1562 593 485 592 1563 592 1563 592 485 592 1563 592 1562 593 1562 593 1563 592 1563 592 1562 592 485 593 1562 592 485 592 485 592 485 592 485 592 485 592 485 592 485 592 1563 592 485 592 1563 591 1563 592 1563 593 485 592 485 592 1563 592 485 592 1563 591 485 593 485 592 485 592 1563 592 1563 591 +# +# Model: Mitsubishi MSZ-AP25VGK +name: Off +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3531 1667 500 1225 499 1225 499 376 499 377 498 377 498 1224 500 377 498 377 498 1224 500 1225 499 377 527 1195 557 318 556 318 555 1167 530 1194 529 374 499 1224 499 1225 497 377 497 378 497 1228 496 379 496 380 495 1229 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 496 380 495 380 495 380 495 380 495 9028 3526 1672 495 1229 495 1229 495 380 495 380 495 380 495 1230 494 380 495 380 495 1229 495 1229 495 380 495 1229 495 380 495 380 495 1229 495 1229 495 380 495 1229 495 1229 495 380 495 380 495 1229 495 380 495 380 495 1229 495 380 495 381 494 381 494 380 495 380 495 380 495 380 495 381 494 380 495 381 494 381 494 381 494 381 494 381 494 380 495 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 1230 494 1230 494 381 494 381 494 381 494 381 494 381 494 381 494 1230 494 381 494 381 494 381 494 381 494 381 494 1230 494 1230 494 381 494 1230 494 1230 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 1230 494 381 494 1230 494 381 494 381 494 1230 494 381 494 1230 494 1230 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 1231 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 1231 493 382 493 1231 493 382 493 1231 493 382 493 383 492 382 493 +# +name: Dh +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3561 1666 500 1195 529 1193 531 374 501 375 500 375 500 1196 529 374 501 375 500 1223 501 1223 501 375 529 1194 558 318 557 318 555 1168 530 1193 530 345 529 1194 529 1196 527 348 526 350 525 1200 524 352 522 353 522 1228 496 379 496 379 496 379 496 379 496 379 496 379 497 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 9028 3529 1670 496 1228 496 1228 496 379 496 379 496 379 496 1228 496 379 496 379 496 1228 496 1228 496 379 496 1228 496 379 496 379 496 1228 496 1228 496 379 496 1228 496 1228 496 379 496 379 496 1228 496 379 496 379 496 1228 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 380 495 379 496 379 496 379 496 379 496 380 495 379 496 380 495 379 496 1229 495 380 495 380 495 379 496 380 495 380 495 380 495 1229 495 380 495 380 495 380 495 380 495 380 495 380 495 1229 495 380 495 380 495 380 495 380 495 380 495 1229 495 380 495 380 495 1229 495 1229 495 380 495 380 495 380 495 380 495 380 496 380 495 380 495 380 495 1229 495 380 495 1229 495 380 495 380 495 1229 495 380 495 1229 495 1229 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 381 494 380 495 380 495 380 495 380 495 1230 494 380 495 381 494 381 494 380 495 380 495 380 495 380 495 381 494 381 495 380 495 381 494 381 495 380 495 381 494 381 495 380 495 381 494 381 494 381 494 381 494 381 494 381 494 381 494 1230 494 381 494 381 494 1230 494 381 494 1230 494 381 494 381 494 +# +name: Cool_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3534 1637 530 1192 533 1195 529 375 500 375 500 375 500 1195 530 375 501 375 500 1224 500 1224 501 376 528 1195 557 319 556 318 555 1168 530 1193 530 345 530 1194 529 1196 527 348 526 350 525 1201 523 353 522 378 497 1228 496 379 497 379 496 379 497 379 496 379 497 379 497 379 497 379 496 379 496 379 496 379 496 379 497 379 497 379 496 379 496 9030 3530 1671 496 1229 496 1229 495 379 496 379 496 379 497 1229 496 379 496 379 497 1229 496 1229 495 380 496 1229 495 379 497 379 496 1229 496 1229 495 379 497 1229 495 1228 497 379 496 380 496 1229 496 379 497 379 496 1229 496 379 496 380 496 380 495 380 496 379 496 380 496 380 495 380 496 380 496 380 496 379 496 380 496 380 495 380 496 380 495 380 496 380 495 380 496 380 495 380 495 1229 496 380 495 380 495 380 495 380 496 380 495 1229 496 1229 496 380 495 380 496 380 495 380 496 380 496 380 495 380 495 380 496 380 496 380 495 380 496 380 495 1229 495 1230 495 380 495 1229 496 1229 496 380 495 381 495 380 495 380 495 380 496 380 496 380 495 380 496 1229 496 380 495 1230 495 380 495 380 495 1230 495 380 495 1230 495 1230 495 380 495 380 496 380 495 380 495 380 495 380 496 380 496 380 495 380 496 380 495 380 495 380 496 380 495 381 495 380 495 380 495 380 495 381 495 380 495 381 495 380 495 381 494 381 495 381 495 380 495 1230 495 381 495 380 495 381 494 381 495 381 494 381 495 381 494 381 495 381 495 381 494 381 495 381 494 381 495 381 495 381 494 381 495 381 494 381 494 381 495 381 494 381 494 381 494 381 495 1230 495 381 495 1230 495 1230 495 381 494 1230 494 381 495 381 494 +# +name: Cool_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3534 1667 500 1224 501 1224 501 376 500 375 500 376 500 1224 501 376 500 376 499 1224 501 1225 500 376 500 1225 556 320 556 318 555 1167 530 1194 530 345 530 1195 529 1196 528 348 527 377 498 1227 498 378 497 379 496 1229 496 379 496 379 497 379 497 379 497 379 497 380 496 379 497 379 496 379 497 380 496 380 496 380 496 380 496 379 497 379 497 9033 3530 1672 496 1229 496 1229 496 380 496 380 496 380 496 1229 496 380 496 380 496 1229 496 1229 496 380 496 1229 496 380 496 380 496 1229 496 1229 496 380 496 1230 495 1229 496 380 495 380 496 1229 496 380 496 380 496 1229 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 495 380 496 380 496 380 496 380 496 380 496 380 496 380 496 1230 495 380 496 380 495 380 496 381 495 380 495 1230 495 1230 495 380 496 380 496 380 496 1230 495 1230 495 1230 495 380 496 380 496 380 496 380 496 380 496 381 495 1230 495 1230 495 381 495 1230 495 1230 495 380 495 381 495 381 495 381 495 381 495 381 495 380 496 381 495 1230 495 381 495 1230 495 381 495 380 496 1230 495 381 495 1230 495 1230 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 380 496 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 1231 494 381 495 381 495 381 495 381 495 381 495 381 494 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 382 494 382 494 1231 494 381 495 1231 494 1231 494 381 495 382 494 +# +name: Heat_hi +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3539 1670 501 1226 502 1226 501 376 501 377 500 376 501 1226 501 376 499 378 500 1226 501 1226 501 377 528 1199 557 320 557 318 529 1197 531 1195 531 346 530 1196 530 1198 528 349 527 352 524 1229 498 379 498 379 498 1230 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 9045 3536 1674 496 1231 497 1231 497 380 497 380 497 380 497 1231 496 380 497 380 497 1231 497 1231 496 380 497 1231 496 380 497 380 497 1231 496 1231 497 380 497 1231 496 1231 496 380 497 380 497 1231 496 381 496 380 497 1231 497 381 496 380 497 380 497 380 497 380 497 381 496 381 496 381 496 380 497 380 497 381 496 381 496 381 496 381 496 380 497 381 496 381 496 381 496 381 496 380 497 1231 496 381 496 381 496 380 497 381 496 381 496 1232 495 381 496 381 496 381 496 381 496 1232 495 1232 495 1232 496 1232 495 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 1232 496 1232 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 1232 496 381 496 1232 495 381 496 1232 495 381 496 1232 495 1232 495 381 496 381 496 382 495 381 496 381 496 381 496 381 496 382 495 381 496 381 496 381 496 381 496 381 496 382 495 381 496 381 496 381 496 381 496 382 495 382 495 382 495 382 495 382 495 382 495 382 495 1232 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 1233 495 1233 494 1233 495 382 495 382 495 1233 495 1233 494 382 495 +# +name: Heat_lo +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3539 1637 533 1225 502 1193 534 375 501 376 501 376 500 1226 501 376 501 376 500 1226 500 1227 501 376 529 1197 558 320 557 319 555 1169 531 1195 531 346 529 1196 530 1198 528 349 526 352 524 1229 497 379 497 379 497 1230 497 380 497 380 497 379 498 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 9042 3535 1674 496 1230 497 1230 497 380 497 380 497 380 497 1230 497 380 497 380 496 1230 497 1230 497 380 497 1230 497 380 497 380 497 1231 496 1230 497 380 497 1231 496 1231 496 380 496 380 497 1231 496 380 497 380 496 1231 496 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 496 380 497 380 497 380 497 380 497 380 496 381 496 380 497 380 497 380 497 381 496 1231 496 381 496 380 497 380 497 381 496 381 496 1231 496 381 496 381 496 380 497 381 495 1231 496 1231 496 1231 496 380 497 381 496 381 496 380 496 381 496 381 496 381 496 381 496 381 496 1231 496 1231 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 1231 496 381 496 381 496 1232 495 381 495 1232 495 381 496 1231 496 1231 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 495 381 496 381 496 381 496 381 496 1232 495 381 496 381 496 381 496 381 496 381 495 381 496 381 495 382 495 381 496 382 495 381 495 382 495 381 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 381 495 1232 495 1232 495 1232 495 1232 495 1232 495 382 495 382 495 382 495 diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index b45171cb142..ba8807123c9 100644 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1675,3 +1675,9 @@ type: parsed protocol: NEC address: 04 00 00 00 command: 03 00 00 00 +# +name: Power +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3462 1592 490 332 513 1200 489 331 514 1201 489 355 490 1201 489 356 512 1178 489 356 512 1178 512 334 487 1202 488 1202 488 357 512 1178 512 334 486 1203 487 1202 488 1203 487 1204 486 383 461 1228 488 357 488 357 487 357 487 1203 486 1204 486 359 485 1205 485 360 485 361 484 360 485 360 485 361 484 361 484 361 484 1206 484 360 484 361 484 361 484 1206 484 361 484 361 484 361 484 1206 484 361 484 1206 484 361 484 71543 3434 1620 486 359 485 1205 485 360 485 1206 484 360 485 1206 484 360 485 1206 484 360 485 1206 484 360 485 1205 485 1206 484 360 485 1206 484 360 485 1206 484 1206 484 1206 484 1206 484 361 484 1206 484 360 485 360 485 361 484 1206 484 1206 484 360 484 1206 484 360 485 361 484 361 484 360 485 361 484 361 484 361 484 1206 484 361 484 361 484 361 484 1206 484 361 484 361 484 361 484 1207 483 361 484 1206 484 361 484 71543 3435 1619 486 358 486 1204 486 359 486 1205 485 360 485 1205 485 360 485 1205 485 360 485 1205 485 360 484 1205 485 1205 485 360 485 1205 485 360 485 1205 485 1205 485 1205 485 1206 484 360 485 1205 485 360 485 360 485 360 485 1205 485 1206 484 360 485 1206 484 360 485 360 485 360 485 360 485 360 485 360 485 360 485 1206 484 360 485 360 485 360 485 1206 484 360 485 360 485 360 485 1205 485 360 485 1206 484 360 485 71542 3436 1619 486 358 487 1204 486 359 485 1205 485 360 485 1205 485 360 485 1205 485 360 485 1205 485 360 485 1205 485 1205 485 360 485 1205 485 360 485 1206 484 1206 484 1206 484 1206 484 360 485 1206 484 360 485 360 485 361 484 1206 484 1206 484 361 484 1206 484 361 484 361 484 361 484 361 484 361 484 361 484 360 485 1206 484 361 484 361 484 361 484 1206 484 361 484 361 484 360 485 1206 484 361 484 1206 484 361 484 71542 3437 1618 487 358 486 1204 486 359 486 1205 485 360 485 1205 485 360 485 1205 485 360 485 1205 485 360 485 1205 485 1206 484 360 485 1205 485 360 485 1206 484 1205 485 1206 484 1205 485 360 485 1205 485 360 485 360 485 360 485 1205 485 1205 485 360 485 1205 485 360 485 360 485 360 485 360 485 360 485 360 485 360 485 1205 485 360 485 360 485 360 485 1205 485 360 485 360 485 360 485 1205 485 360 485 1205 485 360 485 diff --git a/documentation/FuriHalBus.md b/documentation/FuriHalBus.md index 5c754018b93..230a98050fd 100644 --- a/documentation/FuriHalBus.md +++ b/documentation/FuriHalBus.md @@ -78,9 +78,9 @@ The system will take over any given peripheral only when the respective feature | ADC | | | | QUADSPI | | | | TIM1 | yes | subghz, lfrfid, nfc, infrared, etc... | -| TIM2 | yes | -- | +| TIM2 | yes | subghz, infrared, etc... | | TIM16 | yes | speaker | -| TIM17 | | | +| TIM17 | yes | cc1101_ext | | LPTIM1 | yes | tickless idle timer | | LPTIM2 | yes | pwm | | SAI1 | | | @@ -104,10 +104,10 @@ Below is the list of DMA channels and their usage by the system. | -- | 5 | | | | -- | 6 | | | | -- | 7 | | | -| DMA2 | 1 | yes | infrared, lfrfid, subghz | +| DMA2 | 1 | yes | infrared, lfrfid, subghz, | | -- | 2 | yes | -- | -| -- | 3 | yes | SPI | -| -- | 4 | yes | SPI | -| -- | 5 | | | -| -- | 6 | | | -| -- | 7 | | | +| -- | 3 | yes | cc1101_ext | +| -- | 4 | yes | cc1101_ext | +| -- | 5 | yes | cc1101_ext | +| -- | 6 | yes | SPI | +| -- | 7 | yes | SPI | diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index d429de655a2..1884fe43373 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,+,30.1,, +Version,+,32.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -128,6 +128,7 @@ Header,+,lib/mlib/m-list.h,, Header,+,lib/mlib/m-rbtree.h,, Header,+,lib/mlib/m-tuple.h,, Header,+,lib/mlib/m-variant.h,, +Header,+,lib/music_worker/music_worker.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, @@ -282,6 +283,7 @@ Function,-,LL_mDelay,void,uint32_t Function,-,SystemCoreClockUpdate,void, Function,-,SystemInit,void, Function,-,_Exit,void,int +Function,+,__aeabi_uldivmod,void*,"uint64_t, uint64_t" Function,-,__assert,void,"const char*, int, const char*" Function,+,__assert_func,void,"const char*, int, const char*, const char*" Function,+,__clear_cache,void,"void*, void*" @@ -679,7 +681,8 @@ Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_ Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, uint8_t" Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool" -Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, const char*, Elf32_Addr*" +Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*" +Function,+,elf_symbolname_hash,uint32_t,const char* Function,+,empty_screen_alloc,EmptyScreen*, Function,+,empty_screen_free,void,EmptyScreen* Function,+,empty_screen_get_view,View*,EmptyScreen* @@ -735,9 +738,11 @@ Function,+,filesystem_api_error_get_desc,const char*,FS_Error Function,-,fiprintf,int,"FILE*, const char*, ..." Function,-,fiscanf,int,"FILE*, const char*, ..." Function,+,flipper_application_alloc,FlipperApplication*,"Storage*, const ElfApiInterface*" +Function,+,flipper_application_alloc_thread,FuriThread*,"FlipperApplication*, const char*" Function,+,flipper_application_free,void,FlipperApplication* Function,+,flipper_application_get_manifest,const FlipperApplicationManifest*,FlipperApplication* Function,+,flipper_application_is_plugin,_Bool,FlipperApplication* +Function,+,flipper_application_load_name_and_icon,_Bool,"FuriString*, Storage*, uint8_t**, FuriString*" Function,+,flipper_application_load_status_to_string,const char*,FlipperApplicationLoadStatus Function,+,flipper_application_manifest_is_compatible,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*" Function,+,flipper_application_manifest_is_target_compatible,_Bool,const FlipperApplicationManifest* @@ -747,7 +752,6 @@ Function,+,flipper_application_plugin_get_descriptor,const FlipperAppPluginDescr Function,+,flipper_application_preload,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" Function,+,flipper_application_preload_manifest,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" Function,+,flipper_application_preload_status_to_string,const char*,FlipperApplicationPreloadStatus -Function,+,flipper_application_spawn,FuriThread*,"FlipperApplication*, void*" Function,+,flipper_format_buffered_file_alloc,FlipperFormat*,Storage* Function,+,flipper_format_buffered_file_close,_Bool,FlipperFormat* Function,+,flipper_format_buffered_file_open_always,_Bool,"FlipperFormat*, const char*" @@ -1059,6 +1063,7 @@ Function,+,furi_hal_power_sleep,void, Function,+,furi_hal_power_sleep_available,_Bool, Function,+,furi_hal_power_suppress_charge_enter,void, Function,+,furi_hal_power_suppress_charge_exit,void, +Function,+,furi_hal_pwm_is_running,_Bool,FuriHalPwmOutputId Function,+,furi_hal_pwm_set_params,void,"FuriHalPwmOutputId, uint32_t, uint8_t" Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t" Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId @@ -1419,7 +1424,8 @@ Function,+,loader_get_pubsub,FuriPubSub*,Loader* Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* Function,+,loader_show_menu,void,Loader* -Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" +Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*, FuriString*" +Function,+,loader_start_with_gui_error,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* @@ -1515,6 +1521,18 @@ Function,-,mkstemps,int,"char*, int" Function,-,mktemp,char*,char* Function,-,mktime,time_t,tm* Function,-,mrand48,long, +Function,-,music_worker_alloc,MusicWorker*, +Function,-,music_worker_clear,void,MusicWorker* +Function,-,music_worker_free,void,MusicWorker* +Function,-,music_worker_is_playing,_Bool,MusicWorker* +Function,-,music_worker_load,_Bool,"MusicWorker*, const char*" +Function,-,music_worker_load_fmf_from_file,_Bool,"MusicWorker*, const char*" +Function,-,music_worker_load_rtttl_from_file,_Bool,"MusicWorker*, const char*" +Function,-,music_worker_load_rtttl_from_string,_Bool,"MusicWorker*, const char*" +Function,-,music_worker_set_callback,void,"MusicWorker*, MusicWorkerCallback, void*" +Function,-,music_worker_set_volume,void,"MusicWorker*, float" +Function,-,music_worker_start,void,MusicWorker* +Function,-,music_worker_stop,void,MusicWorker* Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" diff --git a/firmware/targets/f18/target.json b/firmware/targets/f18/target.json index 14d395d2227..2d14813f6da 100644 --- a/firmware/targets/f18/target.json +++ b/firmware/targets/f18/target.json @@ -25,6 +25,7 @@ "appframe", "assets", "one_wire", + "music_worker", "misc", "flipper_application", "flipperformat", diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index eb5b96f7b7f..b28602e2ba3 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,+,36.6,, +Version,+,33.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -56,7 +56,6 @@ 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_subghz_configs.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,, @@ -147,6 +146,7 @@ Header,+,lib/mlib/m-list.h,, Header,+,lib/mlib/m-rbtree.h,, Header,+,lib/mlib/m-tuple.h,, Header,+,lib/mlib/m-variant.h,, +Header,+,lib/music_worker/music_worker.h,, Header,+,lib/nanopb/pb.h,, Header,+,lib/nanopb/pb_decode.h,, Header,+,lib/nanopb/pb_encode.h,, @@ -189,6 +189,7 @@ Header,+,lib/subghz/blocks/decoder.h,, Header,+,lib/subghz/blocks/encoder.h,, Header,+,lib/subghz/blocks/generic.h,, Header,+,lib/subghz/blocks/math.h,, +Header,+,lib/subghz/devices/cc1101_configs.h,, Header,+,lib/subghz/environment.h,, Header,+,lib/subghz/protocols/raw.h,, Header,+,lib/subghz/receiver.h,, @@ -320,6 +321,7 @@ Function,-,LL_mDelay,void,uint32_t Function,-,SystemCoreClockUpdate,void, Function,-,SystemInit,void, Function,-,_Exit,void,int +Function,+,__aeabi_uldivmod,void*,"uint64_t, uint64_t" Function,-,__assert,void,"const char*, int, const char*" Function,+,__assert_func,void,"const char*, int, const char*, const char*" Function,+,__clear_cache,void,"void*, void*" @@ -687,26 +689,6 @@ Function,+,canvas_width,uint8_t,const Canvas* Function,-,cbrt,double,double Function,-,cbrtf,float,float Function,-,cbrtl,long double,long double -Function,+,cc1101_calibrate,void,FuriHalSpiBusHandle* -Function,+,cc1101_flush_rx,void,FuriHalSpiBusHandle* -Function,+,cc1101_flush_tx,void,FuriHalSpiBusHandle* -Function,-,cc1101_get_partnumber,uint8_t,FuriHalSpiBusHandle* -Function,+,cc1101_get_rssi,uint8_t,FuriHalSpiBusHandle* -Function,+,cc1101_get_status,CC1101Status,FuriHalSpiBusHandle* -Function,-,cc1101_get_version,uint8_t,FuriHalSpiBusHandle* -Function,+,cc1101_read_fifo,uint8_t,"FuriHalSpiBusHandle*, uint8_t*, uint8_t*" -Function,+,cc1101_read_reg,CC1101Status,"FuriHalSpiBusHandle*, uint8_t, uint8_t*" -Function,+,cc1101_reset,void,FuriHalSpiBusHandle* -Function,+,cc1101_set_frequency,uint32_t,"FuriHalSpiBusHandle*, uint32_t" -Function,-,cc1101_set_intermediate_frequency,uint32_t,"FuriHalSpiBusHandle*, uint32_t" -Function,+,cc1101_set_pa_table,void,"FuriHalSpiBusHandle*, const uint8_t[8]" -Function,+,cc1101_shutdown,void,FuriHalSpiBusHandle* -Function,+,cc1101_strobe,CC1101Status,"FuriHalSpiBusHandle*, uint8_t" -Function,+,cc1101_switch_to_idle,void,FuriHalSpiBusHandle* -Function,+,cc1101_switch_to_rx,void,FuriHalSpiBusHandle* -Function,+,cc1101_switch_to_tx,void,FuriHalSpiBusHandle* -Function,+,cc1101_write_fifo,uint8_t,"FuriHalSpiBusHandle*, const uint8_t*, uint8_t" -Function,+,cc1101_write_reg,CC1101Status,"FuriHalSpiBusHandle*, uint8_t, uint8_t" Function,-,ceil,double,double Function,-,ceilf,float,float Function,-,ceill,long double,long double @@ -831,7 +813,8 @@ Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_ Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, uint8_t" Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool" -Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, const char*, Elf32_Addr*" +Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*" +Function,+,elf_symbolname_hash,uint32_t,const char* Function,+,empty_screen_alloc,EmptyScreen*, Function,+,empty_screen_free,void,EmptyScreen* Function,+,empty_screen_get_view,View*,EmptyScreen* @@ -943,9 +926,11 @@ Function,-,finitel,int,long double Function,-,fiprintf,int,"FILE*, const char*, ..." Function,-,fiscanf,int,"FILE*, const char*, ..." Function,+,flipper_application_alloc,FlipperApplication*,"Storage*, const ElfApiInterface*" +Function,+,flipper_application_alloc_thread,FuriThread*,"FlipperApplication*, const char*" Function,+,flipper_application_free,void,FlipperApplication* Function,+,flipper_application_get_manifest,const FlipperApplicationManifest*,FlipperApplication* Function,+,flipper_application_is_plugin,_Bool,FlipperApplication* +Function,+,flipper_application_load_name_and_icon,_Bool,"FuriString*, Storage*, uint8_t**, FuriString*" Function,+,flipper_application_load_status_to_string,const char*,FlipperApplicationLoadStatus Function,+,flipper_application_manifest_is_compatible,_Bool,"const FlipperApplicationManifest*, const ElfApiInterface*" Function,+,flipper_application_manifest_is_target_compatible,_Bool,const FlipperApplicationManifest* @@ -955,7 +940,6 @@ Function,+,flipper_application_plugin_get_descriptor,const FlipperAppPluginDescr Function,+,flipper_application_preload,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" Function,+,flipper_application_preload_manifest,FlipperApplicationPreloadStatus,"FlipperApplication*, const char*" Function,+,flipper_application_preload_status_to_string,const char*,FlipperApplicationPreloadStatus -Function,+,flipper_application_spawn,FuriThread*,"FlipperApplication*, void*" Function,+,flipper_format_buffered_file_alloc,FlipperFormat*,Storage* Function,+,flipper_format_buffered_file_close,_Bool,FlipperFormat* Function,+,flipper_format_buffered_file_open_always,_Bool,"FlipperFormat*, const char*" @@ -1273,6 +1257,8 @@ Function,-,furi_hal_nfc_deinit,void, Function,+,furi_hal_nfc_detect,_Bool,"FuriHalNfcDevData*, uint32_t" Function,+,furi_hal_nfc_emulate_nfca,_Bool,"uint8_t*, uint8_t, uint8_t*, uint8_t, FuriHalNfcEmulateCallback, void*, uint32_t" Function,+,furi_hal_nfc_exit_sleep,void, +Function,+,furi_hal_nfc_field_detect_start,void, +Function,+,furi_hal_nfc_field_is_present,_Bool, Function,+,furi_hal_nfc_field_off,void, Function,+,furi_hal_nfc_field_on,void, Function,-,furi_hal_nfc_init,void, @@ -1334,6 +1320,7 @@ Function,+,furi_hal_power_sleep,void, Function,+,furi_hal_power_sleep_available,_Bool, Function,+,furi_hal_power_suppress_charge_enter,void, Function,+,furi_hal_power_suppress_charge_exit,void, +Function,+,furi_hal_pwm_is_running,_Bool,FuriHalPwmOutputId Function,+,furi_hal_pwm_set_params,void,"FuriHalPwmOutputId, uint32_t, uint8_t" Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t" Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId @@ -1354,6 +1341,9 @@ Function,-,furi_hal_resources_init_early,void, Function,+,furi_hal_rfid_comp_set_callback,void,"FuriHalRfidCompCallback, void*" Function,+,furi_hal_rfid_comp_start,void, Function,+,furi_hal_rfid_comp_stop,void, +Function,+,furi_hal_rfid_field_detect_start,void, +Function,+,furi_hal_rfid_field_detect_stop,void, +Function,+,furi_hal_rfid_field_is_present,_Bool,uint32_t* Function,-,furi_hal_rfid_init,void, Function,+,furi_hal_rfid_pin_pull_pulldown,void, Function,+,furi_hal_rfid_pin_pull_release,void, @@ -1426,6 +1416,7 @@ Function,+,furi_hal_spi_release,void,FuriHalSpiBusHandle* Function,-,furi_hal_subghz_dump_state,void, Function,+,furi_hal_subghz_flush_rx,void, Function,+,furi_hal_subghz_flush_tx,void, +Function,+,furi_hal_subghz_get_data_gpio,const GpioPin*, Function,+,furi_hal_subghz_get_lqi,uint8_t, Function,+,furi_hal_subghz_get_rssi,float, Function,+,furi_hal_subghz_idle,void, @@ -1433,10 +1424,9 @@ Function,-,furi_hal_subghz_init,void, Function,+,furi_hal_subghz_is_async_tx_complete,_Bool, Function,+,furi_hal_subghz_is_frequency_valid,_Bool,uint32_t Function,+,furi_hal_subghz_is_rx_data_crc_valid,_Bool, -Function,+,furi_hal_subghz_load_custom_preset,void,uint8_t* +Function,+,furi_hal_subghz_load_custom_preset,void,const uint8_t* Function,+,furi_hal_subghz_load_patable,void,const uint8_t[8] -Function,+,furi_hal_subghz_load_preset,void,FuriHalSubGhzPreset -Function,+,furi_hal_subghz_load_registers,void,uint8_t* +Function,+,furi_hal_subghz_load_registers,void,const uint8_t* Function,+,furi_hal_subghz_read_packet,void,"uint8_t*, uint8_t*" Function,+,furi_hal_subghz_reset,void, Function,+,furi_hal_subghz_rx,void, @@ -1444,7 +1434,7 @@ Function,+,furi_hal_subghz_rx_pipe_not_empty,_Bool, Function,+,furi_hal_subghz_set_async_mirror_pin,void,const GpioPin* Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t -Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath +Function,-,furi_hal_subghz_set_path,void,FuriHalSubGhzPath Function,-,furi_hal_subghz_shutdown,void, Function,+,furi_hal_subghz_sleep,void, Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*" @@ -1894,7 +1884,8 @@ Function,+,loader_get_pubsub,FuriPubSub*,Loader* Function,+,loader_is_locked,_Bool,Loader* Function,+,loader_lock,_Bool,Loader* Function,+,loader_show_menu,void,Loader* -Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" +Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*, FuriString*" +Function,+,loader_start_with_gui_error,LoaderStatus,"Loader*, const char*, const char*" Function,+,loader_unlock,void,Loader* Function,+,loading_alloc,Loading*, Function,+,loading_free,void,Loading* @@ -2043,6 +2034,18 @@ Function,-,modf,double,"double, double*" Function,-,modff,float,"float, float*" Function,-,modfl,long double,"long double, long double*" Function,-,mrand48,long, +Function,-,music_worker_alloc,MusicWorker*, +Function,-,music_worker_clear,void,MusicWorker* +Function,-,music_worker_free,void,MusicWorker* +Function,-,music_worker_is_playing,_Bool,MusicWorker* +Function,-,music_worker_load,_Bool,"MusicWorker*, const char*" +Function,-,music_worker_load_fmf_from_file,_Bool,"MusicWorker*, const char*" +Function,-,music_worker_load_rtttl_from_file,_Bool,"MusicWorker*, const char*" +Function,-,music_worker_load_rtttl_from_string,_Bool,"MusicWorker*, const char*" +Function,-,music_worker_set_callback,void,"MusicWorker*, MusicWorkerCallback, void*" +Function,-,music_worker_set_volume,void,"MusicWorker*, float" +Function,-,music_worker_start,void,MusicWorker* +Function,-,music_worker_stop,void,MusicWorker* Function,-,nan,double,const char* Function,-,nanf,float,const char* Function,-,nanl,long double,const char* @@ -2682,6 +2685,36 @@ Function,+,subghz_block_generic_deserialize,SubGhzProtocolStatus,"SubGhzBlockGen Function,+,subghz_block_generic_deserialize_check_count_bit,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, uint16_t" Function,+,subghz_block_generic_get_preset_name,void,"const char*, FuriString*" Function,+,subghz_block_generic_serialize,SubGhzProtocolStatus,"SubGhzBlockGeneric*, FlipperFormat*, SubGhzRadioPreset*" +Function,+,subghz_devices_begin,_Bool,const SubGhzDevice* +Function,+,subghz_devices_deinit,void, +Function,+,subghz_devices_end,void,const SubGhzDevice* +Function,+,subghz_devices_flush_rx,void,const SubGhzDevice* +Function,+,subghz_devices_flush_tx,void,const SubGhzDevice* +Function,+,subghz_devices_get_by_name,const SubGhzDevice*,const char* +Function,+,subghz_devices_get_data_gpio,const GpioPin*,const SubGhzDevice* +Function,+,subghz_devices_get_lqi,uint8_t,const SubGhzDevice* +Function,+,subghz_devices_get_name,const char*,const SubGhzDevice* +Function,+,subghz_devices_get_rssi,float,const SubGhzDevice* +Function,+,subghz_devices_idle,void,const SubGhzDevice* +Function,+,subghz_devices_init,void, +Function,+,subghz_devices_is_async_complete_tx,_Bool,const SubGhzDevice* +Function,+,subghz_devices_is_connect,_Bool,const SubGhzDevice* +Function,+,subghz_devices_is_frequency_valid,_Bool,"const SubGhzDevice*, uint32_t" +Function,+,subghz_devices_is_rx_data_crc_valid,_Bool,const SubGhzDevice* +Function,+,subghz_devices_load_preset,void,"const SubGhzDevice*, FuriHalSubGhzPreset, uint8_t*" +Function,+,subghz_devices_read_packet,void,"const SubGhzDevice*, uint8_t*, uint8_t*" +Function,+,subghz_devices_reset,void,const SubGhzDevice* +Function,+,subghz_devices_rx_pipe_not_empty,_Bool,const SubGhzDevice* +Function,+,subghz_devices_set_async_mirror_pin,void,"const SubGhzDevice*, const GpioPin*" +Function,+,subghz_devices_set_frequency,uint32_t,"const SubGhzDevice*, uint32_t" +Function,+,subghz_devices_set_rx,void,const SubGhzDevice* +Function,+,subghz_devices_set_tx,_Bool,const SubGhzDevice* +Function,+,subghz_devices_sleep,void,const SubGhzDevice* +Function,+,subghz_devices_start_async_rx,void,"const SubGhzDevice*, void*, void*" +Function,+,subghz_devices_start_async_tx,_Bool,"const SubGhzDevice*, void*, void*" +Function,+,subghz_devices_stop_async_rx,void,const SubGhzDevice* +Function,+,subghz_devices_stop_async_tx,void,const SubGhzDevice* +Function,+,subghz_devices_write_packet,void,"const SubGhzDevice*, const uint8_t*, uint8_t" Function,+,subghz_environment_alloc,SubGhzEnvironment*, Function,+,subghz_environment_free,void,SubGhzEnvironment* Function,+,subghz_environment_get_alutech_at_4n_rainbow_table_file_name,const char*,SubGhzEnvironment* @@ -2740,7 +2773,7 @@ Function,+,subghz_protocol_encoder_raw_free,void,void* Function,+,subghz_protocol_encoder_raw_stop,void,void* Function,+,subghz_protocol_encoder_raw_yield,LevelDuration,void* Function,+,subghz_protocol_raw_file_encoder_worker_set_callback_end,void,"SubGhzProtocolEncoderRAW*, SubGhzProtocolEncoderRAWCallbackEnd, void*" -Function,+,subghz_protocol_raw_gen_fff_data,void,"FlipperFormat*, const char*" +Function,+,subghz_protocol_raw_gen_fff_data,void,"FlipperFormat*, const char*, const char*" Function,+,subghz_protocol_raw_get_sample_write,size_t,SubGhzProtocolDecoderRAW* Function,+,subghz_protocol_raw_save_to_file_init,_Bool,"SubGhzProtocolDecoderRAW*, const char*, SubGhzRadioPreset*" Function,+,subghz_protocol_raw_save_to_file_pause,void,"SubGhzProtocolDecoderRAW*, _Bool" @@ -2784,7 +2817,7 @@ Function,+,subghz_tx_rx_worker_free,void,SubGhzTxRxWorker* Function,+,subghz_tx_rx_worker_is_running,_Bool,SubGhzTxRxWorker* Function,+,subghz_tx_rx_worker_read,size_t,"SubGhzTxRxWorker*, uint8_t*, size_t" Function,+,subghz_tx_rx_worker_set_callback_have_read,void,"SubGhzTxRxWorker*, SubGhzTxRxWorkerCallbackHaveRead, void*" -Function,+,subghz_tx_rx_worker_start,_Bool,"SubGhzTxRxWorker*, uint32_t" +Function,+,subghz_tx_rx_worker_start,_Bool,"SubGhzTxRxWorker*, const SubGhzDevice*, uint32_t" Function,+,subghz_tx_rx_worker_stop,void,SubGhzTxRxWorker* Function,+,subghz_tx_rx_worker_write,_Bool,"SubGhzTxRxWorker*, uint8_t*, size_t" Function,+,subghz_worker_alloc,SubGhzWorker*, @@ -3387,6 +3420,12 @@ Variable,+,sequence_set_vibro_on,const NotificationSequence, Variable,+,sequence_single_vibro,const NotificationSequence, Variable,+,sequence_solid_yellow,const NotificationSequence, Variable,+,sequence_success,const NotificationSequence, +Variable,+,subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs,const uint8_t[], +Variable,+,subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs,const uint8_t[], +Variable,+,subghz_device_cc1101_preset_gfsk_9_99kb_async_regs,const uint8_t[], +Variable,+,subghz_device_cc1101_preset_msk_99_97kb_async_regs,const uint8_t[], +Variable,+,subghz_device_cc1101_preset_ook_270khz_async_regs,const uint8_t[], +Variable,+,subghz_device_cc1101_preset_ook_650khz_async_regs,const uint8_t[], Variable,+,subghz_protocol_raw,const SubGhzProtocol, Variable,+,subghz_protocol_raw_decoder,const SubGhzProtocolDecoder, Variable,+,subghz_protocol_raw_encoder,const SubGhzProtocolEncoder, diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index 6ff9f0e3b1f..57aee0bf2a2 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -21,8 +21,17 @@ #define FURI_HAL_BT_HARDFAULT_INFO_MAGIC 0x1170FD0F -FuriMutex* furi_hal_bt_core2_mtx = NULL; -static FuriHalBtStack furi_hal_bt_stack = FuriHalBtStackUnknown; +typedef struct { + FuriMutex* core2_mtx; + FuriTimer* hardfault_check_timer; + FuriHalBtStack stack; +} FuriHalBt; + +static FuriHalBt furi_hal_bt = { + .core2_mtx = NULL, + .hardfault_check_timer = NULL, + .stack = FuriHalBtStackUnknown, +}; typedef void (*FuriHalBtProfileStart)(void); typedef void (*FuriHalBtProfileStop)(void); @@ -79,6 +88,13 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { }; FuriHalBtProfileConfig* current_profile = NULL; +static void furi_hal_bt_hardfault_check(void* context) { + UNUSED(context); + if(furi_hal_bt_get_hardfault_info()) { + furi_crash("ST(R) Copro(R) HardFault"); + } +} + void furi_hal_bt_init() { furi_hal_bus_enable(FuriHalBusHSEM); furi_hal_bus_enable(FuriHalBusIPCC); @@ -86,9 +102,15 @@ void furi_hal_bt_init() { furi_hal_bus_enable(FuriHalBusPKA); furi_hal_bus_enable(FuriHalBusCRC); - if(!furi_hal_bt_core2_mtx) { - furi_hal_bt_core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal); - furi_assert(furi_hal_bt_core2_mtx); + if(!furi_hal_bt.core2_mtx) { + furi_hal_bt.core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal); + furi_assert(furi_hal_bt.core2_mtx); + } + + if(!furi_hal_bt.hardfault_check_timer) { + furi_hal_bt.hardfault_check_timer = + furi_timer_alloc(furi_hal_bt_hardfault_check, FuriTimerTypePeriodic, NULL); + furi_timer_start(furi_hal_bt.hardfault_check_timer, 5000); } // Explicitly tell that we are in charge of CLK48 domain @@ -99,13 +121,13 @@ void furi_hal_bt_init() { } void furi_hal_bt_lock_core2() { - furi_assert(furi_hal_bt_core2_mtx); - furi_check(furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever) == FuriStatusOk); + furi_assert(furi_hal_bt.core2_mtx); + furi_check(furi_mutex_acquire(furi_hal_bt.core2_mtx, FuriWaitForever) == FuriStatusOk); } void furi_hal_bt_unlock_core2() { - furi_assert(furi_hal_bt_core2_mtx); - furi_check(furi_mutex_release(furi_hal_bt_core2_mtx) == FuriStatusOk); + furi_assert(furi_hal_bt.core2_mtx); + furi_check(furi_mutex_release(furi_hal_bt.core2_mtx) == FuriStatusOk); } static bool furi_hal_bt_radio_stack_is_supported(const BleGlueC2Info* info) { @@ -113,26 +135,26 @@ static bool furi_hal_bt_radio_stack_is_supported(const BleGlueC2Info* info) { if(info->StackType == INFO_STACK_TYPE_BLE_LIGHT) { if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR && info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) { - furi_hal_bt_stack = FuriHalBtStackLight; + furi_hal_bt.stack = FuriHalBtStackLight; supported = true; } } else if(info->StackType == INFO_STACK_TYPE_BLE_FULL) { if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR && info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) { - furi_hal_bt_stack = FuriHalBtStackFull; + furi_hal_bt.stack = FuriHalBtStackFull; supported = true; } } else { - furi_hal_bt_stack = FuriHalBtStackUnknown; + furi_hal_bt.stack = FuriHalBtStackUnknown; } return supported; } bool furi_hal_bt_start_radio_stack() { bool res = false; - furi_assert(furi_hal_bt_core2_mtx); + furi_assert(furi_hal_bt.core2_mtx); - furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever); + furi_mutex_acquire(furi_hal_bt.core2_mtx, FuriWaitForever); // Explicitly tell that we are in charge of CLK48 domain furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0); @@ -166,17 +188,17 @@ bool furi_hal_bt_start_radio_stack() { } res = true; } while(false); - furi_mutex_release(furi_hal_bt_core2_mtx); + furi_mutex_release(furi_hal_bt.core2_mtx); return res; } FuriHalBtStack furi_hal_bt_get_radio_stack() { - return furi_hal_bt_stack; + return furi_hal_bt.stack; } bool furi_hal_bt_is_ble_gatt_gap_supported() { - if(furi_hal_bt_stack == FuriHalBtStackLight || furi_hal_bt_stack == FuriHalBtStackFull) { + if(furi_hal_bt.stack == FuriHalBtStackLight || furi_hal_bt.stack == FuriHalBtStackFull) { return true; } else { return false; @@ -184,7 +206,7 @@ bool furi_hal_bt_is_ble_gatt_gap_supported() { } bool furi_hal_bt_is_testing_supported() { - if(furi_hal_bt_stack == FuriHalBtStackFull) { + if(furi_hal_bt.stack == FuriHalBtStackFull) { return true; } else { return false; diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index bd621c2db7d..ffda124a407 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -819,3 +819,17 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits( void furi_hal_nfc_ll_poll() { rfalWorker(); } + +void furi_hal_nfc_field_detect_start() { + st25r3916WriteRegister( + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_en_fd_mask); + st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om0); +} + +bool furi_hal_nfc_field_is_present() { + return st25r3916CheckReg( + ST25R3916_REG_AUX_DISPLAY, + ST25R3916_REG_AUX_DISPLAY_efd_o, + ST25R3916_REG_AUX_DISPLAY_efd_o); +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.h b/firmware/targets/f7/furi_hal/furi_hal_nfc.h index 81d2bae484f..c106f70a05c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.h +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.h @@ -423,6 +423,10 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits( void furi_hal_nfc_ll_poll(); +void furi_hal_nfc_field_detect_start(); + +bool furi_hal_nfc_field_is_present(); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.c b/firmware/targets/f7/furi_hal/furi_hal_pwm.c index 7e985cbb11b..879460e6bd5 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_pwm.c +++ b/firmware/targets/f7/furi_hal/furi_hal_pwm.c @@ -82,6 +82,15 @@ void furi_hal_pwm_stop(FuriHalPwmOutputId channel) { } } +bool furi_hal_pwm_is_running(FuriHalPwmOutputId channel) { + if(channel == FuriHalPwmOutputIdTim1PA7) { + return furi_hal_bus_is_enabled(FuriHalBusTIM1); + } else if(channel == FuriHalPwmOutputIdLptim2PA4) { + return furi_hal_bus_is_enabled(FuriHalBusLPTIM2); + } + return false; +} + void furi_hal_pwm_set_params(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) { furi_assert(freq > 0); uint32_t freq_div = 64000000LU / freq; diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.h b/firmware/targets/f7/furi_hal/furi_hal_pwm.h index a8682c5fbb1..16acca05efe 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_pwm.h +++ b/firmware/targets/f7/furi_hal/furi_hal_pwm.h @@ -9,6 +9,7 @@ extern "C" { #endif #include +#include typedef enum { FuriHalPwmOutputIdTim1PA7, @@ -37,6 +38,13 @@ void furi_hal_pwm_stop(FuriHalPwmOutputId channel); */ void furi_hal_pwm_set_params(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty); +/** Is PWM channel running? + * + * @param[in] channel PWM channel (FuriHalPwmOutputId) + * @return bool - true if running +*/ +bool furi_hal_pwm_is_running(FuriHalPwmOutputId channel); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index fa0c19b098b..67f11d6ff7b 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.c @@ -25,6 +25,19 @@ #define RFID_CAPTURE_IND_CH LL_TIM_CHANNEL_CH3 #define RFID_CAPTURE_DIR_CH LL_TIM_CHANNEL_CH4 +// Field presence detection +#define FURI_HAL_RFID_FIELD_FREQUENCY_MIN 80000 +#define FURI_HAL_RFID_FIELD_FREQUENCY_MAX 200000 + +#define FURI_HAL_RFID_FIELD_COUNTER_TIMER TIM2 +#define FURI_HAL_RFID_FIELD_COUNTER_TIMER_BUS FuriHalBusTIM2 +#define FURI_HAL_RFID_FIELD_COUNTER_TIMER_CHANNEL LL_TIM_CHANNEL_CH3 + +#define FURI_HAL_RFID_FIELD_TIMEOUT_TIMER TIM1 +#define FURI_HAL_RFID_FIELD_TIMEOUT_TIMER_BUS FuriHalBusTIM1 + +#define FURI_HAL_RFID_FIELD_DMAMUX_DMA LL_DMAMUX_REQ_TIM1_UP + /* DMA Channels definition */ #define RFID_DMA DMA2 #define RFID_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 @@ -33,10 +46,16 @@ #define RFID_DMA_CH1_DEF RFID_DMA, RFID_DMA_CH1_CHANNEL #define RFID_DMA_CH2_DEF RFID_DMA, RFID_DMA_CH2_CHANNEL +typedef struct { + uint32_t counter; + uint32_t set_tim_counter_cnt; +} FuriHalRfidField; + typedef struct { FuriHalRfidDMACallback dma_callback; FuriHalRfidReadCaptureCallback read_capture_callback; void* context; + FuriHalRfidField field; } FuriHalRfid; FuriHalRfid* furi_hal_rfid = NULL; @@ -51,6 +70,8 @@ FuriHalRfid* furi_hal_rfid = NULL; void furi_hal_rfid_init() { furi_assert(furi_hal_rfid == NULL); furi_hal_rfid = malloc(sizeof(FuriHalRfid)); + furi_hal_rfid->field.counter = 0; + furi_hal_rfid->field.set_tim_counter_cnt = 0; furi_hal_rfid_pins_reset(); @@ -133,6 +154,23 @@ static void furi_hal_rfid_pins_read() { furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } +static void furi_hal_rfid_pins_field() { + // ibutton low + furi_hal_ibutton_pin_configure(); + furi_hal_ibutton_pin_write(false); + + // pull pin to timer out + furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false); + + // pull rfid antenna from carrier side + furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_write(&gpio_rfid_carrier_out, false); + + furi_hal_gpio_init_ex( + &gpio_rfid_carrier, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn2TIM2); +} + void furi_hal_rfid_pin_pull_release() { furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, true); } @@ -427,3 +465,124 @@ void COMP_IRQHandler() { furi_hal_rfid_comp_callback_context); } } + +static void furi_hal_rfid_field_tim_setup() { + // setup timer counter + furi_hal_bus_enable(FURI_HAL_RFID_FIELD_COUNTER_TIMER_BUS); + + LL_TIM_SetPrescaler(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0); + LL_TIM_SetCounterMode(FURI_HAL_RFID_FIELD_COUNTER_TIMER, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetAutoReload(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0xFFFFFFFF); + LL_TIM_DisableARRPreload(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + LL_TIM_SetRepetitionCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0); + + LL_TIM_SetClockDivision(FURI_HAL_RFID_FIELD_COUNTER_TIMER, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockSource(FURI_HAL_RFID_FIELD_COUNTER_TIMER, LL_TIM_CLOCKSOURCE_EXT_MODE2); + LL_TIM_ConfigETR( + FURI_HAL_RFID_FIELD_COUNTER_TIMER, + LL_TIM_ETR_POLARITY_INVERTED, + LL_TIM_ETR_PRESCALER_DIV1, + LL_TIM_ETR_FILTER_FDIV1); + + LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; + TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1; + TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; + TIM_OC_InitStruct.CompareValue = 1; + LL_TIM_OC_Init( + FURI_HAL_RFID_FIELD_COUNTER_TIMER, + FURI_HAL_RFID_FIELD_COUNTER_TIMER_CHANNEL, + &TIM_OC_InitStruct); + + LL_TIM_GenerateEvent_UPDATE(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + LL_TIM_OC_SetPolarity( + FURI_HAL_RFID_FIELD_COUNTER_TIMER, + FURI_HAL_RFID_FIELD_COUNTER_TIMER_CHANNEL, + LL_TIM_OCPOLARITY_HIGH); + LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + + // setup timer timeouts dma + furi_hal_bus_enable(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER_BUS); + + LL_TIM_SetPrescaler(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, 64000 - 1); + LL_TIM_SetCounterMode(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, LL_TIM_COUNTERMODE_UP); + LL_TIM_SetAutoReload(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, 100 - 1); // 100 ms + LL_TIM_SetClockDivision(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, LL_TIM_CLOCKDIVISION_DIV1); + LL_TIM_SetClockSource(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, LL_TIM_CLOCKSOURCE_INTERNAL); + + LL_TIM_DisableARRPreload(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); + + LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); + LL_TIM_GenerateEvent_UPDATE(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); +} + +void furi_hal_rfid_field_detect_start(void) { + // setup pins + furi_hal_rfid_pins_field(); + + // configure timer + furi_hal_rfid_field_tim_setup(); + + // configure DMA "TIM_COUNTER_CNT -> counter" + LL_DMA_SetMemoryAddress(RFID_DMA_CH1_DEF, (uint32_t) & (furi_hal_rfid->field.counter)); + LL_DMA_SetPeriphAddress( + RFID_DMA_CH1_DEF, (uint32_t) & (FURI_HAL_RFID_FIELD_COUNTER_TIMER->CNT)); + LL_DMA_ConfigTransfer( + RFID_DMA_CH1_DEF, + LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_NOINCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_PRIORITY_MEDIUM); + LL_DMA_SetDataLength(RFID_DMA_CH1_DEF, 1); + LL_DMA_SetPeriphRequest(RFID_DMA_CH1_DEF, FURI_HAL_RFID_FIELD_DMAMUX_DMA); + LL_DMA_EnableChannel(RFID_DMA_CH1_DEF); + + // configure DMA "mem -> TIM_COUNTER_CNT" + LL_DMA_SetMemoryAddress( + RFID_DMA_CH2_DEF, (uint32_t) & (furi_hal_rfid->field.set_tim_counter_cnt)); + LL_DMA_SetPeriphAddress( + RFID_DMA_CH2_DEF, (uint32_t) & (FURI_HAL_RFID_FIELD_COUNTER_TIMER->CNT)); + LL_DMA_ConfigTransfer( + RFID_DMA_CH2_DEF, + LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT | + LL_DMA_MEMORY_NOINCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD | + LL_DMA_PRIORITY_LOW); + LL_DMA_SetDataLength(RFID_DMA_CH2_DEF, 1); + LL_DMA_SetPeriphRequest(RFID_DMA_CH2_DEF, FURI_HAL_RFID_FIELD_DMAMUX_DMA); + LL_DMA_EnableChannel(RFID_DMA_CH2_DEF); + + // start tim counter + LL_TIM_EnableAllOutputs(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + + LL_TIM_SetCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0); + LL_TIM_EnableCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + + // start tim timeout + LL_TIM_SetCounter(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, 0); + LL_TIM_EnableCounter(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); + LL_TIM_EnableIT_UPDATE(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); +} + +void furi_hal_rfid_field_detect_stop(void) { + LL_TIM_DisableCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + LL_TIM_DisableAllOutputs(FURI_HAL_RFID_FIELD_COUNTER_TIMER); + + LL_TIM_DisableCounter(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER); + + FURI_CRITICAL_ENTER(); + + LL_DMA_DeInit(RFID_DMA_CH1_DEF); + LL_DMA_DeInit(RFID_DMA_CH2_DEF); + + furi_hal_bus_disable(FURI_HAL_RFID_FIELD_COUNTER_TIMER_BUS); + furi_hal_bus_disable(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER_BUS); + + furi_hal_rfid_pins_reset(); + + FURI_CRITICAL_EXIT(); +} + +bool furi_hal_rfid_field_is_present(uint32_t* frequency) { + *frequency = furi_hal_rfid->field.counter * 10; + return ( + (*frequency >= FURI_HAL_RFID_FIELD_FREQUENCY_MIN) && + (*frequency <= FURI_HAL_RFID_FIELD_FREQUENCY_MAX)); +} \ No newline at end of file diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.h b/firmware/targets/f7/furi_hal/furi_hal_rfid.h index 78d9b665870..7087ba991fa 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.h +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.h @@ -87,6 +87,20 @@ typedef void (*FuriHalRfidCompCallback)(bool level, void* context); /** Set comparator callback */ void furi_hal_rfid_comp_set_callback(FuriHalRfidCompCallback callback, void* context); +/** Start/Enable Field Presence detect */ +void furi_hal_rfid_field_detect_start(); + +/** Stop/Disable Field Presence detect */ +void furi_hal_rfid_field_detect_stop(); + +/** Check Field Presence + * + * @param[out] frequency pointer to frequency value to be set if filed detected + * + * @return true if field is present, false if not + */ +bool furi_hal_rfid_field_is_present(uint32_t* frequency); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi.c b/firmware/targets/f7/furi_hal/furi_hal_spi.c index 42b85479955..17769832b6a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi.c @@ -12,10 +12,10 @@ #define TAG "FuriHalSpi" #define SPI_DMA DMA2 -#define SPI_DMA_RX_CHANNEL LL_DMA_CHANNEL_3 -#define SPI_DMA_TX_CHANNEL LL_DMA_CHANNEL_4 -#define SPI_DMA_RX_IRQ FuriHalInterruptIdDma2Ch3 -#define SPI_DMA_TX_IRQ FuriHalInterruptIdDma2Ch4 +#define SPI_DMA_RX_CHANNEL LL_DMA_CHANNEL_6 +#define SPI_DMA_TX_CHANNEL LL_DMA_CHANNEL_7 +#define SPI_DMA_RX_IRQ FuriHalInterruptIdDma2Ch6 +#define SPI_DMA_TX_IRQ FuriHalInterruptIdDma2Ch7 #define SPI_DMA_RX_DEF SPI_DMA, SPI_DMA_RX_CHANNEL #define SPI_DMA_TX_DEF SPI_DMA, SPI_DMA_TX_CHANNEL @@ -170,18 +170,18 @@ bool furi_hal_spi_bus_trx( } static void spi_dma_isr() { -#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_3 - if(LL_DMA_IsActiveFlag_TC3(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_RX_DEF)) { - LL_DMA_ClearFlag_TC3(SPI_DMA); +#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_6 + if(LL_DMA_IsActiveFlag_TC6(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_RX_DEF)) { + LL_DMA_ClearFlag_TC6(SPI_DMA); furi_check(furi_semaphore_release(spi_dma_completed) == FuriStatusOk); } #else #error Update this code. Would you kindly? #endif -#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_4 - if(LL_DMA_IsActiveFlag_TC4(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_TX_DEF)) { - LL_DMA_ClearFlag_TC4(SPI_DMA); +#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_7 + if(LL_DMA_IsActiveFlag_TC7(SPI_DMA) && LL_DMA_IsEnabledIT_TC(SPI_DMA_TX_DEF)) { + LL_DMA_ClearFlag_TC7(SPI_DMA); furi_check(furi_semaphore_release(spi_dma_completed) == FuriStatusOk); } #else @@ -241,8 +241,8 @@ bool furi_hal_spi_bus_trx_dma( dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; LL_DMA_Init(SPI_DMA_TX_DEF, &dma_config); -#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_4 - LL_DMA_ClearFlag_TC4(SPI_DMA); +#if SPI_DMA_TX_CHANNEL == LL_DMA_CHANNEL_7 + LL_DMA_ClearFlag_TC7(SPI_DMA); #else #error Update this code. Would you kindly? #endif @@ -315,8 +315,8 @@ bool furi_hal_spi_bus_trx_dma( dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; LL_DMA_Init(SPI_DMA_RX_DEF, &dma_config); -#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_3 - LL_DMA_ClearFlag_TC3(SPI_DMA); +#if SPI_DMA_RX_CHANNEL == LL_DMA_CHANNEL_6 + LL_DMA_ClearFlag_TC6(SPI_DMA); #else #error Update this code. Would you kindly? #endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 6d671a9e15b..ac5adefb8df 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -1,6 +1,5 @@ #include -#include - +#include #include #include #include @@ -27,17 +26,36 @@ static uint32_t furi_hal_subghz_debug_gpio_buff[2]; #define SUBGHZ_DMA_CH1_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH1_CHANNEL #define SUBGHZ_DMA_CH2_DEF SUBGHZ_DMA, SUBGHZ_DMA_CH2_CHANNEL +/** SubGhz state */ +typedef enum { + SubGhzStateInit, /**< Init pending */ + + SubGhzStateIdle, /**< Idle, energy save mode */ + + SubGhzStateAsyncRx, /**< Async RX started */ + + SubGhzStateAsyncTx, /**< Async TX started, DMA and timer is on */ + SubGhzStateAsyncTxLast, /**< Async TX continue, DMA completed and timer got last value to go */ + SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */ + +} SubGhzState; + +/** SubGhz regulation, receive transmission on the current frequency for the + * region */ +typedef enum { + SubGhzRegulationOnlyRx, /**only Rx*/ + SubGhzRegulationTxRx, /**TxRx*/ +} SubGhzRegulation; + typedef struct { volatile SubGhzState state; volatile SubGhzRegulation regulation; - volatile FuriHalSubGhzPreset preset; const GpioPin* async_mirror_pin; } FuriHalSubGhz; volatile FuriHalSubGhz furi_hal_subghz = { .state = SubGhzStateInit, .regulation = SubGhzRegulationTxRx, - .preset = FuriHalSubGhzPresetIDLE, .async_mirror_pin = NULL, }; @@ -45,10 +63,13 @@ void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin) { furi_hal_subghz.async_mirror_pin = pin; } +const GpioPin* furi_hal_subghz_get_data_gpio() { + return &gpio_cc1101_g0; +} + void furi_hal_subghz_init() { furi_assert(furi_hal_subghz.state == SubGhzStateInit); furi_hal_subghz.state = SubGhzStateIdle; - furi_hal_subghz.preset = FuriHalSubGhzPresetIDLE; furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); @@ -102,8 +123,6 @@ void furi_hal_subghz_sleep() { cc1101_shutdown(&furi_hal_spi_bus_handle_subghz); furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); - - furi_hal_subghz.preset = FuriHalSubGhzPresetIDLE; } void furi_hal_subghz_dump_state() { @@ -115,34 +134,7 @@ void furi_hal_subghz_dump_state() { furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz); } -void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) { - if(preset == FuriHalSubGhzPresetOok650Async) { - furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_ook_650khz_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); - } else if(preset == FuriHalSubGhzPresetOok270Async) { - furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_ook_270khz_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable); - } else if(preset == FuriHalSubGhzPreset2FSKDev238Async) { - furi_hal_subghz_load_registers( - (uint8_t*)furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable); - } else if(preset == FuriHalSubGhzPreset2FSKDev476Async) { - furi_hal_subghz_load_registers( - (uint8_t*)furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable); - } else if(preset == FuriHalSubGhzPresetMSK99_97KbAsync) { - furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_msk_99_97kb_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_msk_async_patable); - } else if(preset == FuriHalSubGhzPresetGFSK9_99KbAsync) { - furi_hal_subghz_load_registers((uint8_t*)furi_hal_subghz_preset_gfsk_9_99kb_async_regs); - furi_hal_subghz_load_patable(furi_hal_subghz_preset_gfsk_async_patable); - } else { - furi_crash("SubGhz: Missing config."); - } - furi_hal_subghz.preset = preset; -} - -void furi_hal_subghz_load_custom_preset(uint8_t* preset_data) { +void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data) { //load config furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); cc1101_reset(&furi_hal_spi_bus_handle_subghz); @@ -157,7 +149,6 @@ void furi_hal_subghz_load_custom_preset(uint8_t* preset_data) { //load pa table memcpy(&pa[0], &preset_data[i + 2], 8); furi_hal_subghz_load_patable(pa); - furi_hal_subghz.preset = FuriHalSubGhzPresetCustom; //show debug if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { @@ -173,7 +164,7 @@ void furi_hal_subghz_load_custom_preset(uint8_t* preset_data) { } } -void furi_hal_subghz_load_registers(uint8_t* data) { +void furi_hal_subghz_load_registers(const uint8_t* data) { furi_hal_spi_acquire(&furi_hal_spi_bus_handle_subghz); cc1101_reset(&furi_hal_spi_bus_handle_subghz); uint32_t i = 0; diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.h b/firmware/targets/f7/furi_hal/furi_hal_subghz.h index 102981dbeb5..855ce31619c 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.h +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.h @@ -5,6 +5,8 @@ #pragma once +#include + #include #include #include @@ -20,18 +22,6 @@ extern "C" { #define API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF (API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL / 2) #define API_HAL_SUBGHZ_ASYNC_TX_GUARD_TIME 999 -/** Radio Presets */ -typedef enum { - FuriHalSubGhzPresetIDLE, /**< default configuration */ - FuriHalSubGhzPresetOok270Async, /**< OOK, bandwidth 270kHz, asynchronous */ - FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */ - FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */ - FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 47.60742 kHz, asynchronous */ - FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */ - FuriHalSubGhzPresetGFSK9_99KbAsync, /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */ - FuriHalSubGhzPresetCustom, /**Custom Preset*/ -} FuriHalSubGhzPreset; - /** Switchable Radio Paths */ typedef enum { FuriHalSubGhzPathIsolate, /**< Isolate Radio from antenna */ @@ -40,27 +30,6 @@ typedef enum { FuriHalSubGhzPath868, /**< Center Frequency: 868MHz. Path 3: SW1RF3-SW2RF3, LCLC */ } FuriHalSubGhzPath; -/** SubGhz state */ -typedef enum { - SubGhzStateInit, /**< Init pending */ - - SubGhzStateIdle, /**< Idle, energy save mode */ - - SubGhzStateAsyncRx, /**< Async RX started */ - - SubGhzStateAsyncTx, /**< Async TX started, DMA and timer is on */ - SubGhzStateAsyncTxLast, /**< Async TX continue, DMA completed and timer got last value to go */ - SubGhzStateAsyncTxEnd, /**< Async TX complete, cleanup needed */ - -} SubGhzState; - -/** SubGhz regulation, receive transmission on the current frequency for the - * region */ -typedef enum { - SubGhzRegulationOnlyRx, /**only Rx*/ - SubGhzRegulationTxRx, /**TxRx*/ -} SubGhzRegulation; - /* Mirror RX/TX async modulation signal to specified pin * * @warning Configures pin to output mode. Make sure it is not connected @@ -70,6 +39,12 @@ typedef enum { */ void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin); +/** Get data GPIO + * + * @return pointer to the gpio pin structure + */ +const GpioPin* furi_hal_subghz_get_data_gpio(); + /** Initialize and switch to power save mode Used by internal API-HAL * initialization routine Can be used to reinitialize device to safe state and * send it to sleep @@ -84,23 +59,17 @@ void furi_hal_subghz_sleep(); */ void furi_hal_subghz_dump_state(); -/** Load registers from preset by preset name - * - * @param preset to load - */ -void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset); - /** Load custom registers from preset * * @param preset_data registers to load */ -void furi_hal_subghz_load_custom_preset(uint8_t* preset_data); +void furi_hal_subghz_load_custom_preset(const uint8_t* preset_data); /** Load registers * * @param data Registers data */ -void furi_hal_subghz_load_registers(uint8_t* data); +void furi_hal_subghz_load_registers(const uint8_t* data); /** Load PATABLE * diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h b/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h deleted file mode 100644 index 5ea17b6ddd0..00000000000 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz_configs.h +++ /dev/null @@ -1,314 +0,0 @@ -#pragma once - -#include - -static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = { - // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration - - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input - - /* FIFO and internals */ - {CC1101_FIFOTHR, 0x47}, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32 - - /* Packet engine */ - {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening - - /* Frequency Synthesizer Control */ - {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz - - // Modem Configuration - {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz - {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz - {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync - {CC1101_MDMCFG3, 0x32}, // Data rate is 3.79372 kBaud - {CC1101_MDMCFG4, 0x67}, // Rx BW filter is 270.833333kHz - - /* Main Radio Control State Machine */ - {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) - - /* Frequency Offset Compensation Configuration */ - {CC1101_FOCCFG, - 0x18}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - {CC1101_AGCCTRL0, - 0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary - {CC1101_AGCCTRL1, - 0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - {CC1101_AGCCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB - - /* Wake on radio and timeouts control */ - {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours - - /* Frontend configuration */ - {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1] - {CC1101_FREND1, 0xB6}, // - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = { - // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration - - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input - - /* FIFO and internals */ - {CC1101_FIFOTHR, 0x07}, // The only important bit is ADC_RETENTION - - /* Packet engine */ - {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening - - /* Frequency Synthesizer Control */ - {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz - - // Modem Configuration - {CC1101_MDMCFG0, 0x00}, // Channel spacing is 25kHz - {CC1101_MDMCFG1, 0x00}, // Channel spacing is 25kHz - {CC1101_MDMCFG2, 0x30}, // Format ASK/OOK, No preamble/sync - {CC1101_MDMCFG3, 0x32}, // Data rate is 3.79372 kBaud - {CC1101_MDMCFG4, 0x17}, // Rx BW filter is 650.000kHz - - /* Main Radio Control State Machine */ - {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) - - /* Frequency Offset Compensation Configuration */ - {CC1101_FOCCFG, - 0x18}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - // {CC1101_AGCTRL0,0x40}, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary - // {CC1101_AGCTRL1,0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - // {CC1101_AGCCTRL2, 0x03}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB - //MAGN_TARGET for RX filter BW =< 100 kHz is 0x3. For higher RX filter BW's MAGN_TARGET is 0x7. - {CC1101_AGCCTRL0, - 0x91}, // 10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary - {CC1101_AGCCTRL1, - 0x0}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - {CC1101_AGCCTRL2, 0x07}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB - - /* Wake on radio and timeouts control */ - {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours - - /* Frontend configuration */ - {CC1101_FREND0, 0x11}, // Adjusts current TX LO buffer + high is PATABLE[1] - {CC1101_FREND1, 0xB6}, // - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs[][2] = { - - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input - - /* Frequency Synthesizer Control */ - {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz - - /* Packet engine */ - {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening - {CC1101_PKTCTRL1, 0x04}, - - // // Modem Configuration - {CC1101_MDMCFG0, 0x00}, - {CC1101_MDMCFG1, 0x02}, - {CC1101_MDMCFG2, 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) - {CC1101_MDMCFG3, 0x83}, // Data rate is 4.79794 kBaud - {CC1101_MDMCFG4, 0x67}, //Rx BW filter is 270.833333 kHz - {CC1101_DEVIATN, 0x04}, //Deviation 2.380371 kHz - - /* Main Radio Control State Machine */ - {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) - - /* Frequency Offset Compensation Configuration */ - {CC1101_FOCCFG, - 0x16}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - {CC1101_AGCCTRL0, - 0x91}, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary - {CC1101_AGCCTRL1, - 0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - {CC1101_AGCCTRL2, 0x07}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB - - /* Wake on radio and timeouts control */ - {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours - - /* Frontend configuration */ - {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer - {CC1101_FREND1, 0x56}, - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs[][2] = { - - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x0D}, // GD0 as async serial data output/input - - /* Frequency Synthesizer Control */ - {CC1101_FSCTRL1, 0x06}, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz - - /* Packet engine */ - {CC1101_PKTCTRL0, 0x32}, // Async, continious, no whitening - {CC1101_PKTCTRL1, 0x04}, - - // // Modem Configuration - {CC1101_MDMCFG0, 0x00}, - {CC1101_MDMCFG1, 0x02}, - {CC1101_MDMCFG2, 0x04}, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) - {CC1101_MDMCFG3, 0x83}, // Data rate is 4.79794 kBaud - {CC1101_MDMCFG4, 0x67}, //Rx BW filter is 270.833333 kHz - {CC1101_DEVIATN, 0x47}, //Deviation 47.60742 kHz - - /* Main Radio Control State Machine */ - {CC1101_MCSM0, 0x18}, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) - - /* Frequency Offset Compensation Configuration */ - {CC1101_FOCCFG, - 0x16}, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - {CC1101_AGCCTRL0, - 0x91}, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary - {CC1101_AGCCTRL1, - 0x00}, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - {CC1101_AGCCTRL2, 0x07}, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB - - /* Wake on radio and timeouts control */ - {CC1101_WORCTRL, 0xFB}, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours - - /* Frontend configuration */ - {CC1101_FREND0, 0x10}, // Adjusts current TX LO buffer - {CC1101_FREND1, 0x56}, - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_msk_99_97kb_async_regs[][2] = { - /* GPIO GD0 */ - {CC1101_IOCFG0, 0x06}, - - {CC1101_FIFOTHR, 0x07}, // The only important bit is ADC_RETENTION - {CC1101_SYNC1, 0x46}, - {CC1101_SYNC0, 0x4C}, - {CC1101_ADDR, 0x00}, - {CC1101_PKTLEN, 0x00}, - {CC1101_CHANNR, 0x00}, - - {CC1101_PKTCTRL0, 0x05}, - - {CC1101_FSCTRL0, 0x23}, - {CC1101_FSCTRL1, 0x06}, - - {CC1101_MDMCFG0, 0xF8}, - {CC1101_MDMCFG1, 0x22}, - {CC1101_MDMCFG2, 0x72}, - {CC1101_MDMCFG3, 0xF8}, - {CC1101_MDMCFG4, 0x5B}, - {CC1101_DEVIATN, 0x47}, - - {CC1101_MCSM0, 0x18}, - {CC1101_FOCCFG, 0x16}, - - {CC1101_AGCCTRL0, 0xB2}, - {CC1101_AGCCTRL1, 0x00}, - {CC1101_AGCCTRL2, 0xC7}, - - {CC1101_FREND0, 0x10}, - {CC1101_FREND1, 0x56}, - - {CC1101_BSCFG, 0x1C}, - {CC1101_FSTEST, 0x59}, - - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_gfsk_9_99kb_async_regs[][2] = { - - {CC1101_IOCFG0, 0x06}, //GDO0 Output Pin Configuration - {CC1101_FIFOTHR, 0x47}, //RX FIFO and TX FIFO Thresholds - - //1 : CRC calculation in TX and CRC check in RX enabled, - //1 : Variable packet length mode. Packet length configured by the first byte after sync word - {CC1101_PKTCTRL0, 0x05}, - - {CC1101_FSCTRL1, 0x06}, //Frequency Synthesizer Control - - {CC1101_SYNC1, 0x46}, - {CC1101_SYNC0, 0x4C}, - {CC1101_ADDR, 0x00}, - {CC1101_PKTLEN, 0x00}, - - {CC1101_MDMCFG4, 0xC8}, //Modem Configuration 9.99 - {CC1101_MDMCFG3, 0x93}, //Modem Configuration - {CC1101_MDMCFG2, 0x12}, // 2: 16/16 sync word bits detected - - {CC1101_DEVIATN, 0x34}, //Deviation = 19.042969 - {CC1101_MCSM0, 0x18}, //Main Radio Control State Machine Configuration - {CC1101_FOCCFG, 0x16}, //Frequency Offset Compensation Configuration - - {CC1101_AGCCTRL2, 0x43}, //AGC Control - {CC1101_AGCCTRL1, 0x40}, - {CC1101_AGCCTRL0, 0x91}, - - {CC1101_WORCTRL, 0xFB}, //Wake On Radio Control - /* End */ - {0, 0}, -}; - -static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = { - 0x00, - 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - -static const uint8_t furi_hal_subghz_preset_ook_async_patable_au[8] = { - 0x00, - 0x37, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - -static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = { - 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - -static const uint8_t furi_hal_subghz_preset_msk_async_patable[8] = { - 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - -static const uint8_t furi_hal_subghz_preset_gfsk_async_patable[8] = { - 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; diff --git a/firmware/targets/f7/platform_specific/intrinsic_export.h b/firmware/targets/f7/platform_specific/intrinsic_export.h index 8dbc4bd0320..ca343a12862 100644 --- a/firmware/targets/f7/platform_specific/intrinsic_export.h +++ b/firmware/targets/f7/platform_specific/intrinsic_export.h @@ -1,10 +1,12 @@ #include +#include #ifdef __cplusplus extern "C" { #endif void __clear_cache(void*, void*); +void* __aeabi_uldivmod(uint64_t, uint64_t); #ifdef __cplusplus } diff --git a/firmware/targets/f7/target.json b/firmware/targets/f7/target.json index 5d8231b20ab..0c083b68ddb 100644 --- a/firmware/targets/f7/target.json +++ b/firmware/targets/f7/target.json @@ -38,6 +38,7 @@ "assets", "one_wire", "ibutton", + "music_worker", "misc", "mbedtls", "lfrfid", diff --git a/furi/core/check.c b/furi/core/check.c index 478f3aacccf..c5c4ef1a4af 100644 --- a/furi/core/check.c +++ b/furi/core/check.c @@ -166,7 +166,11 @@ FURI_NORETURN void __furi_crash() { RESTORE_REGISTERS_AND_HALT_MCU(true); #ifndef FURI_DEBUG } else { - furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message); + uint32_t ptr = (uint32_t)__furi_check_message; + if(ptr < FLASH_BASE || ptr > (FLASH_BASE + FLASH_SIZE)) { + ptr = (uint32_t) "Check serial logs"; + } + furi_hal_rtc_set_fault_data(ptr); furi_hal_console_puts("\r\nRebooting system.\r\n"); furi_hal_console_puts("\033[0m\r\n"); furi_hal_power_reset(); diff --git a/furi/core/check.h b/furi/core/check.h index ea83f2219c2..004422e807e 100644 --- a/furi/core/check.h +++ b/furi/core/check.h @@ -13,6 +13,8 @@ */ #pragma once +#include + #ifdef __cplusplus extern "C" { #define FURI_NORETURN [[noreturn]] @@ -48,28 +50,47 @@ FURI_NORETURN void __furi_halt(); } while(0) /** Check condition and crash if check failed */ -#define furi_check(__e) \ - do { \ - if(!(__e)) { \ - furi_crash(__FURI_CHECK_MESSAGE_FLAG); \ - } \ +#define __furi_check(__e, __m) \ + do { \ + if(!(__e)) { \ + furi_crash(__m); \ + } \ } while(0) +/** Check condition and crash if failed + * + * @param condition to check + * @param optional message + */ +#define furi_check(...) \ + M_APPLY(__furi_check, M_DEFAULT_ARGS(2, (__FURI_CHECK_MESSAGE_FLAG), __VA_ARGS__)) + /** Only in debug build: Assert condition and crash if assert failed */ #ifdef FURI_DEBUG -#define furi_assert(__e) \ - do { \ - if(!(__e)) { \ - furi_crash(__FURI_ASSERT_MESSAGE_FLAG); \ - } \ +#define __furi_assert(__e, __m) \ + do { \ + if(!(__e)) { \ + furi_crash(__m); \ + } \ } while(0) #else -#define furi_assert(__e) \ - do { \ - ((void)(__e)); \ +#define __furi_assert(__e, __m) \ + do { \ + ((void)(__e)); \ + ((void)(__m)); \ } while(0) #endif +/** Assert condition and crash if failed + * + * @warning only will do check if firmware compiled in debug mode + * + * @param condition to check + * @param optional message + */ +#define furi_assert(...) \ + M_APPLY(__furi_assert, M_DEFAULT_ARGS(2, (__FURI_ASSERT_MESSAGE_FLAG), __VA_ARGS__)) + #ifdef __cplusplus } #endif diff --git a/furi/core/string.c b/furi/core/string.c index 4384fe06a22..682c8d40977 100644 --- a/furi/core/string.c +++ b/furi/core/string.c @@ -296,7 +296,9 @@ static FuriStringUTF8State state_to_furi_state(m_str1ng_utf8_state_e state) { } void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnicodeValue* unicode) { + string_unicode_t m_u = *unicode; m_str1ng_utf8_state_e m_state = furi_state_to_state(*state); - m_str1ng_utf8_decode(c, &m_state, unicode); + m_str1ng_utf8_decode(c, &m_state, &m_u); *state = state_to_furi_state(m_state); + *unicode = m_u; } diff --git a/furi/core/string.h b/furi/core/string.h index 0523d3ba04e..7529deacd7c 100644 --- a/furi/core/string.h +++ b/furi/core/string.h @@ -633,20 +633,17 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico * @brief Search for a string (or C string) in a string * (string, [c]string[, start=0]) */ -#define furi_string_search(v, ...) \ - M_APPLY( \ - FURI_STRING_SELECT3, \ - furi_string_search, \ - furi_string_search_str, \ - v, \ - M_IF_DEFAULT1(0, __VA_ARGS__)) - +#define furi_string_search(...) \ + M_APPLY( \ + FURI_STRING_SELECT3, \ + furi_string_search, \ + furi_string_search_str, \ + M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) /** * @brief Search for a C string in a string * (string, cstring[, start=0]) */ -#define furi_string_search_str(v, ...) \ - M_APPLY(furi_string_search_str, v, M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_search_str(...) furi_string_search_str(M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) /** * @brief Test if the string starts with the given string (or C string). @@ -672,41 +669,36 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico * @brief Trim a string from the given set of characters (default is " \n\r\t"). * (string[, set=" \n\r\t"]) */ -#define furi_string_trim(...) M_APPLY(furi_string_trim, M_IF_DEFAULT1(" \n\r\t", __VA_ARGS__)) +#define furi_string_trim(...) furi_string_trim(M_DEFAULT_ARGS(2, (" \n\r\t"), __VA_ARGS__)) /** * @brief Search for a character in a string. * (string, character[, start=0]) */ -#define furi_string_search_char(v, ...) \ - M_APPLY(furi_string_search_char, v, M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_search_char(...) furi_string_search_char(M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) /** * @brief Reverse Search for a character in a string. * (string, character[, start=0]) */ -#define furi_string_search_rchar(v, ...) \ - M_APPLY(furi_string_search_rchar, v, M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_search_rchar(...) furi_string_search_rchar(M_DEFAULT_ARGS(3, (0), __VA_ARGS__)) /** * @brief Replace a string to another string (or C string to another C string) in a string. * (string, [c]string, [c]string[, start=0]) */ -#define furi_string_replace(a, b, ...) \ - M_APPLY( \ - FURI_STRING_SELECT4, \ - furi_string_replace, \ - furi_string_replace_str, \ - a, \ - b, \ - M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_replace(...) \ + M_APPLY( \ + FURI_STRING_SELECT4, \ + furi_string_replace, \ + furi_string_replace_str, \ + M_DEFAULT_ARGS(4, (0), __VA_ARGS__)) /** * @brief Replace a C string to another C string in a string. * (string, cstring, cstring[, start=0]) */ -#define furi_string_replace_str(a, b, ...) \ - M_APPLY(furi_string_replace_str, a, b, M_IF_DEFAULT1(0, __VA_ARGS__)) +#define furi_string_replace_str(...) furi_string_replace_str(M_DEFAULT_ARGS(4, (0), __VA_ARGS__)) /** * @brief INIT OPLIST for FuriString. @@ -743,4 +735,4 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/lib/SConscript b/lib/SConscript index 495ba4bfe24..ab78c6ea4d4 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -15,6 +15,7 @@ env.Append( Dir("u8g2"), Dir("update_util"), Dir("print"), + Dir("music_worker"), ], ) @@ -100,6 +101,7 @@ libs = env.BuildModules( "misc", "lfrfid", "flipper_application", + "music_worker", ], ) diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index 39aa9cbc6e1..25adb878b78 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -51,8 +51,16 @@ struct DigitalSignalInternals { #define T_TIM 1562 /* 15.625 ns *100 */ #define T_TIM_DIV2 781 /* 15.625 ns / 2 *100 */ +/* end marker in DMA ringbuffer, will get written into timer register at the end */ +#define SEQ_TIMER_MAX 0xFFFFFFFF + +/* time to wait in loops before returning */ +#define SEQ_LOCK_WAIT_MS 10UL +#define SEQ_LOCK_WAIT_TICKS (SEQ_LOCK_WAIT_MS * 1000 * 64) + /* maximum entry count of the sequence dma ring buffer */ -#define SEQUENCE_DMA_RINGBUFFER_SIZE 32 +#define RINGBUFFER_SIZE 128 + /* maximum number of DigitalSignals in a sequence */ #define SEQUENCE_SIGNALS_SIZE 32 /* @@ -252,7 +260,7 @@ static void digital_signal_setup_timer() { LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); LL_TIM_SetPrescaler(TIM2, 0); - LL_TIM_SetAutoReload(TIM2, 0xFFFFFFFF); + LL_TIM_SetAutoReload(TIM2, SEQ_TIMER_MAX); LL_TIM_SetCounter(TIM2, 0); } @@ -335,7 +343,7 @@ DigitalSequence* digital_sequence_alloc(uint32_t size, const GpioPin* gpio) { sequence->bake = false; sequence->dma_buffer = malloc(sizeof(struct ReloadBuffer)); - sequence->dma_buffer->size = SEQUENCE_DMA_RINGBUFFER_SIZE; + sequence->dma_buffer->size = RINGBUFFER_SIZE; sequence->dma_buffer->buffer = malloc(sequence->dma_buffer->size * sizeof(uint32_t)); sequence->dma_config_gpio.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; @@ -454,39 +462,23 @@ static DigitalSignal* digital_sequence_bake(DigitalSequence* sequence) { return ret; } -static void digital_sequence_update_pos(DigitalSequence* sequence) { - struct ReloadBuffer* dma_buffer = sequence->dma_buffer; - - dma_buffer->read_pos = dma_buffer->size - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); -} - -static const uint32_t wait_ms = 10; -static const uint32_t wait_ticks = wait_ms * 1000 * 64; - static void digital_sequence_finish(DigitalSequence* sequence) { struct ReloadBuffer* dma_buffer = sequence->dma_buffer; if(dma_buffer->dma_active) { uint32_t prev_timer = DWT->CYCCNT; - uint32_t end_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; do { - uint32_t last_pos = dma_buffer->read_pos; - - digital_sequence_update_pos(sequence); - - /* we are finished, when the DMA transferred the 0xFFFFFFFF-timer which is the current write_pos */ - if(dma_buffer->read_pos == end_pos) { + /* we are finished, when the DMA transferred the SEQ_TIMER_MAX marker */ + if(TIM2->ARR == SEQ_TIMER_MAX) { break; } - - if(last_pos != dma_buffer->read_pos) { //-V547 - prev_timer = DWT->CYCCNT; - } - if(DWT->CYCCNT - prev_timer > wait_ticks) { + if(DWT->CYCCNT - prev_timer > SEQ_LOCK_WAIT_TICKS) { + dma_buffer->read_pos = + RINGBUFFER_SIZE - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); FURI_LOG_D( TAG, "[SEQ] hung %lu ms in finish (ARR 0x%08lx, read %lu, write %lu)", - wait_ms, + SEQ_LOCK_WAIT_MS, TIM2->ARR, dma_buffer->read_pos, dma_buffer->write_pos); @@ -504,23 +496,30 @@ static void digital_sequence_queue_pulse(DigitalSequence* sequence, uint32_t len if(dma_buffer->dma_active) { uint32_t prev_timer = DWT->CYCCNT; - uint32_t end_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; do { - uint32_t last_pos = dma_buffer->read_pos; - digital_sequence_update_pos(sequence); + dma_buffer->read_pos = RINGBUFFER_SIZE - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2); + + uint32_t free = + (RINGBUFFER_SIZE + dma_buffer->read_pos - dma_buffer->write_pos) % RINGBUFFER_SIZE; - if(dma_buffer->read_pos != end_pos) { + if(free > 2) { break; } - if(last_pos != dma_buffer->read_pos) { //-V547 - prev_timer = DWT->CYCCNT; - } - if(DWT->CYCCNT - prev_timer > wait_ticks) { + if(DWT->CYCCNT - prev_timer > SEQ_LOCK_WAIT_TICKS) { FURI_LOG_D( TAG, "[SEQ] hung %lu ms in queue (ARR 0x%08lx, read %lu, write %lu)", - wait_ms, + SEQ_LOCK_WAIT_MS, + TIM2->ARR, + dma_buffer->read_pos, + dma_buffer->write_pos); + break; + } + if(TIM2->ARR == SEQ_TIMER_MAX) { + FURI_LOG_D( + TAG, + "[SEQ] buffer underrun in queue (ARR 0x%08lx, read %lu, write %lu)", TIM2->ARR, dma_buffer->read_pos, dma_buffer->write_pos); @@ -530,8 +529,9 @@ static void digital_sequence_queue_pulse(DigitalSequence* sequence, uint32_t len } dma_buffer->buffer[dma_buffer->write_pos] = length; - dma_buffer->write_pos = (dma_buffer->write_pos + 1) % dma_buffer->size; - dma_buffer->buffer[dma_buffer->write_pos] = 0xFFFFFFFF; + dma_buffer->write_pos++; + dma_buffer->write_pos %= RINGBUFFER_SIZE; + dma_buffer->buffer[dma_buffer->write_pos] = SEQ_TIMER_MAX; } bool digital_sequence_send(DigitalSequence* sequence) { @@ -553,90 +553,97 @@ bool digital_sequence_send(DigitalSequence* sequence) { return true; } - int32_t remainder = 0; - bool traded_first = false; + if(!sequence->sequence_used) { + return false; + } - FURI_CRITICAL_ENTER(); + int32_t remainder = 0; + uint32_t trade_for_next = 0; + uint32_t seq_pos_next = 1; dma_buffer->dma_active = false; - dma_buffer->buffer[0] = 0xFFFFFFFF; + dma_buffer->buffer[0] = SEQ_TIMER_MAX; dma_buffer->read_pos = 0; dma_buffer->write_pos = 0; - for(uint32_t seq_pos = 0; seq_pos < sequence->sequence_used; seq_pos++) { - uint8_t signal_index = sequence->sequence[seq_pos]; - DigitalSignal* sig = sequence->signals[signal_index]; - bool last_signal = ((seq_pos + 1) == sequence->sequence_used); + /* already prepare the current signal pointer */ + DigitalSignal* sig = sequence->signals[sequence->sequence[0]]; + DigitalSignal* sig_next = NULL; + /* re-use the GPIO buffer from the first signal */ + sequence->gpio_buff = sig->internals->gpio_buff; + + FURI_CRITICAL_ENTER(); + + while(sig) { + bool last_signal = (seq_pos_next >= sequence->sequence_used); - /* all signals are prepared and we can re-use the GPIO buffer from the fist signal */ - if(seq_pos == 0) { - sequence->gpio_buff = sig->internals->gpio_buff; + if(!last_signal) { + sig_next = sequence->signals[sequence->sequence[seq_pos_next++]]; } for(uint32_t pulse_pos = 0; pulse_pos < sig->internals->reload_reg_entries; pulse_pos++) { - if(traded_first) { - traded_first = false; - continue; - } - uint32_t pulse_length = 0; - bool last_pulse = ((pulse_pos + 1) == sig->internals->reload_reg_entries); + bool last_pulse = ((pulse_pos + 1) >= sig->internals->reload_reg_entries); + uint32_t pulse_length = sig->reload_reg_buff[pulse_pos] + trade_for_next; - pulse_length = sig->reload_reg_buff[pulse_pos]; + trade_for_next = 0; /* when we are too late more than half a tick, make the first edge temporarily longer */ if(remainder >= T_TIM_DIV2) { remainder -= T_TIM; pulse_length += 1; } - remainder += sig->internals->reload_reg_remainder; - - /* last pulse in that signal and have a next signal? */ - if(last_pulse) { - if((seq_pos + 1) < sequence->sequence_used) { - DigitalSignal* sig_next = sequence->signals[sequence->sequence[seq_pos + 1]]; - /* when a signal ends with the same level as the next signal begins, let the fist signal generate the whole pulse */ - /* beware, we do not want the level after the last edge, but the last level before that edge */ - bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0); + /* last pulse in current signal and have a next signal? */ + if(last_pulse && sig_next) { + /* when a signal ends with the same level as the next signal begins, let the next signal generate the whole pulse. + beware, we do not want the level after the last edge, but the last level before that edge */ + bool end_level = sig->start_level ^ ((sig->edge_cnt % 2) == 0); - /* take from the next, add it to the current if they have the same level */ - if(end_level == sig_next->start_level) { - pulse_length += sig_next->reload_reg_buff[0]; - traded_first = true; - } + /* if they have the same level, pass the duration to the next pulse(s) */ + if(end_level == sig_next->start_level) { + trade_for_next = pulse_length; } } - digital_sequence_queue_pulse(sequence, pulse_length); + /* if it was decided, that the next signal's first pulse shall also handle our "length", then do not queue here */ + if(!trade_for_next) { + digital_sequence_queue_pulse(sequence, pulse_length); - /* start transmission when buffer was filled enough */ - bool start_send = sequence->dma_buffer->write_pos >= (sequence->dma_buffer->size - 4); - - /* or it was the last pulse */ - if(last_pulse && last_signal) { - start_send = true; - } + if(!dma_buffer->dma_active) { + /* start transmission when buffer was filled enough */ + bool start_send = sequence->dma_buffer->write_pos >= (RINGBUFFER_SIZE - 2); - /* start transmission */ - if(start_send && !dma_buffer->dma_active) { - digital_sequence_setup_dma(sequence); - digital_signal_setup_timer(); + /* or it was the last pulse */ + if(last_pulse && last_signal) { + start_send = true; + } - /* if the send time is specified, wait till the core timer passed beyond that time */ - if(sequence->send_time_active) { - sequence->send_time_active = false; - while(sequence->send_time - DWT->CYCCNT < 0x80000000) { + /* start transmission */ + if(start_send) { + digital_sequence_setup_dma(sequence); + digital_signal_setup_timer(); + + /* if the send time is specified, wait till the core timer passed beyond that time */ + if(sequence->send_time_active) { + sequence->send_time_active = false; + while(sequence->send_time - DWT->CYCCNT < 0x80000000) { + } + } + digital_signal_start_timer(); + dma_buffer->dma_active = true; } } - digital_signal_start_timer(); - dma_buffer->dma_active = true; } } + + remainder += sig->internals->reload_reg_remainder; + sig = sig_next; + sig_next = NULL; } /* wait until last dma transaction was finished */ - digital_sequence_finish(sequence); FURI_CRITICAL_EXIT(); + digital_sequence_finish(sequence); return true; } diff --git a/lib/flipper_application/api_hashtable/api_hashtable.cpp b/lib/flipper_application/api_hashtable/api_hashtable.cpp index 022792dce63..6db5fb5fde6 100644 --- a/lib/flipper_application/api_hashtable/api_hashtable.cpp +++ b/lib/flipper_application/api_hashtable/api_hashtable.cpp @@ -7,27 +7,22 @@ bool elf_resolve_from_hashtable( const ElfApiInterface* interface, - const char* name, + uint32_t hash, Elf32_Addr* address) { + bool result = false; const HashtableApiInterface* hashtable_interface = static_cast(interface); - bool result = false; - uint32_t gnu_sym_hash = elf_gnu_hash(name); sym_entry key = { - .hash = gnu_sym_hash, + .hash = hash, .address = 0, }; auto find_res = std::lower_bound(hashtable_interface->table_cbegin, hashtable_interface->table_cend, key); - if((find_res == hashtable_interface->table_cend || (find_res->hash != gnu_sym_hash))) { + if((find_res == hashtable_interface->table_cend || (find_res->hash != hash))) { FURI_LOG_W( - TAG, - "Can't find symbol '%s' (hash %lx) @ %p!", - name, - gnu_sym_hash, - hashtable_interface->table_cbegin); + TAG, "Can't find symbol with hash %lx @ %p!", hash, hashtable_interface->table_cbegin); result = false; } else { result = true; @@ -36,3 +31,7 @@ bool elf_resolve_from_hashtable( return result; } + +uint32_t elf_symbolname_hash(const char* s) { + return elf_gnu_hash(s); +} \ No newline at end of file diff --git a/lib/flipper_application/api_hashtable/api_hashtable.h b/lib/flipper_application/api_hashtable/api_hashtable.h index 7e4b4aba1dd..7ba6aab9727 100644 --- a/lib/flipper_application/api_hashtable/api_hashtable.h +++ b/lib/flipper_application/api_hashtable/api_hashtable.h @@ -19,15 +19,17 @@ struct sym_entry { /** * @brief Resolver for API entries using a pre-sorted table with hashes * @param interface pointer to HashtableApiInterface - * @param name function name + * @param hash gnu hash of function name * @param address output for function address * @return true if the table contains a function */ bool elf_resolve_from_hashtable( const ElfApiInterface* interface, - const char* name, + uint32_t hash, Elf32_Addr* address); +uint32_t elf_symbolname_hash(const char* s); + #ifdef __cplusplus } @@ -48,8 +50,10 @@ struct HashtableApiInterface : public ElfApiInterface { .hash = elf_gnu_hash(#x), .address = (uint32_t)(static_cast(x)) \ } -#define API_VARIABLE(x, var_type) \ - sym_entry { .hash = elf_gnu_hash(#x), .address = (uint32_t)(&(x)), } +#define API_VARIABLE(x, var_type) \ + sym_entry { \ + .hash = elf_gnu_hash(#x), .address = (uint32_t)(&(x)), \ + } constexpr bool operator<(const sym_entry& k1, const sym_entry& k2) { return k1.hash < k2.hash; diff --git a/lib/flipper_application/elf/elf_api_interface.h b/lib/flipper_application/elf/elf_api_interface.h index f07df4edb76..facdc44473d 100644 --- a/lib/flipper_application/elf/elf_api_interface.h +++ b/lib/flipper_application/elf/elf_api_interface.h @@ -11,6 +11,6 @@ typedef struct ElfApiInterface { uint16_t api_version_minor; bool (*resolver_callback)( const struct ElfApiInterface* interface, - const char* name, + uint32_t hash, Elf32_Addr* address); } ElfApiInterface; diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 0338144a9a7..fc9dd06ba81 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -2,6 +2,7 @@ #include "elf_file.h" #include "elf_file_i.h" #include "elf_api_interface.h" +#include "../api_hashtable/api_hashtable.h" #define TAG "elf" @@ -9,6 +10,7 @@ #define SECTION_OFFSET(e, n) ((e)->section_table + (n) * sizeof(Elf32_Shdr)) #define IS_FLAGS_SET(v, m) (((v) & (m)) == (m)) #define RESOLVER_THREAD_YIELD_STEP 30 +#define FAST_RELOCATION_VERSION 1 // #define ELF_DEBUG_LOG 1 @@ -71,6 +73,7 @@ static ELFSection* elf_file_get_or_put_section(ELFFile* elf, const char* name) { .size = 0, .rel_count = 0, .rel_offset = 0, + .fast_rel = NULL, }); section_p = elf_file_get_section(elf, name); } @@ -168,7 +171,8 @@ static ELFSection* elf_section_of(ELFFile* elf, int index) { static Elf32_Addr elf_address_of(ELFFile* elf, Elf32_Sym* sym, const char* sName) { if(sym->st_shndx == SHN_UNDEF) { Elf32_Addr addr = 0; - if(elf->api_interface->resolver_callback(elf->api_interface, sName, &addr)) { + uint32_t hash = elf_symbolname_hash(sName); + if(elf->api_interface->resolver_callback(elf->api_interface, hash, &addr)) { return addr; } } else { @@ -424,6 +428,7 @@ typedef enum { SectionTypeSymTab = 1 << 3, SectionTypeStrTab = 1 << 4, SectionTypeDebugLink = 1 << 5, + SectionTypeFastRelData = 1 << 6, SectionTypeValid = SectionTypeSymTab | SectionTypeStrTab, } SectionType; @@ -505,7 +510,8 @@ static SectionType elf_preload_section( // TODO: how to do it not by name? // .ARM: type 0x70000001, flags SHF_ALLOC | SHF_LINK_ORDER // .rel.ARM: type 0x9, flags SHT_REL - if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.")) { + if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.") || + str_prefix(name, ".fast.rel.ARM.")) { FURI_LOG_D(TAG, "Ignoring ARM section"); return SectionTypeUnused; } @@ -536,11 +542,31 @@ static SectionType elf_preload_section( // Load link info section if(section_header->sh_flags & SHF_INFO_LINK) { - name = name + strlen(".rel"); + if(str_prefix(name, ".rel")) { + name = name + strlen(".rel"); + ELFSection* section_p = elf_file_get_or_put_section(elf, name); + section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel); + section_p->rel_offset = section_header->sh_offset; + return SectionTypeRelData; + } else { + FURI_LOG_E(TAG, "Unknown link info section '%s'", name); + return SectionTypeERROR; + } + } + + // Load fast rel section + if(str_prefix(name, ".fast.rel")) { + name = name + strlen(".fast.rel"); ELFSection* section_p = elf_file_get_or_put_section(elf, name); - section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel); - section_p->rel_offset = section_header->sh_offset; - return SectionTypeRelData; + section_p->fast_rel = malloc(sizeof(ELFSection)); + + if(!elf_load_section_data(elf, section_p->fast_rel, section_header)) { + FURI_LOG_E(TAG, "Error loading section '%s'", name); + return SectionTypeERROR; + } + + FURI_LOG_D(TAG, "Loaded fast rel section for '%s'", name); + return SectionTypeFastRelData; } // Load symbol table @@ -571,8 +597,90 @@ static SectionType elf_preload_section( return SectionTypeUnused; } +static Elf32_Addr elf_address_of_by_hash(ELFFile* elf, uint32_t hash) { + Elf32_Addr addr = 0; + if(elf->api_interface->resolver_callback(elf->api_interface, hash, &addr)) { + return addr; + } + return ELF_INVALID_ADDRESS; +} + +static bool elf_relocate_fast(ELFFile* elf, ELFSection* s) { + UNUSED(elf); + const uint8_t* start = s->fast_rel->data; + const uint8_t version = *start; + + if(version != FAST_RELOCATION_VERSION) { + FURI_LOG_E(TAG, "Unsupported fast relocation version %d", version); + return false; + } + start += 1; + + const uint32_t records_count = *((uint32_t*)start); + start += 4; + FURI_LOG_D(TAG, "Fast relocation records count: %ld", records_count); + + for(uint32_t i = 0; i < records_count; i++) { + bool is_section = (*start & (0x1 << 7)) ? true : false; + uint8_t type = *start & 0x7F; + start += 1; + uint32_t hash_or_section_index = *((uint32_t*)start); + start += 4; + + uint32_t section_value = ELF_INVALID_ADDRESS; + if(is_section) { + section_value = *((uint32_t*)start); + start += 4; + } + + const uint32_t offsets_count = *((uint32_t*)start); + start += 4; + + FURI_LOG_D( + TAG, + "Fast relocation record %ld: is_section=%d, type=%d, hash_or_section_index=%lX, offsets_count=%ld", + i, + is_section, + type, + hash_or_section_index, + offsets_count); + + Elf32_Addr address = 0; + if(is_section) { + ELFSection* symSec = elf_section_of(elf, hash_or_section_index); + if(symSec) { + address = ((Elf32_Addr)symSec->data) + section_value; + } + } else { + address = elf_address_of_by_hash(elf, hash_or_section_index); + } + + if(address == ELF_INVALID_ADDRESS) { + FURI_LOG_E(TAG, "Failed to resolve address for hash %lX", hash_or_section_index); + return false; + } + + for(uint32_t j = 0; j < offsets_count; j++) { + uint32_t offset = *((uint32_t*)start) & 0x00FFFFFF; + start += 3; + // FURI_LOG_I(TAG, " Fast relocation offset %ld: %ld", j, offset); + Elf32_Addr relAddr = ((Elf32_Addr)s->data) + offset; + elf_relocate_symbol(elf, relAddr, type, address); + } + } + + aligned_free(s->fast_rel->data); + free(s->fast_rel); + s->fast_rel = NULL; + + return true; +} + static bool elf_relocate_section(ELFFile* elf, ELFSection* section) { - if(section->rel_count) { + if(section->fast_rel) { + FURI_LOG_D(TAG, "Fast relocating section"); + return elf_relocate_fast(elf, section); + } else if(section->rel_count) { FURI_LOG_D(TAG, "Relocating section"); return elf_relocate(elf, section); } else { @@ -630,6 +738,10 @@ void elf_file_free(ELFFile* elf) { if(itref->value.data) { aligned_free(itref->value.data); } + if(itref->value.fast_rel) { + aligned_free(itref->value.fast_rel->data); + free(itref->value.fast_rel); + } free((void*)itref->key); } diff --git a/lib/flipper_application/elf/elf_file_i.h b/lib/flipper_application/elf/elf_file_i.h index af9a1d9b4fb..39cadfdc6f6 100644 --- a/lib/flipper_application/elf/elf_file_i.h +++ b/lib/flipper_application/elf/elf_file_i.h @@ -13,14 +13,18 @@ DICT_DEF2(AddressCache, int, M_DEFAULT_OPLIST, Elf32_Addr, M_DEFAULT_OPLIST) */ typedef int32_t(entry_t)(void*); -typedef struct { +typedef struct ELFSection ELFSection; + +struct ELFSection { void* data; - uint16_t sec_idx; Elf32_Word size; size_t rel_count; Elf32_Off rel_offset; -} ELFSection; + ELFSection* fast_rel; + + uint16_t sec_idx; +}; DICT_DEF2(ELFSectionDict, const char*, M_CSTR_OPLIST, ELFSection, M_POD_OPLIST) diff --git a/lib/flipper_application/flipper_application.c b/lib/flipper_application/flipper_application.c index 1b4f5681486..fbcf2973dbe 100644 --- a/lib/flipper_application/flipper_application.c +++ b/lib/flipper_application/flipper_application.c @@ -2,6 +2,7 @@ #include "elf/elf_file.h" #include #include "application_assets.h" +#include #include @@ -81,6 +82,12 @@ void flipper_application_free(FlipperApplication* app) { } elf_file_free(app->elf); + + if(app->ep_thread_args) { + free(app->ep_thread_args); + app->ep_thread_args = NULL; + } + free(app); } @@ -224,10 +231,19 @@ static int32_t flipper_application_thread(void* context) { return ret_code; } -FuriThread* flipper_application_spawn(FlipperApplication* app, void* args) { +FuriThread* flipper_application_alloc_thread(FlipperApplication* app, const char* args) { furi_check(app->thread == NULL); furi_check(!flipper_application_is_plugin(app)); - app->ep_thread_args = args; + + if(app->ep_thread_args) { + free(app->ep_thread_args); + } + + if(args) { + app->ep_thread_args = strdup(args); + } else { + app->ep_thread_args = NULL; + } const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); app->thread = furi_thread_alloc_ex( @@ -289,4 +305,32 @@ const FlipperAppPluginDescriptor* lib_descriptor->ep_api_version); return lib_descriptor; +} + +bool flipper_application_load_name_and_icon( + FuriString* path, + Storage* storage, + uint8_t** icon_ptr, + FuriString* item_name) { + FlipperApplication* app = flipper_application_alloc(storage, firmware_api_interface); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload_manifest(app, furi_string_get_cstr(path)); + + bool load_success = false; + + if(preload_res == FlipperApplicationPreloadStatusSuccess) { + const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); + if(manifest->has_icon) { + memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); + } + furi_string_set(item_name, manifest->name); + load_success = true; + } else { + FURI_LOG_E(TAG, "Failed to preload %s", furi_string_get_cstr(path)); + load_success = false; + } + + flipper_application_free(app); + return load_success; } \ No newline at end of file diff --git a/lib/flipper_application/flipper_application.h b/lib/flipper_application/flipper_application.h index 519cc397108..20baae8264f 100644 --- a/lib/flipper_application/flipper_application.h +++ b/lib/flipper_application/flipper_application.h @@ -106,14 +106,14 @@ const FlipperApplicationManifest* flipper_application_get_manifest(FlipperApplic FlipperApplicationLoadStatus flipper_application_map_to_memory(FlipperApplication* app); /** - * @brief Create application thread at entry point address, using app name and + * @brief Allocate application thread at entry point address, using app name and * stack size from metadata. Returned thread isn't started yet. * Can be only called once for application instance. * @param app Applicaiton pointer - * @param args Object to pass to app's entry point + * @param args Args to pass to app's entry point * @return Created thread */ -FuriThread* flipper_application_spawn(FlipperApplication* app, void* args); +FuriThread* flipper_application_alloc_thread(FlipperApplication* app, const char* args); /** * @brief Check if application is a plugin (not a runnable standalone app) @@ -149,6 +149,21 @@ typedef const FlipperAppPluginDescriptor* (*FlipperApplicationPluginEntryPoint)( const FlipperAppPluginDescriptor* flipper_application_plugin_get_descriptor(FlipperApplication* app); +/** + * @brief Load name and icon from FAP file. + * + * @param path Path to FAP file. + * @param storage Storage instance. + * @param icon_ptr Icon pointer. + * @param item_name Application name. + * @return true if icon and name were loaded successfully. + */ +bool flipper_application_load_name_and_icon( + FuriString* path, + Storage* storage, + uint8_t** icon_ptr, + FuriString* item_name); + #ifdef __cplusplus } #endif diff --git a/lib/flipper_application/plugins/composite_resolver.c b/lib/flipper_application/plugins/composite_resolver.c index 1402c3ad08f..7cc2b340a96 100644 --- a/lib/flipper_application/plugins/composite_resolver.c +++ b/lib/flipper_application/plugins/composite_resolver.c @@ -13,12 +13,12 @@ struct CompositeApiResolver { static bool composite_api_resolver_callback( const ElfApiInterface* interface, - const char* name, + uint32_t hash, Elf32_Addr* address) { CompositeApiResolver* resolver = (CompositeApiResolver*)interface; for M_EACH(interface, resolver->interfaces, ElfApiInterfaceList_t) { - if((*interface)->resolver_callback(*interface, name, address)) { + if((*interface)->resolver_callback(*interface, hash, address)) { return true; } } diff --git a/lib/music_worker/SConscript b/lib/music_worker/SConscript new file mode 100644 index 00000000000..36d01d8596a --- /dev/null +++ b/lib/music_worker/SConscript @@ -0,0 +1,27 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/music_worker", + ], + SDK_HEADERS=[ + File("music_worker.h"), + ], +) + +libenv = env.Clone(FW_LIB_NAME="music_worker") +libenv.ApplyLibFlags() + +libenv.AppendUnique( + CCFLAGS=[ + # Required for lib to be linkable with .faps + "-mword-relocations", + "-mlong-calls", + ], +) + +sources = libenv.GlobRecursive("*.c*") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/applications/external/music_player/music_player_worker.c b/lib/music_worker/music_worker.c similarity index 85% rename from applications/external/music_player/music_player_worker.c rename to lib/music_worker/music_worker.c index ee350ee8045..61fc838f2e3 100644 --- a/applications/external/music_player/music_player_worker.c +++ b/lib/music_worker/music_worker.c @@ -1,4 +1,4 @@ -#include "music_player_worker.h" +#include "music_worker.h" #include #include @@ -9,7 +9,7 @@ #include #include -#define TAG "MusicPlayerWorker" +#define TAG "MusicWorker" #define MUSIC_PLAYER_FILETYPE "Flipper Music Format" #define MUSIC_PLAYER_VERSION 0 @@ -28,11 +28,11 @@ typedef struct { ARRAY_DEF(NoteBlockArray, NoteBlock, M_POD_OPLIST); -struct MusicPlayerWorker { +struct MusicWorker { FuriThread* thread; bool should_work; - MusicPlayerWorkerCallback callback; + MusicWorkerCallback callback; void* callback_context; float volume; @@ -42,9 +42,9 @@ struct MusicPlayerWorker { NoteBlockArray_t notes; }; -static int32_t music_player_worker_thread_callback(void* context) { +static int32_t music_worker_thread_callback(void* context) { furi_assert(context); - MusicPlayerWorker* instance = context; + MusicWorker* instance = context; NoteBlockArray_it_t it; NoteBlockArray_it(it, instance->notes); @@ -97,24 +97,24 @@ static int32_t music_player_worker_thread_callback(void* context) { return 0; } -MusicPlayerWorker* music_player_worker_alloc() { - MusicPlayerWorker* instance = malloc(sizeof(MusicPlayerWorker)); +MusicWorker* music_worker_alloc() { + MusicWorker* instance = malloc(sizeof(MusicWorker)); NoteBlockArray_init(instance->notes); - instance->thread = furi_thread_alloc_ex( - "MusicPlayerWorker", 1024, music_player_worker_thread_callback, instance); + instance->thread = + furi_thread_alloc_ex("MusicWorker", 1024, music_worker_thread_callback, instance); instance->volume = 1.0f; return instance; } -void music_player_worker_clear(MusicPlayerWorker* instance) { +void music_worker_clear(MusicWorker* instance) { NoteBlockArray_reset(instance->notes); } -void music_player_worker_free(MusicPlayerWorker* instance) { +void music_worker_free(MusicWorker* instance) { furi_assert(instance); furi_thread_free(instance->thread); NoteBlockArray_clear(instance->notes); @@ -186,11 +186,8 @@ static size_t skip_till(const char* string, const char symbol) { return ret; } -static bool music_player_worker_add_note( - MusicPlayerWorker* instance, - uint8_t semitone, - uint8_t duration, - uint8_t dots) { +static bool + music_worker_add_note(MusicWorker* instance, uint8_t semitone, uint8_t duration, uint8_t dots) { NoteBlock note_block; note_block.semitone = semitone; @@ -228,7 +225,7 @@ static int8_t note_to_semitone(const char note) { } } -static bool music_player_worker_parse_notes(MusicPlayerWorker* instance, const char* string) { +static bool music_worker_parse_notes(MusicWorker* instance, const char* string) { const char* cursor = string; bool result = true; @@ -286,7 +283,7 @@ static bool music_player_worker_parse_notes(MusicPlayerWorker* instance, const c semitone += sharp_char == '#' ? 1 : 0; } - if(music_player_worker_add_note(instance, semitone, duration, dots)) { + if(music_worker_add_note(instance, semitone, duration, dots)) { FURI_LOG_D( TAG, "Added note: %c%c%lu.%lu = %u %lu", @@ -316,20 +313,20 @@ static bool music_player_worker_parse_notes(MusicPlayerWorker* instance, const c return result; } -bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path) { +bool music_worker_load(MusicWorker* instance, const char* file_path) { furi_assert(instance); furi_assert(file_path); bool ret = false; if(strcasestr(file_path, ".fmf")) { - ret = music_player_worker_load_fmf_from_file(instance, file_path); + ret = music_worker_load_fmf_from_file(instance, file_path); } else { - ret = music_player_worker_load_rtttl_from_file(instance, file_path); + ret = music_worker_load_rtttl_from_file(instance, file_path); } return ret; } -bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path) { +bool music_worker_load_fmf_from_file(MusicWorker* instance, const char* file_path) { furi_assert(instance); furi_assert(file_path); @@ -369,7 +366,7 @@ bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const c break; } - if(!music_player_worker_parse_notes(instance, furi_string_get_cstr(temp_str))) { + if(!music_worker_parse_notes(instance, furi_string_get_cstr(temp_str))) { break; } @@ -383,7 +380,7 @@ bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const c return result; } -bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path) { +bool music_worker_load_rtttl_from_file(MusicWorker* instance, const char* file_path) { furi_assert(instance); furi_assert(file_path); @@ -414,7 +411,7 @@ bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const break; } - if(!music_player_worker_load_rtttl_from_string(instance, furi_string_get_cstr(content))) { + if(!music_worker_load_rtttl_from_string(instance, furi_string_get_cstr(content))) { FURI_LOG_E(TAG, "Invalid file content"); break; } @@ -429,7 +426,7 @@ bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const return result; } -bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string) { +bool music_worker_load_rtttl_from_string(MusicWorker* instance, const char* string) { furi_assert(instance); const char* cursor = string; @@ -470,28 +467,25 @@ bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, con return false; } cursor++; - if(!music_player_worker_parse_notes(instance, cursor)) { + if(!music_worker_parse_notes(instance, cursor)) { return false; } return true; } -void music_player_worker_set_callback( - MusicPlayerWorker* instance, - MusicPlayerWorkerCallback callback, - void* context) { +void music_worker_set_callback(MusicWorker* instance, MusicWorkerCallback callback, void* context) { furi_assert(instance); instance->callback = callback; instance->callback_context = context; } -void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume) { +void music_worker_set_volume(MusicWorker* instance, float volume) { furi_assert(instance); instance->volume = volume; } -void music_player_worker_start(MusicPlayerWorker* instance) { +void music_worker_start(MusicWorker* instance) { furi_assert(instance); furi_assert(instance->should_work == false); @@ -499,10 +493,15 @@ void music_player_worker_start(MusicPlayerWorker* instance) { furi_thread_start(instance->thread); } -void music_player_worker_stop(MusicPlayerWorker* instance) { +void music_worker_stop(MusicWorker* instance) { furi_assert(instance); furi_assert(instance->should_work == true); instance->should_work = false; furi_thread_join(instance->thread); } + +bool music_worker_is_playing(MusicWorker* instance) { + furi_assert(instance); + return instance->should_work; +} diff --git a/lib/music_worker/music_worker.h b/lib/music_worker/music_worker.h new file mode 100644 index 00000000000..5a7cb4936a9 --- /dev/null +++ b/lib/music_worker/music_worker.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +typedef void (*MusicWorkerCallback)( + uint8_t semitone, + uint8_t dots, + uint8_t duration, + float position, + void* context); + +typedef struct MusicWorker MusicWorker; + +MusicWorker* music_worker_alloc(); + +void music_worker_clear(MusicWorker* instance); + +void music_worker_free(MusicWorker* instance); + +bool music_worker_load(MusicWorker* instance, const char* file_path); + +bool music_worker_load_fmf_from_file(MusicWorker* instance, const char* file_path); + +bool music_worker_load_rtttl_from_file(MusicWorker* instance, const char* file_path); + +bool music_worker_load_rtttl_from_string(MusicWorker* instance, const char* string); + +void music_worker_set_callback(MusicWorker* instance, MusicWorkerCallback callback, void* context); + +void music_worker_set_volume(MusicWorker* instance, float volume); + +void music_worker_start(MusicWorker* instance); + +void music_worker_stop(MusicWorker* instance); + +bool music_worker_is_playing(MusicWorker* instance); diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 3a0325b71db..2c42a5157f2 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -19,6 +19,7 @@ env.Append( File("blocks/math.h"), File("subghz_setting.h"), File("subghz_protocol_registry.h"), + File("devices/cc1101_configs.h"), ], ) diff --git a/lib/subghz/devices/cc1101_configs.c b/lib/subghz/devices/cc1101_configs.c new file mode 100644 index 00000000000..35ddccd54f6 --- /dev/null +++ b/lib/subghz/devices/cc1101_configs.c @@ -0,0 +1,431 @@ +#include "cc1101_configs.h" +#include + +const uint8_t subghz_device_cc1101_preset_ook_270khz_async_regs[] = { + // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration + + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x0D, // GD0 as async serial data output/input + + /* FIFO and internals */ + CC1101_FIFOTHR, + 0x47, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32 + + /* Packet engine */ + CC1101_PKTCTRL0, + 0x32, // Async, continious, no whitening + + /* Frequency Synthesizer Control */ + CC1101_FSCTRL1, + 0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + // Modem Configuration + CC1101_MDMCFG0, + 0x00, // Channel spacing is 25kHz + CC1101_MDMCFG1, + 0x00, // Channel spacing is 25kHz + CC1101_MDMCFG2, + 0x30, // Format ASK/OOK, No preamble/sync + CC1101_MDMCFG3, + 0x32, // Data rate is 3.79372 kBaud + CC1101_MDMCFG4, + 0x67, // Rx BW filter is 270.833333kHz + + /* Main Radio Control State Machine */ + CC1101_MCSM0, + 0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + CC1101_FOCCFG, + 0x18, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + CC1101_AGCCTRL0, + 0x40, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary + CC1101_AGCCTRL1, + 0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + CC1101_AGCCTRL2, + 0x03, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB + + /* Wake on radio and timeouts control */ + CC1101_WORCTRL, + 0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + CC1101_FREND0, + 0x11, // Adjusts current TX LO buffer + high is PATABLE[1] + CC1101_FREND1, + 0xB6, // + + /* End load reg */ + 0, + 0, + + //ook_async_patable[8] + 0x00, + 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_ook_650khz_async_regs[] = { + // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration + + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x0D, // GD0 as async serial data output/input + + /* FIFO and internals */ + CC1101_FIFOTHR, + 0x07, // The only important bit is ADC_RETENTION + + /* Packet engine */ + CC1101_PKTCTRL0, + 0x32, // Async, continious, no whitening + + /* Frequency Synthesizer Control */ + CC1101_FSCTRL1, + 0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + // Modem Configuration + CC1101_MDMCFG0, + 0x00, // Channel spacing is 25kHz + CC1101_MDMCFG1, + 0x00, // Channel spacing is 25kHz + CC1101_MDMCFG2, + 0x30, // Format ASK/OOK, No preamble/sync + CC1101_MDMCFG3, + 0x32, // Data rate is 3.79372 kBaud + CC1101_MDMCFG4, + 0x17, // Rx BW filter is 650.000kHz + + /* Main Radio Control State Machine */ + CC1101_MCSM0, + 0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + CC1101_FOCCFG, + 0x18, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + // CC1101_AGCTRL0,0x40, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary + // CC1101_AGCTRL1,0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + // CC1101_AGCCTRL2, 0x03, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB + //MAGN_TARGET for RX filter BW =< 100 kHz is 0x3. For higher RX filter BW's MAGN_TARGET is 0x7. + CC1101_AGCCTRL0, + 0x91, // 10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary + CC1101_AGCCTRL1, + 0x0, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + CC1101_AGCCTRL2, + 0x07, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB + + /* Wake on radio and timeouts control */ + CC1101_WORCTRL, + 0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + CC1101_FREND0, + 0x11, // Adjusts current TX LO buffer + high is PATABLE[1] + CC1101_FREND1, + 0xB6, // + + /* End load reg */ + 0, + 0, + + //ook_async_patable[8] + 0x00, + 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs[] = { + + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x0D, // GD0 as async serial data output/input + + /* Frequency Synthesizer Control */ + CC1101_FSCTRL1, + 0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + /* Packet engine */ + CC1101_PKTCTRL0, + 0x32, // Async, continious, no whitening + CC1101_PKTCTRL1, + 0x04, + + // // Modem Configuration + CC1101_MDMCFG0, + 0x00, + CC1101_MDMCFG1, + 0x02, + CC1101_MDMCFG2, + 0x04, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) + CC1101_MDMCFG3, + 0x83, // Data rate is 4.79794 kBaud + CC1101_MDMCFG4, + 0x67, //Rx BW filter is 270.833333 kHz + CC1101_DEVIATN, + 0x04, //Deviation 2.380371 kHz + + /* Main Radio Control State Machine */ + CC1101_MCSM0, + 0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + CC1101_FOCCFG, + 0x16, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + CC1101_AGCCTRL0, + 0x91, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary + CC1101_AGCCTRL1, + 0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + CC1101_AGCCTRL2, + 0x07, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB + + /* Wake on radio and timeouts control */ + CC1101_WORCTRL, + 0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + CC1101_FREND0, + 0x10, // Adjusts current TX LO buffer + CC1101_FREND1, + 0x56, + + /* End load reg */ + 0, + 0, + + // 2fsk_async_patable[8] + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs[] = { + + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x0D, // GD0 as async serial data output/input + + /* Frequency Synthesizer Control */ + CC1101_FSCTRL1, + 0x06, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz + + /* Packet engine */ + CC1101_PKTCTRL0, + 0x32, // Async, continious, no whitening + CC1101_PKTCTRL1, + 0x04, + + // // Modem Configuration + CC1101_MDMCFG0, + 0x00, + CC1101_MDMCFG1, + 0x02, + CC1101_MDMCFG2, + 0x04, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized) + CC1101_MDMCFG3, + 0x83, // Data rate is 4.79794 kBaud + CC1101_MDMCFG4, + 0x67, //Rx BW filter is 270.833333 kHz + CC1101_DEVIATN, + 0x47, //Deviation 47.60742 kHz + + /* Main Radio Control State Machine */ + CC1101_MCSM0, + 0x18, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us) + + /* Frequency Offset Compensation Configuration */ + CC1101_FOCCFG, + 0x16, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off + + /* Automatic Gain Control */ + CC1101_AGCCTRL0, + 0x91, //10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary + CC1101_AGCCTRL1, + 0x00, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET + CC1101_AGCCTRL2, + 0x07, // 00 - DVGA all; 000 - MAX LNA+LNA2; 111 - MAIN_TARGET 42 dB + + /* Wake on radio and timeouts control */ + CC1101_WORCTRL, + 0xFB, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours + + /* Frontend configuration */ + CC1101_FREND0, + 0x10, // Adjusts current TX LO buffer + CC1101_FREND1, + 0x56, + + /* End load reg */ + 0, + 0, + + // 2fsk_async_patable[8] + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_msk_99_97kb_async_regs[] = { + /* GPIO GD0 */ + CC1101_IOCFG0, + 0x06, + + CC1101_FIFOTHR, + 0x07, // The only important bit is ADC_RETENTION + CC1101_SYNC1, + 0x46, + CC1101_SYNC0, + 0x4C, + CC1101_ADDR, + 0x00, + CC1101_PKTLEN, + 0x00, + CC1101_CHANNR, + 0x00, + + CC1101_PKTCTRL0, + 0x05, + + CC1101_FSCTRL0, + 0x23, + CC1101_FSCTRL1, + 0x06, + + CC1101_MDMCFG0, + 0xF8, + CC1101_MDMCFG1, + 0x22, + CC1101_MDMCFG2, + 0x72, + CC1101_MDMCFG3, + 0xF8, + CC1101_MDMCFG4, + 0x5B, + CC1101_DEVIATN, + 0x47, + + CC1101_MCSM0, + 0x18, + CC1101_FOCCFG, + 0x16, + + CC1101_AGCCTRL0, + 0xB2, + CC1101_AGCCTRL1, + 0x00, + CC1101_AGCCTRL2, + 0xC7, + + CC1101_FREND0, + 0x10, + CC1101_FREND1, + 0x56, + + CC1101_BSCFG, + 0x1C, + CC1101_FSTEST, + 0x59, + + /* End load reg */ + 0, + 0, + + // msk_async_patable[8] + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +const uint8_t subghz_device_cc1101_preset_gfsk_9_99kb_async_regs[] = { + + CC1101_IOCFG0, + 0x06, //GDO0 Output Pin Configuration + CC1101_FIFOTHR, + 0x47, //RX FIFO and TX FIFO Thresholds + + //1 : CRC calculation in TX and CRC check in RX enabled, + //1 : Variable packet length mode. Packet length configured by the first byte after sync word + CC1101_PKTCTRL0, + 0x05, + + CC1101_FSCTRL1, + 0x06, //Frequency Synthesizer Control + + CC1101_SYNC1, + 0x46, + CC1101_SYNC0, + 0x4C, + CC1101_ADDR, + 0x00, + CC1101_PKTLEN, + 0x00, + + CC1101_MDMCFG4, + 0xC8, //Modem Configuration 9.99 + CC1101_MDMCFG3, + 0x93, //Modem Configuration + CC1101_MDMCFG2, + 0x12, // 2: 16/16 sync word bits detected + + CC1101_DEVIATN, + 0x34, //Deviation = 19.042969 + CC1101_MCSM0, + 0x18, //Main Radio Control State Machine Configuration + CC1101_FOCCFG, + 0x16, //Frequency Offset Compensation Configuration + + CC1101_AGCCTRL2, + 0x43, //AGC Control + CC1101_AGCCTRL1, + 0x40, + CC1101_AGCCTRL0, + 0x91, + + CC1101_WORCTRL, + 0xFB, //Wake On Radio Control + + /* End load reg */ + 0, + 0, + + // gfsk_async_patable[8] + 0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12 + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; diff --git a/lib/subghz/devices/cc1101_configs.h b/lib/subghz/devices/cc1101_configs.h new file mode 100644 index 00000000000..eecab01d999 --- /dev/null +++ b/lib/subghz/devices/cc1101_configs.h @@ -0,0 +1,18 @@ +#pragma once +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const uint8_t subghz_device_cc1101_preset_ook_270khz_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_ook_650khz_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_msk_99_97kb_async_regs[]; +extern const uint8_t subghz_device_cc1101_preset_gfsk_9_99kb_async_regs[]; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c new file mode 100644 index 00000000000..41a0609df00 --- /dev/null +++ b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.c @@ -0,0 +1,96 @@ +#include "cc1101_int_interconnect.h" +#include +#include "../cc1101_configs.h" + +#define TAG "SubGhzDeviceCC1101Int" + +static bool subghz_device_cc1101_int_interconnect_is_frequency_valid(uint32_t frequency) { + bool ret = furi_hal_subghz_is_frequency_valid(frequency); + if(!ret) { + furi_crash("SubGhz: Incorrect frequency."); + } + return ret; +} + +static uint32_t subghz_device_cc1101_int_interconnect_set_frequency(uint32_t frequency) { + subghz_device_cc1101_int_interconnect_is_frequency_valid(frequency); + return furi_hal_subghz_set_frequency_and_path(frequency); +} + +static bool subghz_device_cc1101_int_interconnect_start_async_tx(void* callback, void* context) { + return furi_hal_subghz_start_async_tx((FuriHalSubGhzAsyncTxCallback)callback, context); +} + +static void subghz_device_cc1101_int_interconnect_start_async_rx(void* callback, void* context) { + furi_hal_subghz_start_async_rx((FuriHalSubGhzCaptureCallback)callback, context); +} + +static void subghz_device_cc1101_int_interconnect_load_preset( + FuriHalSubGhzPreset preset, + uint8_t* preset_data) { + switch(preset) { + case FuriHalSubGhzPresetOok650Async: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_650khz_async_regs); + break; + case FuriHalSubGhzPresetOok270Async: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_ook_270khz_async_regs); + break; + case FuriHalSubGhzPreset2FSKDev238Async: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs); + break; + case FuriHalSubGhzPreset2FSKDev476Async: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs); + break; + case FuriHalSubGhzPresetMSK99_97KbAsync: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_msk_99_97kb_async_regs); + break; + case FuriHalSubGhzPresetGFSK9_99KbAsync: + furi_hal_subghz_load_custom_preset(subghz_device_cc1101_preset_gfsk_9_99kb_async_regs); + break; + + default: + furi_hal_subghz_load_custom_preset(preset_data); + } +} + +static bool subghz_device_cc1101_int_interconnect_is_connect(void) { + return true; +} + +const SubGhzDeviceInterconnect subghz_device_cc1101_int_interconnect = { + .begin = NULL, + .end = furi_hal_subghz_shutdown, + .is_connect = subghz_device_cc1101_int_interconnect_is_connect, + .reset = furi_hal_subghz_reset, + .sleep = furi_hal_subghz_sleep, + .idle = furi_hal_subghz_idle, + .load_preset = subghz_device_cc1101_int_interconnect_load_preset, + .set_frequency = subghz_device_cc1101_int_interconnect_set_frequency, + .is_frequency_valid = furi_hal_subghz_is_frequency_valid, + .set_async_mirror_pin = furi_hal_subghz_set_async_mirror_pin, + .get_data_gpio = furi_hal_subghz_get_data_gpio, + + .set_tx = furi_hal_subghz_tx, + .flush_tx = furi_hal_subghz_flush_tx, + .start_async_tx = subghz_device_cc1101_int_interconnect_start_async_tx, + .is_async_complete_tx = furi_hal_subghz_is_async_tx_complete, + .stop_async_tx = furi_hal_subghz_stop_async_tx, + + .set_rx = furi_hal_subghz_rx, + .flush_rx = furi_hal_subghz_flush_rx, + .start_async_rx = subghz_device_cc1101_int_interconnect_start_async_rx, + .stop_async_rx = furi_hal_subghz_stop_async_rx, + + .get_rssi = furi_hal_subghz_get_rssi, + .get_lqi = furi_hal_subghz_get_lqi, + + .rx_pipe_not_empty = furi_hal_subghz_rx_pipe_not_empty, + .is_rx_data_crc_valid = furi_hal_subghz_is_rx_data_crc_valid, + .read_packet = furi_hal_subghz_read_packet, + .write_packet = furi_hal_subghz_write_packet, +}; + +const SubGhzDevice subghz_device_cc1101_int = { + .name = SUBGHZ_DEVICE_CC1101_INT_NAME, + .interconnect = &subghz_device_cc1101_int_interconnect, +}; diff --git a/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h new file mode 100644 index 00000000000..629d1264c09 --- /dev/null +++ b/lib/subghz/devices/cc1101_int/cc1101_int_interconnect.h @@ -0,0 +1,8 @@ +#pragma once +#include "../types.h" + +#define SUBGHZ_DEVICE_CC1101_INT_NAME "cc1101_int" + +typedef struct SubGhzDeviceCC1101Int SubGhzDeviceCC1101Int; + +extern const SubGhzDevice subghz_device_cc1101_int; diff --git a/lib/subghz/devices/device_registry.h b/lib/subghz/devices/device_registry.h new file mode 100644 index 00000000000..70a0db4b265 --- /dev/null +++ b/lib/subghz/devices/device_registry.h @@ -0,0 +1,13 @@ +#pragma once + +#include "registry.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const SubGhzDeviceRegistry subghz_device_registry; + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/devices/devices.c b/lib/subghz/devices/devices.c new file mode 100644 index 00000000000..55db61e1188 --- /dev/null +++ b/lib/subghz/devices/devices.c @@ -0,0 +1,236 @@ +#include "devices.h" + +#include "registry.h" + +void subghz_devices_init() { + furi_check(!subghz_device_registry_is_valid()); + subghz_device_registry_init(); +} + +void subghz_devices_deinit(void) { + furi_check(subghz_device_registry_is_valid()); + subghz_device_registry_deinit(); +} + +const SubGhzDevice* subghz_devices_get_by_name(const char* device_name) { + furi_check(subghz_device_registry_is_valid()); + const SubGhzDevice* device = subghz_device_registry_get_by_name(device_name); + return device; +} + +const char* subghz_devices_get_name(const SubGhzDevice* device) { + const char* ret = NULL; + if(device) { + ret = device->name; + } + return ret; +} + +bool subghz_devices_begin(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->begin) { + ret = device->interconnect->begin(); + } + return ret; +} + +void subghz_devices_end(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->end) { + device->interconnect->end(); + } +} + +bool subghz_devices_is_connect(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->is_connect) { + ret = device->interconnect->is_connect(); + } + return ret; +} + +void subghz_devices_reset(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->reset) { + device->interconnect->reset(); + } +} + +void subghz_devices_sleep(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->sleep) { + device->interconnect->sleep(); + } +} + +void subghz_devices_idle(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->idle) { + device->interconnect->idle(); + } +} + +void subghz_devices_load_preset( + const SubGhzDevice* device, + FuriHalSubGhzPreset preset, + uint8_t* preset_data) { + furi_assert(device); + if(device->interconnect->load_preset) { + device->interconnect->load_preset(preset, preset_data); + } +} + +uint32_t subghz_devices_set_frequency(const SubGhzDevice* device, uint32_t frequency) { + uint32_t ret = 0; + furi_assert(device); + if(device->interconnect->set_frequency) { + ret = device->interconnect->set_frequency(frequency); + } + return ret; +} + +bool subghz_devices_is_frequency_valid(const SubGhzDevice* device, uint32_t frequency) { + bool ret = false; + furi_assert(device); + if(device->interconnect->is_frequency_valid) { + ret = device->interconnect->is_frequency_valid(frequency); + } + return ret; +} + +void subghz_devices_set_async_mirror_pin(const SubGhzDevice* device, const GpioPin* gpio) { + furi_assert(device); + if(device->interconnect->set_async_mirror_pin) { + device->interconnect->set_async_mirror_pin(gpio); + } +} + +const GpioPin* subghz_devices_get_data_gpio(const SubGhzDevice* device) { + const GpioPin* ret = NULL; + furi_assert(device); + if(device->interconnect->get_data_gpio) { + ret = device->interconnect->get_data_gpio(); + } + return ret; +} + +bool subghz_devices_set_tx(const SubGhzDevice* device) { + bool ret = 0; + furi_assert(device); + if(device->interconnect->set_tx) { + ret = device->interconnect->set_tx(); + } + return ret; +} + +void subghz_devices_flush_tx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->flush_tx) { + device->interconnect->flush_tx(); + } +} + +bool subghz_devices_start_async_tx(const SubGhzDevice* device, void* callback, void* context) { + bool ret = false; + furi_assert(device); + if(device->interconnect->start_async_tx) { + ret = device->interconnect->start_async_tx(callback, context); + } + return ret; +} + +bool subghz_devices_is_async_complete_tx(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->is_async_complete_tx) { + ret = device->interconnect->is_async_complete_tx(); + } + return ret; +} + +void subghz_devices_stop_async_tx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->stop_async_tx) { + device->interconnect->stop_async_tx(); + } +} + +void subghz_devices_set_rx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->set_rx) { + device->interconnect->set_rx(); + } +} + +void subghz_devices_flush_rx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->flush_rx) { + device->interconnect->flush_rx(); + } +} + +void subghz_devices_start_async_rx(const SubGhzDevice* device, void* callback, void* context) { + furi_assert(device); + if(device->interconnect->start_async_rx) { + device->interconnect->start_async_rx(callback, context); + } +} + +void subghz_devices_stop_async_rx(const SubGhzDevice* device) { + furi_assert(device); + if(device->interconnect->stop_async_rx) { + device->interconnect->stop_async_rx(); + } +} + +float subghz_devices_get_rssi(const SubGhzDevice* device) { + float ret = 0; + furi_assert(device); + if(device->interconnect->get_rssi) { + ret = device->interconnect->get_rssi(); + } + return ret; +} + +uint8_t subghz_devices_get_lqi(const SubGhzDevice* device) { + uint8_t ret = 0; + furi_assert(device); + if(device->interconnect->get_lqi) { + ret = device->interconnect->get_lqi(); + } + return ret; +} + +bool subghz_devices_rx_pipe_not_empty(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->rx_pipe_not_empty) { + ret = device->interconnect->rx_pipe_not_empty(); + } + return ret; +} + +bool subghz_devices_is_rx_data_crc_valid(const SubGhzDevice* device) { + bool ret = false; + furi_assert(device); + if(device->interconnect->is_rx_data_crc_valid) { + ret = device->interconnect->is_rx_data_crc_valid(); + } + return ret; +} + +void subghz_devices_read_packet(const SubGhzDevice* device, uint8_t* data, uint8_t* size) { + furi_assert(device); + if(device->interconnect->read_packet) { + device->interconnect->read_packet(data, size); + } +} + +void subghz_devices_write_packet(const SubGhzDevice* device, const uint8_t* data, uint8_t size) { + furi_assert(device); + if(device->interconnect->write_packet) { + device->interconnect->write_packet(data, size); + } +} diff --git a/lib/subghz/devices/devices.h b/lib/subghz/devices/devices.h new file mode 100644 index 00000000000..dad3c9aeb53 --- /dev/null +++ b/lib/subghz/devices/devices.h @@ -0,0 +1,52 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SubGhzDevice SubGhzDevice; + +void subghz_devices_init(); +void subghz_devices_deinit(void); + +const SubGhzDevice* subghz_devices_get_by_name(const char* device_name); +const char* subghz_devices_get_name(const SubGhzDevice* device); +bool subghz_devices_begin(const SubGhzDevice* device); +void subghz_devices_end(const SubGhzDevice* device); +bool subghz_devices_is_connect(const SubGhzDevice* device); +void subghz_devices_reset(const SubGhzDevice* device); +void subghz_devices_sleep(const SubGhzDevice* device); +void subghz_devices_idle(const SubGhzDevice* device); +void subghz_devices_load_preset( + const SubGhzDevice* device, + FuriHalSubGhzPreset preset, + uint8_t* preset_data); +uint32_t subghz_devices_set_frequency(const SubGhzDevice* device, uint32_t frequency); +bool subghz_devices_is_frequency_valid(const SubGhzDevice* device, uint32_t frequency); +void subghz_devices_set_async_mirror_pin(const SubGhzDevice* device, const GpioPin* gpio); +const GpioPin* subghz_devices_get_data_gpio(const SubGhzDevice* device); + +bool subghz_devices_set_tx(const SubGhzDevice* device); +void subghz_devices_flush_tx(const SubGhzDevice* device); +bool subghz_devices_start_async_tx(const SubGhzDevice* device, void* callback, void* context); +bool subghz_devices_is_async_complete_tx(const SubGhzDevice* device); +void subghz_devices_stop_async_tx(const SubGhzDevice* device); + +void subghz_devices_set_rx(const SubGhzDevice* device); +void subghz_devices_flush_rx(const SubGhzDevice* device); +void subghz_devices_start_async_rx(const SubGhzDevice* device, void* callback, void* context); +void subghz_devices_stop_async_rx(const SubGhzDevice* device); + +float subghz_devices_get_rssi(const SubGhzDevice* device); +uint8_t subghz_devices_get_lqi(const SubGhzDevice* device); + +bool subghz_devices_rx_pipe_not_empty(const SubGhzDevice* device); +bool subghz_devices_is_rx_data_crc_valid(const SubGhzDevice* device); +void subghz_devices_read_packet(const SubGhzDevice* device, uint8_t* data, uint8_t* size); +void subghz_devices_write_packet(const SubGhzDevice* device, const uint8_t* data, uint8_t size); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/devices/preset.h b/lib/subghz/devices/preset.h new file mode 100644 index 00000000000..8716f2e233c --- /dev/null +++ b/lib/subghz/devices/preset.h @@ -0,0 +1,13 @@ +#pragma once + +/** Radio Presets */ +typedef enum { + FuriHalSubGhzPresetIDLE, /**< default configuration */ + FuriHalSubGhzPresetOok270Async, /**< OOK, bandwidth 270kHz, asynchronous */ + FuriHalSubGhzPresetOok650Async, /**< OOK, bandwidth 650kHz, asynchronous */ + FuriHalSubGhzPreset2FSKDev238Async, /**< FM, deviation 2.380371 kHz, asynchronous */ + FuriHalSubGhzPreset2FSKDev476Async, /**< FM, deviation 47.60742 kHz, asynchronous */ + FuriHalSubGhzPresetMSK99_97KbAsync, /**< MSK, deviation 47.60742 kHz, 99.97Kb/s, asynchronous */ + FuriHalSubGhzPresetGFSK9_99KbAsync, /**< GFSK, deviation 19.042969 kHz, 9.996Kb/s, asynchronous */ + FuriHalSubGhzPresetCustom, /**Custom Preset*/ +} FuriHalSubGhzPreset; diff --git a/lib/subghz/devices/registry.c b/lib/subghz/devices/registry.c new file mode 100644 index 00000000000..c0d5bb292dc --- /dev/null +++ b/lib/subghz/devices/registry.c @@ -0,0 +1,76 @@ +#include "registry.h" + +#include "cc1101_int/cc1101_int_interconnect.h" +#include +#include + +#define TAG "SubGhzDeviceRegistry" + +struct SubGhzDeviceRegistry { + const SubGhzDevice** items; + size_t size; + PluginManager* manager; +}; + +static SubGhzDeviceRegistry* subghz_device_registry = NULL; + +void subghz_device_registry_init(void) { + SubGhzDeviceRegistry* subghz_device = + (SubGhzDeviceRegistry*)malloc(sizeof(SubGhzDeviceRegistry)); + subghz_device->manager = plugin_manager_alloc( + SUBGHZ_RADIO_DEVICE_PLUGIN_APP_ID, + SUBGHZ_RADIO_DEVICE_PLUGIN_API_VERSION, + firmware_api_interface); + + //ToDo: fix path to plugins + if(plugin_manager_load_all(subghz_device->manager, "/any/apps_data/subghz/plugins") != + //if(plugin_manager_load_all(subghz_device->manager, APP_DATA_PATH("plugins")) != + PluginManagerErrorNone) { + FURI_LOG_E(TAG, "Failed to load all libs"); + } + + subghz_device->size = plugin_manager_get_count(subghz_device->manager) + 1; + subghz_device->items = + (const SubGhzDevice**)malloc(sizeof(SubGhzDevice*) * subghz_device->size); + subghz_device->items[0] = &subghz_device_cc1101_int; + for(uint32_t i = 1; i < subghz_device->size; i++) { + const SubGhzDevice* plugin = plugin_manager_get_ep(subghz_device->manager, i - 1); + subghz_device->items[i] = plugin; + } + + FURI_LOG_I(TAG, "Loaded %zu radio device", subghz_device->size); + subghz_device_registry = subghz_device; +} + +void subghz_device_registry_deinit(void) { + plugin_manager_free(subghz_device_registry->manager); + free(subghz_device_registry->items); + free(subghz_device_registry); + subghz_device_registry = NULL; +} + +bool subghz_device_registry_is_valid(void) { + return subghz_device_registry != NULL; +} + +const SubGhzDevice* subghz_device_registry_get_by_name(const char* name) { + furi_assert(subghz_device_registry); + + if(name != NULL) { + for(size_t i = 0; i < subghz_device_registry->size; i++) { + if(strcmp(name, subghz_device_registry->items[i]->name) == 0) { + return subghz_device_registry->items[i]; + } + } + } + return NULL; +} + +const SubGhzDevice* subghz_device_registry_get_by_index(size_t index) { + furi_assert(subghz_device_registry); + if(index < subghz_device_registry->size) { + return subghz_device_registry->items[index]; + } else { + return NULL; + } +} diff --git a/lib/subghz/devices/registry.h b/lib/subghz/devices/registry.h new file mode 100644 index 00000000000..5200589205b --- /dev/null +++ b/lib/subghz/devices/registry.h @@ -0,0 +1,40 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SubGhzDevice SubGhzDevice; + +void subghz_device_registry_init(void); + +void subghz_device_registry_deinit(void); + +bool subghz_device_registry_is_valid(void); + +/** + * Registration by name SubGhzDevice. + * @param name SubGhzDevice name + * @return SubGhzDevice* pointer to a SubGhzDevice instance + */ +const SubGhzDevice* subghz_device_registry_get_by_name(const char* name); + +/** + * Registration subghzdevice by index in array SubGhzDevice. + * @param index SubGhzDevice by index in array + * @return SubGhzDevice* pointer to a SubGhzDevice instance + */ +const SubGhzDevice* subghz_device_registry_get_by_index(size_t index); + +/** + * Getting the number of registered subghzdevices. + * @param subghz_device SubGhzDeviceRegistry + * @return Number of subghzdevices + */ +size_t subghz_device_registry_count(void); + +#ifdef __cplusplus +} +#endif diff --git a/lib/subghz/devices/types.h b/lib/subghz/devices/types.h new file mode 100644 index 00000000000..8a41984263f --- /dev/null +++ b/lib/subghz/devices/types.h @@ -0,0 +1,91 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include "preset.h" + +#include + +#define SUBGHZ_RADIO_DEVICE_PLUGIN_APP_ID "subghz_radio_device" +#define SUBGHZ_RADIO_DEVICE_PLUGIN_API_VERSION 1 + +typedef struct SubGhzDeviceRegistry SubGhzDeviceRegistry; +typedef struct SubGhzDevice SubGhzDevice; + +typedef bool (*SubGhzBegin)(void); +typedef void (*SubGhzEnd)(void); +typedef bool (*SubGhzIsConnect)(void); +typedef void (*SubGhzReset)(void); +typedef void (*SubGhzSleep)(void); +typedef void (*SubGhzIdle)(void); +typedef void (*SubGhzLoadPreset)(FuriHalSubGhzPreset preset, uint8_t* preset_data); +typedef uint32_t (*SubGhzSetFrequency)(uint32_t frequency); +typedef bool (*SubGhzIsFrequencyValid)(uint32_t frequency); + +typedef void (*SubGhzSetAsyncMirrorPin)(const GpioPin* gpio); +typedef const GpioPin* (*SubGhzGetDataGpio)(void); + +typedef bool (*SubGhzSetTx)(void); +typedef void (*SubGhzFlushTx)(void); +typedef bool (*SubGhzStartAsyncTx)(void* callback, void* context); +typedef bool (*SubGhzIsAsyncCompleteTx)(void); +typedef void (*SubGhzStopAsyncTx)(void); + +typedef void (*SubGhzSetRx)(void); +typedef void (*SubGhzFlushRx)(void); +typedef void (*SubGhzStartAsyncRx)(void* callback, void* context); +typedef void (*SubGhzStopAsyncRx)(void); + +typedef float (*SubGhzGetRSSI)(void); +typedef uint8_t (*SubGhzGetLQI)(void); + +typedef bool (*SubGhzRxPipeNotEmpty)(void); +typedef bool (*SubGhzRxIsDataCrcValid)(void); +typedef void (*SubGhzReadPacket)(uint8_t* data, uint8_t* size); +typedef void (*SubGhzWritePacket)(const uint8_t* data, uint8_t size); + +typedef struct { + SubGhzBegin begin; + SubGhzEnd end; + + SubGhzIsConnect is_connect; + SubGhzReset reset; + SubGhzSleep sleep; + SubGhzIdle idle; + + SubGhzLoadPreset load_preset; + SubGhzSetFrequency set_frequency; + SubGhzIsFrequencyValid is_frequency_valid; + SubGhzSetAsyncMirrorPin set_async_mirror_pin; + SubGhzGetDataGpio get_data_gpio; + + SubGhzSetTx set_tx; + SubGhzFlushTx flush_tx; + SubGhzStartAsyncTx start_async_tx; + SubGhzIsAsyncCompleteTx is_async_complete_tx; + SubGhzStopAsyncTx stop_async_tx; + + SubGhzSetRx set_rx; + SubGhzFlushRx flush_rx; + SubGhzStartAsyncRx start_async_rx; + SubGhzStopAsyncRx stop_async_rx; + + SubGhzGetRSSI get_rssi; + SubGhzGetLQI get_lqi; + + SubGhzRxPipeNotEmpty rx_pipe_not_empty; + SubGhzRxIsDataCrcValid is_rx_data_crc_valid; + SubGhzReadPacket read_packet; + SubGhzWritePacket write_packet; + +} SubGhzDeviceInterconnect; + +struct SubGhzDevice { + const char* name; + const SubGhzDeviceInterconnect* interconnect; +}; diff --git a/lib/subghz/protocols/raw.c b/lib/subghz/protocols/raw.c index 66358698ac9..1288c957371 100644 --- a/lib/subghz/protocols/raw.c +++ b/lib/subghz/protocols/raw.c @@ -40,6 +40,7 @@ struct SubGhzProtocolEncoderRAW { bool is_running; FuriString* file_name; + FuriString* radio_device_name; SubGhzFileEncoderWorker* file_worker_encoder; }; @@ -282,6 +283,7 @@ void* subghz_protocol_encoder_raw_alloc(SubGhzEnvironment* environment) { instance->base.protocol = &subghz_protocol_raw; instance->file_name = furi_string_alloc(); + instance->radio_device_name = furi_string_alloc(); instance->is_running = false; return instance; } @@ -300,6 +302,7 @@ void subghz_protocol_encoder_raw_free(void* context) { SubGhzProtocolEncoderRAW* instance = context; subghz_protocol_encoder_raw_stop(instance); furi_string_free(instance->file_name); + furi_string_free(instance->radio_device_name); free(instance); } @@ -318,7 +321,9 @@ static bool subghz_protocol_encoder_raw_worker_init(SubGhzProtocolEncoderRAW* in instance->file_worker_encoder = subghz_file_encoder_worker_alloc(); if(subghz_file_encoder_worker_start( - instance->file_worker_encoder, furi_string_get_cstr(instance->file_name))) { + instance->file_worker_encoder, + furi_string_get_cstr(instance->file_name), + furi_string_get_cstr(instance->radio_device_name))) { //the worker needs a file in order to open and read part of the file furi_delay_ms(100); instance->is_running = true; @@ -328,7 +333,10 @@ static bool subghz_protocol_encoder_raw_worker_init(SubGhzProtocolEncoderRAW* in return instance->is_running; } -void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_path) { +void subghz_protocol_raw_gen_fff_data( + FlipperFormat* flipper_format, + const char* file_path, + const char* radio_device_name) { do { stream_clean(flipper_format_get_raw_stream(flipper_format)); if(!flipper_format_write_string_cstr(flipper_format, "Protocol", "RAW")) { @@ -340,6 +348,12 @@ void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* FURI_LOG_E(TAG, "Unable to add File_name"); break; } + + if(!flipper_format_write_string_cstr( + flipper_format, "Radio_device_name", radio_device_name)) { + FURI_LOG_E(TAG, "Unable to add Radio_device_name"); + break; + } } while(false); } @@ -364,6 +378,13 @@ SubGhzProtocolStatus } furi_string_set(instance->file_name, temp_str); + if(!flipper_format_read_string(flipper_format, "Radio_device_name", temp_str)) { + FURI_LOG_E(TAG, "Missing Radio_device_name"); + res = SubGhzProtocolStatusErrorParserOthers; + break; + } + furi_string_set(instance->radio_device_name, temp_str); + if(!subghz_protocol_encoder_raw_worker_init(instance)) { res = SubGhzProtocolStatusErrorEncoderGetUpload; break; diff --git a/lib/subghz/protocols/raw.h b/lib/subghz/protocols/raw.h index 4f67a4e2f24..6d791bb3663 100644 --- a/lib/subghz/protocols/raw.h +++ b/lib/subghz/protocols/raw.h @@ -126,8 +126,12 @@ void subghz_protocol_raw_file_encoder_worker_set_callback_end( * File generation for RAW work. * @param flipper_format Pointer to a FlipperFormat instance * @param file_path File path + * @param radio_dev_name Radio device name */ -void subghz_protocol_raw_gen_fff_data(FlipperFormat* flipper_format, const char* file_path); +void subghz_protocol_raw_gen_fff_data( + FlipperFormat* flipper_format, + const char* file_path, + const char* radio_dev_name); /** * Deserialize and generating an upload to send. diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index 5c4d36f78e8..519ff3fdcc3 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -3,6 +3,7 @@ #include #include #include +#include #define TAG "SubGhzFileEncoderWorker" @@ -21,6 +22,7 @@ struct SubGhzFileEncoderWorker { bool is_storage_slow; FuriString* str_data; FuriString* file_path; + const SubGhzDevice* device; SubGhzFileEncoderWorkerCallbackEnd callback_end; void* context_end; @@ -156,10 +158,13 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { if(instance->is_storage_slow) { FURI_LOG_E(TAG, "Storage is slow"); } + FURI_LOG_I(TAG, "End read file"); - while(!furi_hal_subghz_is_async_tx_complete() && instance->worker_running) { + while(instance->device && !subghz_devices_is_async_complete_tx(instance->device) && + instance->worker_running) { furi_delay_ms(5); } + FURI_LOG_I(TAG, "End transmission"); while(instance->worker_running) { if(instance->worker_stoping) { @@ -206,12 +211,16 @@ void subghz_file_encoder_worker_free(SubGhzFileEncoderWorker* instance) { free(instance); } -bool subghz_file_encoder_worker_start(SubGhzFileEncoderWorker* instance, const char* file_path) { +bool subghz_file_encoder_worker_start( + SubGhzFileEncoderWorker* instance, + const char* file_path, + const char* radio_device_name) { furi_assert(instance); furi_assert(!instance->worker_running); furi_stream_buffer_reset(instance->stream); furi_string_set(instance->file_path, file_path); + instance->device = subghz_devices_get_by_name(radio_device_name); instance->worker_running = true; furi_thread_start(instance->thread); diff --git a/lib/subghz/subghz_file_encoder_worker.h b/lib/subghz/subghz_file_encoder_worker.h index a87be5cd6f3..e66c66d76ea 100644 --- a/lib/subghz/subghz_file_encoder_worker.h +++ b/lib/subghz/subghz_file_encoder_worker.h @@ -38,9 +38,14 @@ LevelDuration subghz_file_encoder_worker_get_level_duration(void* context); /** * Start SubGhzFileEncoderWorker. * @param instance Pointer to a SubGhzFileEncoderWorker instance + * @param file_path File path + * @param radio_device_name Radio device name * @return bool - true if ok */ -bool subghz_file_encoder_worker_start(SubGhzFileEncoderWorker* instance, const char* file_path); +bool subghz_file_encoder_worker_start( + SubGhzFileEncoderWorker* instance, + const char* file_path, + const char* radio_device_name); /** * Stop SubGhzFileEncoderWorker diff --git a/lib/subghz/subghz_setting.c b/lib/subghz/subghz_setting.c index 656580043f0..9804f827733 100644 --- a/lib/subghz/subghz_setting.c +++ b/lib/subghz/subghz_setting.c @@ -4,7 +4,7 @@ #include #include -#include +#include #define TAG "SubGhzSetting" @@ -218,8 +218,7 @@ void subghz_setting_free(SubGhzSetting* instance) { static void subghz_setting_load_default_preset( SubGhzSetting* instance, const char* preset_name, - const uint8_t* preset_data, - const uint8_t preset_pa_table[8]) { + const uint8_t* preset_data) { furi_assert(instance); furi_assert(preset_data); uint32_t preset_data_count = 0; @@ -235,10 +234,8 @@ static void subghz_setting_load_default_preset( preset_data_count += 2; item->custom_preset_data_size = sizeof(uint8_t) * preset_data_count + sizeof(uint8_t) * 8; item->custom_preset_data = malloc(item->custom_preset_data_size); - //load preset register - memcpy(&item->custom_preset_data[0], &preset_data[0], preset_data_count); - //load pa table - memcpy(&item->custom_preset_data[preset_data_count], &preset_pa_table[0], 8); + //load preset register + pa table + memcpy(&item->custom_preset_data[0], &preset_data[0], item->custom_preset_data_size); } static void subghz_setting_load_default_region( @@ -262,25 +259,13 @@ static void subghz_setting_load_default_region( } subghz_setting_load_default_preset( - instance, - "AM270", - (uint8_t*)furi_hal_subghz_preset_ook_270khz_async_regs, - furi_hal_subghz_preset_ook_async_patable); + instance, "AM270", subghz_device_cc1101_preset_ook_270khz_async_regs); subghz_setting_load_default_preset( - instance, - "AM650", - (uint8_t*)furi_hal_subghz_preset_ook_650khz_async_regs, - furi_hal_subghz_preset_ook_async_patable); + instance, "AM650", subghz_device_cc1101_preset_ook_650khz_async_regs); subghz_setting_load_default_preset( - instance, - "FM238", - (uint8_t*)furi_hal_subghz_preset_2fsk_dev2_38khz_async_regs, - furi_hal_subghz_preset_2fsk_async_patable); + instance, "FM238", subghz_device_cc1101_preset_2fsk_dev2_38khz_async_regs); subghz_setting_load_default_preset( - instance, - "FM476", - (uint8_t*)furi_hal_subghz_preset_2fsk_dev47_6khz_async_regs, - furi_hal_subghz_preset_2fsk_async_patable); + instance, "FM476", subghz_device_cc1101_preset_2fsk_dev47_6khz_async_regs); } void subghz_setting_load_default(SubGhzSetting* instance) { @@ -359,6 +344,7 @@ void subghz_setting_load(SubGhzSetting* instance, const char* file_path) { } while(flipper_format_read_uint32( fff_data_file, "Frequency", (uint32_t*)&temp_data32, 1)) { + //Todo: add a frequency support check depending on the selected radio device if(furi_hal_subghz_is_frequency_valid(temp_data32)) { FURI_LOG_I(TAG, "Frequency loaded %lu", temp_data32); FrequencyList_push_back(instance->frequencies, temp_data32); diff --git a/lib/subghz/subghz_tx_rx_worker.c b/lib/subghz/subghz_tx_rx_worker.c index 42124bebc1c..250e6666f40 100644 --- a/lib/subghz/subghz_tx_rx_worker.c +++ b/lib/subghz/subghz_tx_rx_worker.c @@ -21,6 +21,8 @@ struct SubGhzTxRxWorker { SubGhzTxRxWorkerStatus status; uint32_t frequency; + const SubGhzDevice* device; + const GpioPin* device_data_gpio; SubGhzTxRxWorkerCallbackHaveRead callback_have_read; void* context_have_read; @@ -65,33 +67,33 @@ bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t* uint8_t timeout = 100; bool ret = false; if(instance->status != SubGhzTxRxWorkerStatusRx) { - furi_hal_subghz_rx(); + subghz_devices_set_rx(instance->device); instance->status = SubGhzTxRxWorkerStatusRx; furi_delay_tick(1); } //waiting for reception to complete - while(furi_hal_gpio_read(&gpio_cc1101_g0)) { + while(furi_hal_gpio_read(instance->device_data_gpio)) { furi_delay_tick(1); if(!--timeout) { FURI_LOG_W(TAG, "RX cc1101_g0 timeout"); - furi_hal_subghz_flush_rx(); - furi_hal_subghz_rx(); + subghz_devices_flush_rx(instance->device); + subghz_devices_set_rx(instance->device); break; } } - if(furi_hal_subghz_rx_pipe_not_empty()) { + if(subghz_devices_rx_pipe_not_empty(instance->device)) { FURI_LOG_I( TAG, "RSSI: %03.1fdbm LQI: %d", - (double)furi_hal_subghz_get_rssi(), - furi_hal_subghz_get_lqi()); - if(furi_hal_subghz_is_rx_data_crc_valid()) { - furi_hal_subghz_read_packet(data, size); + (double)subghz_devices_get_rssi(instance->device), + subghz_devices_get_lqi(instance->device)); + if(subghz_devices_is_rx_data_crc_valid(instance->device)) { + subghz_devices_read_packet(instance->device, data, size); ret = true; } - furi_hal_subghz_flush_rx(); - furi_hal_subghz_rx(); + subghz_devices_flush_rx(instance->device); + subghz_devices_set_rx(instance->device); } return ret; } @@ -99,26 +101,28 @@ bool subghz_tx_rx_worker_rx(SubGhzTxRxWorker* instance, uint8_t* data, uint8_t* void subghz_tx_rx_worker_tx(SubGhzTxRxWorker* instance, uint8_t* data, size_t size) { uint8_t timeout = 200; if(instance->status != SubGhzTxRxWorkerStatusIDLE) { - furi_hal_subghz_idle(); + subghz_devices_idle(instance->device); } - furi_hal_subghz_write_packet(data, size); - furi_hal_subghz_tx(); //start send + subghz_devices_write_packet(instance->device, data, size); + subghz_devices_set_tx(instance->device); //start send instance->status = SubGhzTxRxWorkerStatusTx; - while(!furi_hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be set -> sync transmitted + while(!furi_hal_gpio_read( + instance->device_data_gpio)) { // Wait for GDO0 to be set -> sync transmitted furi_delay_tick(1); if(!--timeout) { FURI_LOG_W(TAG, "TX !cc1101_g0 timeout"); break; } } - while(furi_hal_gpio_read(&gpio_cc1101_g0)) { // Wait for GDO0 to be cleared -> end of packet + while(furi_hal_gpio_read( + instance->device_data_gpio)) { // Wait for GDO0 to be cleared -> end of packet furi_delay_tick(1); if(!--timeout) { FURI_LOG_W(TAG, "TX cc1101_g0 timeout"); break; } } - furi_hal_subghz_idle(); + subghz_devices_idle(instance->device); instance->status = SubGhzTxRxWorkerStatusIDLE; } /** Worker thread @@ -128,16 +132,19 @@ void subghz_tx_rx_worker_tx(SubGhzTxRxWorker* instance, uint8_t* data, size_t si */ static int32_t subghz_tx_rx_worker_thread(void* context) { SubGhzTxRxWorker* instance = context; + furi_assert(instance->device); FURI_LOG_I(TAG, "Worker start"); - furi_hal_subghz_reset(); - furi_hal_subghz_idle(); - furi_hal_subghz_load_preset(FuriHalSubGhzPresetGFSK9_99KbAsync); - //furi_hal_subghz_load_preset(FuriHalSubGhzPresetMSK99_97KbAsync); - furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); + subghz_devices_begin(instance->device); + instance->device_data_gpio = subghz_devices_get_data_gpio(instance->device); + subghz_devices_reset(instance->device); + subghz_devices_idle(instance->device); + subghz_devices_load_preset(instance->device, FuriHalSubGhzPresetGFSK9_99KbAsync, NULL); - furi_hal_subghz_set_frequency_and_path(instance->frequency); - furi_hal_subghz_flush_rx(); + furi_hal_gpio_init(instance->device_data_gpio, GpioModeInput, GpioPullNo, GpioSpeedLow); + + subghz_devices_set_frequency(instance->device, instance->frequency); + subghz_devices_flush_rx(instance->device); uint8_t data[SUBGHZ_TXRX_WORKER_MAX_TXRX_SIZE + 1] = {0}; size_t size_tx = 0; @@ -191,8 +198,8 @@ static int32_t subghz_tx_rx_worker_thread(void* context) { furi_delay_tick(1); } - furi_hal_subghz_set_path(FuriHalSubGhzPathIsolate); - furi_hal_subghz_sleep(); + subghz_devices_sleep(instance->device); + subghz_devices_end(instance->device); FURI_LOG_I(TAG, "Worker stop"); return 0; @@ -224,7 +231,10 @@ void subghz_tx_rx_worker_free(SubGhzTxRxWorker* instance) { free(instance); } -bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency) { +bool subghz_tx_rx_worker_start( + SubGhzTxRxWorker* instance, + const SubGhzDevice* device, + uint32_t frequency) { furi_assert(instance); furi_assert(!instance->worker_running); bool res = false; @@ -235,6 +245,7 @@ bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency) { if(furi_hal_region_is_frequency_allowed(frequency)) { instance->frequency = frequency; + instance->device = device; res = true; } diff --git a/lib/subghz/subghz_tx_rx_worker.h b/lib/subghz/subghz_tx_rx_worker.h index ddc02e749d8..56bdb0a1feb 100644 --- a/lib/subghz/subghz_tx_rx_worker.h +++ b/lib/subghz/subghz_tx_rx_worker.h @@ -1,6 +1,7 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { @@ -67,9 +68,13 @@ void subghz_tx_rx_worker_free(SubGhzTxRxWorker* instance); /** * Start SubGhzTxRxWorker * @param instance Pointer to a SubGhzTxRxWorker instance + * @param device Pointer to a SubGhzDevice instance * @return bool - true if ok */ -bool subghz_tx_rx_worker_start(SubGhzTxRxWorker* instance, uint32_t frequency); +bool subghz_tx_rx_worker_start( + SubGhzTxRxWorker* instance, + const SubGhzDevice* device, + uint32_t frequency); /** * Stop SubGhzTxRxWorker diff --git a/lib/subghz/types.h b/lib/subghz/types.h index 719beff45f8..d87a0dc760c 100644 --- a/lib/subghz/types.h +++ b/lib/subghz/types.h @@ -21,6 +21,12 @@ #define SUBGHZ_RAW_FILE_VERSION 1 #define SUBGHZ_RAW_FILE_TYPE "Flipper SubGhz RAW File" +#define SUBGHZ_KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes") +#define SUBGHZ_KEYSTORE_DIR_USER_NAME EXT_PATH("subghz/assets/keeloq_mfcodes_user") +#define SUBGHZ_CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") +#define SUBGHZ_NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") +#define SUBGHZ_ALUTECH_AT_4N_DIR_NAME EXT_PATH("subghz/assets/alutech_at_4n") + typedef struct SubGhzProtocolRegistry SubGhzProtocolRegistry; typedef struct SubGhzEnvironment SubGhzEnvironment; diff --git a/lib/toolbox/m_cstr_dup.h b/lib/toolbox/m_cstr_dup.h index 0555f72c651..11b7fe35ada 100644 --- a/lib/toolbox/m_cstr_dup.h +++ b/lib/toolbox/m_cstr_dup.h @@ -2,15 +2,16 @@ #include #define M_INIT_DUP(a) ((a) = strdup("")) -#define M_SET_DUP(a, b) (M_CHECK_DEFAULT_TYPE(a), free((void*)a), (a) = strdup(b)) +#define M_INIT_SET_DUP(a, b) ((a) = strdup(b)) +#define M_SET_DUP(a, b) (free((void*)a), (a) = strdup(b)) #define M_CLEAR_DUP(a) (free((void*)a)) -#define M_CSTR_DUP_OPLIST \ - (INIT(M_INIT_DUP), \ - INIT_SET(M_SET_DUP), \ - SET(M_SET_DUP), \ - CLEAR(M_CLEAR_DUP), \ - HASH(m_core_cstr_hash), \ - EQUAL(M_CSTR_EQUAL), \ - CMP(strcmp), \ +#define M_CSTR_DUP_OPLIST \ + (INIT(M_INIT_DUP), \ + INIT_SET(M_INIT_SET_DUP), \ + SET(M_SET_DUP), \ + CLEAR(M_CLEAR_DUP), \ + HASH(m_core_cstr_hash), \ + EQUAL(M_CSTR_EQUAL), \ + CMP(strcmp), \ TYPE(const char*)) diff --git a/lib/u8g2/u8g2_glue.c b/lib/u8g2/u8g2_glue.c index 0d4879bce5d..0142e3e2fdc 100644 --- a/lib/u8g2/u8g2_glue.c +++ b/lib/u8g2/u8g2_glue.c @@ -2,7 +2,7 @@ #include -#define CONTRAST_ERC 32 +#define CONTRAST_ERC 31 #define CONTRAST_MGG 31 uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { diff --git a/scripts/distfap.py b/scripts/distfap.py old mode 100644 new mode 100755 index d330988b51e..b1c5587906b --- a/scripts/distfap.py +++ b/scripts/distfap.py @@ -52,9 +52,7 @@ def install(self): if not self.args.launch_app: return 0 - storage.send_and_wait_eol( - f'loader open "Applications" {fap_dst_path}\r' - ) + storage.send_and_wait_eol(f"loader open {fap_dst_path}\r") if len(result := storage.read.until(storage.CLI_EOL)): self.logger.error(f"Unexpected response: {result.decode('ascii')}") diff --git a/scripts/fastfap.py b/scripts/fastfap.py new file mode 100755 index 00000000000..95e32c37be9 --- /dev/null +++ b/scripts/fastfap.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +import hashlib +import os +import struct +import subprocess +import tempfile +from collections import defaultdict +from dataclasses import dataclass + +from elftools.elf.elffile import ELFFile +from elftools.elf.relocation import RelocationSection +from elftools.elf.sections import SymbolTableSection +from fbt.sdk.hashes import gnu_sym_hash +from flipper.app import App + +VERSION = 1 + + +@dataclass +class RelData: + section: int + section_value: int + type: int + offset: int + name: str + + +@dataclass(frozen=True) +class UniqueRelData: + section: int + section_value: int + type: int + name: str + + +@dataclass +class RelSection: + name: str + oringinal_name: str + data: dict[UniqueRelData, list[int]] + + +def serialize_relsection_data(data: dict[UniqueRelData, list[int]]) -> bytes: + result = struct.pack(" 0: + result += struct.pack("> 8) & 0xFF, (offset >> 16) & 0xFF + ) + + return result + + +class Main(App): + def init(self): + self.parser.add_argument("fap_src_path", help="App file to upload") + self.parser.add_argument("objcopy_path", help="Objcopy path") + self.parser.set_defaults(func=self.process) + + def process(self): + fap_path = self.args.fap_src_path + objcopy_path = self.args.objcopy_path + + sections: list[RelSection] = [] + + with open(fap_path, "rb") as f: + elf_file = ELFFile(f) + + relocation_sections: list[RelocationSection] = [] + symtab_section: SymbolTableSection | None = None + + for section in elf_file.iter_sections(): + if isinstance(section, RelocationSection): + relocation_sections.append(section) + + if isinstance(section, SymbolTableSection): + symtab_section = section + + if not symtab_section: + self.logger.error("No symbol table found") + return 1 + + if not relocation_sections: + self.logger.info("No relocation sections found") + return 0 + + for section in relocation_sections: + section_relocations: list[RelData] = [] + + for relocation in section.iter_relocations(): + symbol_id: int = relocation.entry["r_info_sym"] + offset: int = relocation.entry["r_offset"] + type: int = relocation.entry["r_info_type"] + symbol = symtab_section.get_symbol(symbol_id) + section_index: int = symbol["st_shndx"] + section_value: int = symbol["st_value"] + if section_index == "SHN_UNDEF": + section_index = 0 + + section_relocations.append( + RelData(section_index, section_value, type, offset, symbol.name) + ) + + unique_relocations: dict[UniqueRelData, list[int]] = defaultdict(list) + for relocation in section_relocations: + unique = UniqueRelData( + relocation.section, + relocation.section_value, + relocation.type, + relocation.name, + ) + + unique_relocations[unique].append(relocation.offset) + + section_name = section.name + if section_name.startswith(".rel"): + section_name = ".fast.rel" + section_name[4:] + else: + self.logger.error( + "Unknown relocation section name: %s", section_name + ) + return 1 + + sections.append( + RelSection(section_name, section.name, unique_relocations) + ) + + with tempfile.TemporaryDirectory() as temp_dir: + for section in sections: + data = serialize_relsection_data(section.data) + hash_name = hashlib.md5(section.name.encode()).hexdigest() + filename = f"{temp_dir}/{hash_name}.bin" + + if os.path.isfile(filename): + self.logger.error(f"File {filename} already exists") + return 1 + + with open(filename, "wb") as f: + f.write(data) + + exit_code = subprocess.run( + [ + objcopy_path, + "--add-section", + f"{section.name}={filename}", + fap_path, + ], + check=True, + ) + + if exit_code.returncode != 0: + self.logger.error("objcopy failed") + return 1 + + return 0 + + +if __name__ == "__main__": + Main()() diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 820f5a8c55f..73e5c777079 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -353,12 +353,18 @@ def get_builtin_app_folders(self): class ApplicationsCGenerator: APP_TYPE_MAP = { - FlipperAppType.SERVICE: ("FlipperApplication", "FLIPPER_SERVICES"), - FlipperAppType.SYSTEM: ("FlipperApplication", "FLIPPER_SYSTEM_APPS"), - FlipperAppType.APP: ("FlipperApplication", "FLIPPER_APPS"), - FlipperAppType.DEBUG: ("FlipperApplication", "FLIPPER_DEBUG_APPS"), - FlipperAppType.SETTINGS: ("FlipperApplication", "FLIPPER_SETTINGS_APPS"), - FlipperAppType.STARTUP: ("FlipperOnStartHook", "FLIPPER_ON_SYSTEM_START"), + 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", + ), } def __init__(self, buildset: AppBuildset, autorun_app: str = ""): @@ -379,7 +385,7 @@ def get_app_descr(self, app: FlipperApplication): .appid = "{app.appid}", .stack_size = {app.stack_size}, .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" + .flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}""" def generate(self): contents = [ @@ -408,7 +414,7 @@ def generate(self): contents.extend( [ self.get_app_ep_forward(archive_app[0]), - f"const FlipperApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", + f"const FlipperInternalApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", ] ) diff --git a/scripts/fbt/sdk/collector.py b/scripts/fbt/sdk/collector.py index 578a8c7a62b..1dd3bc4ebb9 100644 --- a/scripts/fbt/sdk/collector.py +++ b/scripts/fbt/sdk/collector.py @@ -1,4 +1,5 @@ from typing import List +from .hashes import gnu_sym_hash from cxxheaderparser.parser import CxxParser from . import ( @@ -72,13 +73,6 @@ def add_header(self, header: str): self.api.headers.add(ApiHeader(header)) -def gnu_sym_hash(name: str): - h = 0x1505 - for c in name: - h = (h << 5) + h + ord(c) - return str(hex(h))[-8:] - - class SdkCollector: def __init__(self): self.symbol_manager = SymbolManager() diff --git a/scripts/fbt/sdk/hashes.py b/scripts/fbt/sdk/hashes.py new file mode 100644 index 00000000000..fef88ddb5ee --- /dev/null +++ b/scripts/fbt/sdk/hashes.py @@ -0,0 +1,5 @@ +def gnu_sym_hash(name: str) -> int: + h = 0x1505 + for c in name: + h = ((h << 5) + h + ord(c)) & 0xFFFFFFFF + return h diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 16d5dcbabd3..69d70021413 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -384,10 +384,16 @@ def generate_embed_app_metadata_actions(source, target, env, for_signature): "${SOURCES} ${TARGET}" ) - actions.append( - Action( - objcopy_str, - "$APPMETAEMBED_COMSTR", + actions.extend( + ( + Action( + objcopy_str, + "$APPMETAEMBED_COMSTR", + ), + Action( + "${PYTHON3} ${FBT_SCRIPT_DIR}/fastfap.py ${TARGET} ${OBJCOPY}", + "$FASTFAP_COMSTR", + ), ) ) @@ -450,6 +456,7 @@ def generate(env, **kw): APPMETA_COMSTR="\tAPPMETA\t${TARGET}", APPFILE_COMSTR="\tAPPFILE\t${TARGET}", APPMETAEMBED_COMSTR="\tFAP\t${TARGET}", + FASTFAP_COMSTR="\tFASTFAP\t${TARGET}", APPCHECK_COMSTR="\tAPPCHK\t${SOURCE}", ) diff --git a/scripts/fwsize.py b/scripts/fwsize.py old mode 100644 new mode 100755 diff --git a/scripts/get_env.py b/scripts/get_env.py old mode 100644 new mode 100755 diff --git a/scripts/runfap.py b/scripts/runfap.py old mode 100644 new mode 100755 index a240acf1212..42141acff65 --- a/scripts/runfap.py +++ b/scripts/runfap.py @@ -63,7 +63,7 @@ def install(self): storage_ops.recursive_send(fap_dst_path, fap_local_path, False) fap_host_app = self.args.targets[0] - startup_command = f'"Applications" {fap_host_app}' + startup_command = f"{fap_host_app}" if self.args.host_app: startup_command = self.args.host_app diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py old mode 100644 new mode 100755 diff --git a/scripts/selfupdate.py b/scripts/selfupdate.py old mode 100644 new mode 100755 diff --git a/scripts/slideshow.py b/scripts/slideshow.py old mode 100644 new mode 100755 diff --git a/scripts/testing/await_flipper.py b/scripts/testing/await_flipper.py index 2b4c8b4c39b..ea07d6be7ff 100755 --- a/scripts/testing/await_flipper.py +++ b/scripts/testing/await_flipper.py @@ -8,6 +8,7 @@ def flp_serial_by_name(flp_name): if sys.platform == "darwin": # MacOS flp_serial = "/dev/cu.usbmodemflip_" + flp_name + "1" + logging.info(f"Darwin, looking for {flp_serial}") elif sys.platform == "linux": # Linux flp_serial = ( "/dev/serial/by-id/usb-Flipper_Devices_Inc._Flipper_" @@ -16,10 +17,12 @@ def flp_serial_by_name(flp_name): + flp_name + "-if00" ) + logging.info(f"linux, looking for {flp_serial}") if os.path.exists(flp_serial): return flp_serial else: + logging.info(f"Couldn't find {logging.info} on this attempt.") if os.path.exists(flp_name): return flp_name else: @@ -38,7 +41,7 @@ def main(): level=logging.INFO, datefmt="%Y-%m-%d %H:%M:%S", ) - logging.info("Waiting for Flipper to be ready...") + logging.info(f"Waiting for Flipper {flipper_name} to be ready...") while flipper == "" and elapsed < UPDATE_TIMEOUT: elapsed += 1 diff --git a/scripts/testing/units.py b/scripts/testing/units.py index 5083bcd4350..fd8e29a7333 100755 --- a/scripts/testing/units.py +++ b/scripts/testing/units.py @@ -20,13 +20,13 @@ def main(): logging.error("Flipper not found!") sys.exit(1) - with serial.Serial(flp_serial, timeout=1) as flipper: + with serial.Serial(flp_serial, timeout=10) as flipper: logging.info(f"Found Flipper at {flp_serial}") flipper.baudrate = 230400 flipper.flushOutput() flipper.flushInput() - flipper.timeout = 180 + flipper.timeout = 300 flipper.read_until(b">: ").decode("utf-8") flipper.write(b"unit_tests\r") diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 9d45b7e9d7e..4ae04e2a2cb 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=21" +set "FLIPPER_TOOLCHAIN_VERSION=22" if ["%FBT_TOOLCHAIN_PATH%"] == [""] ( set "FBT_TOOLCHAIN_PATH=%FBT_ROOT%" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 143dce74b91..e5548f488b1 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -4,7 +4,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"21"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"22"}"; if [ -z ${FBT_TOOLCHAIN_PATH+x} ] ; then FBT_TOOLCHAIN_PATH_WAS_SET=0; diff --git a/scripts/version.py b/scripts/version.py old mode 100644 new mode 100755 diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index b70b5cff56f..776977cda74 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -228,6 +228,7 @@ vars.AddVariables( ("applications/debug", False), ("applications/external", False), ("applications/examples", False), + ("applications/drivers", False), ("applications_user", False), ], ),