From c35406689b87e6a68e0374fff6e8bbe2efe7a13c Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 31 May 2023 16:45:55 +0100 Subject: [PATCH] Merge branch 'dev' of https://github.com/DarkFlippers/unleashed-firmware into xfw-dev --- .gitignore | 27 +- .../scenes/lfrfid_debug_app_scene_tune.c | 5 +- .../external/mifare_nested/application.fam | 2 +- .../mifare_nested/lib/nested/nested.c | 22 - .../external/mifare_nested/mifare_nested.c | 1 + .../external/mifare_nested/mifare_nested_i.h | 3 +- .../mifare_nested/mifare_nested_worker.c | 83 +- .../mifare_nested/mifare_nested_worker.h | 10 +- .../scenes/mifare_nested_scene_about.c | 2 +- .../scenes/mifare_nested_scene_check.c | 9 +- .../scenes/mifare_nested_scene_check_keys.c | 7 - .../scenes/mifare_nested_scene_collecting.c | 4 + .../scenes/mifare_nested_scene_config.h | 3 +- .../mifare_nested_scene_no_nonces_collected.c | 94 + .../external/subghz_remote/application.fam | 2 +- .../helpers/subrem_custom_event.h | 10 +- .../subghz_remote/helpers/subrem_presets.c | 10 +- .../subghz_remote/helpers/subrem_presets.h | 5 +- .../subghz_remote/helpers/subrem_types.h | 11 +- .../subghz_remote/helpers/txrx/subghz_txrx.h | 3 + .../scenes/subrem_scene_config.h | 4 +- .../scenes/subrem_scene_open_map_file.c | 43 + .../scenes/subrem_scene_openmapfile.c | 42 - .../scenes/subrem_scene_remote.c | 26 +- .../subghz_remote/scenes/subrem_scene_start.c | 16 +- .../subghz_remote/subghz_remote_app.c | 22 +- .../subghz_remote/subghz_remote_app_i.c | 63 +- .../subghz_remote/subghz_remote_app_i.h | 24 +- .../external/subghz_remote/views/remote.c | 162 +- .../external/subghz_remote/views/remote.h | 6 +- .../helpers/subrem_custom_event.h | 10 +- .../helpers/subrem_presets.c | 3 +- .../subghz_remote_app_i.h | 4 - applications/external/totp/features_config.h | 3 + .../external/totp/ui/fonts/active_font.h | 3 + .../external/totp/ui/fonts/dpcomic/dpcomic.c | 1114 +++++++++ .../external/totp/ui/fonts/dpcomic/dpcomic.h | 7 + .../totp/ui/fonts/funclimbing/funclimbing.c | 1172 ++++++++++ .../totp/ui/fonts/funclimbing/funclimbing.h | 7 + .../totp/ui/fonts/pixelflag/pixelflag.c | 1114 +++++++++ .../totp/ui/fonts/pixelflag/pixelflag.h | 7 + .../scenes/app_settings/totp_app_settings.c | 4 +- .../totp_scene_generate_token.c | 18 + .../scenes/uart_terminal_scene_start.c | 2 +- .../wifi_marauder_app.h | 2 +- .../scenes/infrared_scene_universal_ac.c | 54 +- .../scenes/infrared_scene_universal_audio.c | 75 +- .../scenes/infrared_scene_universal_fan.c | 12 +- .../infrared_scene_universal_projector.c | 8 +- .../scenes/infrared_scene_universal_tv.c | 12 +- .../main/lfrfid/helpers/rfid_writer.c | 96 - .../main/lfrfid/helpers/rfid_writer.h | 26 - .../lfrfid/scenes/lfrfid_scene_clear_t5577.c | 31 +- .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 2 +- .../main/subghz/helpers/subghz_txrx.c | 8 + .../main/subghz/helpers/subghz_txrx.h | 2 + .../scenes/subghz_scene_receiver_info.c | 10 +- .../main/subghz/scenes/subghz_scene_rpc.c | 9 +- .../subghz/scenes/subghz_scene_transmitter.c | 11 +- applications/services/desktop/desktop.c | 57 +- .../services/gui/modules/text_input.c | 2 +- .../icons/Archive/subrem_10px.png | Bin assets/icons/Infrared/CoolHi_25x27.png | Bin 0 -> 3680 bytes assets/icons/Infrared/CoolHi_hvr_25x27.png | Bin 0 -> 3669 bytes assets/icons/Infrared/CoolLo_25x27.png | Bin 0 -> 3676 bytes assets/icons/Infrared/CoolLo_hvr_25x27.png | Bin 0 -> 3657 bytes assets/icons/Infrared/Dehumidify_25x27.png | Bin 0 -> 3665 bytes .../icons/Infrared/Dehumidify_hvr_25x27.png | Bin 0 -> 3652 bytes assets/icons/Infrared/HeatHi_25x27.png | Bin 0 -> 3676 bytes assets/icons/Infrared/HeatHi_hvr_25x27.png | Bin 0 -> 3661 bytes assets/icons/Infrared/HeatLo_25x27.png | Bin 0 -> 3670 bytes assets/icons/Infrared/HeatLo_hvr_25x27.png | Bin 0 -> 3655 bytes assets/icons/Infrared/Off_25x27.png | Bin 0 -> 9530 bytes assets/icons/Infrared/Off_hvr_25x27.png | Bin 0 -> 8460 bytes assets/icons/Infrared/Pause_25x27.png | Bin 0 -> 3634 bytes assets/icons/Infrared/Pause_hvr_25x27.png | Bin 0 -> 3623 bytes assets/icons/Infrared/Play_25x27.png | Bin 0 -> 3653 bytes assets/icons/Infrared/Play_hvr_25x27.png | Bin 0 -> 3643 bytes assets/icons/Infrared/Swing_25x27.png | Bin 1706 -> 0 bytes assets/icons/Infrared/Swing_hvr_25x27.png | Bin 1686 -> 0 bytes assets/icons/Infrared/TrackNext_25x27.png | Bin 0 -> 3651 bytes assets/icons/Infrared/TrackNext_hvr_25x27.png | Bin 0 -> 3639 bytes assets/icons/Infrared/TrackPrev_25x27.png | Bin 0 -> 3657 bytes assets/icons/Infrared/TrackPrev_hvr_25x27.png | Bin 0 -> 3644 bytes assets/resources/infrared/assets/ac.ir | 2050 +++------------- assets/resources/infrared/assets/audio.ir | 2075 ++++++++++++++--- assets/resources/infrared/assets/fans.ir | 520 ++--- .../resources/infrared/assets/projectors.ir | 304 +-- assets/resources/infrared/assets/tv.ir | 680 +++--- fbt_options.py | 7 + firmware.scons | 11 + firmware/targets/f18/api_symbols.csv | 15 +- firmware/targets/f18/furi_hal/furi_hal.c | 5 + .../targets/f18/furi_hal/furi_hal_resources.c | 14 + .../f18/furi_hal/furi_hal_spi_config.c | 31 +- firmware/targets/f7/api_symbols.csv | 44 +- firmware/targets/f7/furi_hal/furi_hal.c | 5 + firmware/targets/f7/furi_hal/furi_hal_bt.c | 11 + firmware/targets/f7/furi_hal/furi_hal_bus.c | 302 +++ firmware/targets/f7/furi_hal/furi_hal_bus.h | 112 + firmware/targets/f7/furi_hal/furi_hal_clock.c | 84 - .../targets/f7/furi_hal/furi_hal_crypto.c | 10 +- firmware/targets/f7/furi_hal/furi_hal_dma.c | 14 + firmware/targets/f7/furi_hal/furi_hal_dma.h | 15 + firmware/targets/f7/furi_hal/furi_hal_flash.c | 22 +- .../targets/f7/furi_hal/furi_hal_i2c_config.c | 32 +- .../targets/f7/furi_hal/furi_hal_ibutton.c | 12 +- .../targets/f7/furi_hal/furi_hal_idle_timer.h | 7 +- firmware/targets/f7/furi_hal/furi_hal_info.c | 20 +- .../targets/f7/furi_hal/furi_hal_infrared.c | 302 +-- firmware/targets/f7/furi_hal/furi_hal_pwm.c | 19 +- .../targets/f7/furi_hal/furi_hal_random.c | 9 +- .../targets/f7/furi_hal/furi_hal_resources.c | 14 + firmware/targets/f7/furi_hal/furi_hal_rfid.c | 109 +- firmware/targets/f7/furi_hal/furi_hal_rfid.h | 60 +- firmware/targets/f7/furi_hal/furi_hal_rtc.c | 2 +- .../targets/f7/furi_hal/furi_hal_speaker.c | 9 +- .../targets/f7/furi_hal/furi_hal_spi_config.c | 31 +- .../targets/f7/furi_hal/furi_hal_spi_types.h | 2 - .../targets/f7/furi_hal/furi_hal_subghz.c | 9 +- firmware/targets/f7/furi_hal/furi_hal_uart.c | 20 +- firmware/targets/f7/furi_hal/furi_hal_usb.c | 9 + firmware/targets/f7/src/update.c | 6 + firmware/targets/furi_hal_include/furi_hal.h | 2 + .../furi_hal_include/furi_hal_random.h | 3 + furi/core/core_defines.h | 5 + lib/digital_signal/digital_signal.c | 4 +- lib/lfrfid/lfrfid_raw_worker.c | 4 +- lib/lfrfid/lfrfid_worker_modes.c | 9 +- lib/lfrfid/tools/t5577.c | 40 +- lib/lfrfid/tools/t5577.h | 2 + lib/nfc/parsers/opal.c | 4 +- lib/pulse_reader/pulse_reader.c | 3 + lib/subghz/blocks/custom_btn.c | 13 +- lib/subghz/blocks/custom_btn.h | 4 - lib/subghz/blocks/custom_btn_i.h | 17 + lib/subghz/environment.c | 12 +- lib/subghz/environment.h | 6 + lib/subghz/protocols/alutech_at_4n.c | 2 +- lib/subghz/protocols/came_atomo.c | 2 +- lib/subghz/protocols/keeloq.c | 151 +- lib/subghz/protocols/keeloq.h | 8 - lib/subghz/protocols/nice_flor_s.c | 2 +- lib/subghz/protocols/secplus_v2.c | 2 +- lib/subghz/protocols/somfy_telis.c | 2 +- lib/subghz/protocols/star_line.c | 59 +- lib/subghz/protocols/star_line.h | 4 - lib/subghz/subghz_keystore.c | 14 +- lib/subghz/subghz_keystore.h | 2 + lib/subghz/subghz_keystore_i.h | 9 + lib/toolbox/version.c | 15 +- lib/toolbox/version.h | 11 + scripts/debug/flipperversion.py | 16 +- scripts/fbt_tools/fbt_envhooks.py | 67 + scripts/fbt_tools/fbt_version.py | 4 +- scripts/ufbt/SConstruct | 5 + scripts/version.py | 23 + site_scons/commandline.scons | 7 + 158 files changed, 8052 insertions(+), 4090 deletions(-) create mode 100644 applications/external/mifare_nested/scenes/mifare_nested_scene_no_nonces_collected.c create mode 100644 applications/external/subghz_remote/helpers/txrx/subghz_txrx.h create mode 100644 applications/external/subghz_remote/scenes/subrem_scene_open_map_file.c delete mode 100644 applications/external/subghz_remote/scenes/subrem_scene_openmapfile.c create mode 100644 applications/external/totp/ui/fonts/dpcomic/dpcomic.c create mode 100644 applications/external/totp/ui/fonts/dpcomic/dpcomic.h create mode 100644 applications/external/totp/ui/fonts/funclimbing/funclimbing.c create mode 100644 applications/external/totp/ui/fonts/funclimbing/funclimbing.h create mode 100644 applications/external/totp/ui/fonts/pixelflag/pixelflag.c create mode 100644 applications/external/totp/ui/fonts/pixelflag/pixelflag.h delete mode 100644 applications/main/lfrfid/helpers/rfid_writer.c delete mode 100644 applications/main/lfrfid/helpers/rfid_writer.h rename applications/external/subghz_remote/subghz_remote_10px.png => assets/icons/Archive/subrem_10px.png (100%) create mode 100644 assets/icons/Infrared/CoolHi_25x27.png create mode 100644 assets/icons/Infrared/CoolHi_hvr_25x27.png create mode 100644 assets/icons/Infrared/CoolLo_25x27.png create mode 100644 assets/icons/Infrared/CoolLo_hvr_25x27.png create mode 100644 assets/icons/Infrared/Dehumidify_25x27.png create mode 100644 assets/icons/Infrared/Dehumidify_hvr_25x27.png create mode 100644 assets/icons/Infrared/HeatHi_25x27.png create mode 100644 assets/icons/Infrared/HeatHi_hvr_25x27.png create mode 100644 assets/icons/Infrared/HeatLo_25x27.png create mode 100644 assets/icons/Infrared/HeatLo_hvr_25x27.png create mode 100644 assets/icons/Infrared/Off_25x27.png create mode 100644 assets/icons/Infrared/Off_hvr_25x27.png create mode 100644 assets/icons/Infrared/Pause_25x27.png create mode 100644 assets/icons/Infrared/Pause_hvr_25x27.png create mode 100644 assets/icons/Infrared/Play_25x27.png create mode 100644 assets/icons/Infrared/Play_hvr_25x27.png delete mode 100644 assets/icons/Infrared/Swing_25x27.png delete mode 100644 assets/icons/Infrared/Swing_hvr_25x27.png create mode 100644 assets/icons/Infrared/TrackNext_25x27.png create mode 100644 assets/icons/Infrared/TrackNext_hvr_25x27.png create mode 100644 assets/icons/Infrared/TrackPrev_25x27.png create mode 100644 assets/icons/Infrared/TrackPrev_hvr_25x27.png mode change 100644 => 100755 assets/resources/infrared/assets/tv.ir create mode 100644 firmware/targets/f7/furi_hal/furi_hal_bus.c create mode 100644 firmware/targets/f7/furi_hal/furi_hal_bus.h create mode 100644 firmware/targets/f7/furi_hal/furi_hal_dma.c create mode 100644 firmware/targets/f7/furi_hal/furi_hal_dma.h create mode 100644 lib/subghz/blocks/custom_btn_i.h create mode 100644 lib/subghz/subghz_keystore_i.h create mode 100644 scripts/fbt_tools/fbt_envhooks.py diff --git a/.gitignore b/.gitignore index b47c16dea..54e5f7a41 100644 --- a/.gitignore +++ b/.gitignore @@ -30,31 +30,29 @@ bindings/ .mxproject Brewfile.lock.json -# Visual Studio Code -/.vscode/ - -# Visual Studio -.vs/ - # Kate .kateproject .kateconfig -# legendary cmake's -build -CMakeLists.txt - -# bundle output -dist - # kde .directory null.d # SCons .sconsign.dblite + + +# Visual Studio Code +/.vscode + +# Visual Studio +/.vs + +# bundle output +/dist + # SCons build dir -build/ +/build # Toolchain /toolchain @@ -69,6 +67,7 @@ PVS-Studio.log .gdbinit +/fbt_options_local.py # XFW-specific: 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 c7f3bf24f..74c53ae6d 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 @@ -14,9 +14,7 @@ void lfrfid_debug_scene_tune_on_enter(void* context) { furi_hal_rfid_comp_set_callback(comparator_trigger_callback, app); furi_hal_rfid_comp_start(); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(125000, 0.5); view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewTune); } @@ -43,6 +41,5 @@ void lfrfid_debug_scene_tune_on_exit(void* context) { furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); furi_hal_rfid_pins_reset(); } diff --git a/applications/external/mifare_nested/application.fam b/applications/external/mifare_nested/application.fam index 1e3853e31..7f3606b36 100644 --- a/applications/external/mifare_nested/application.fam +++ b/applications/external/mifare_nested/application.fam @@ -13,5 +13,5 @@ App( fap_author="AloneLiberty", fap_description="Recover Mifare Classic keys", fap_weburl="https://github.com/AloneLiberty/FlipperNested", - fap_version=(1, 4), + fap_version="1.5.0", ) diff --git a/applications/external/mifare_nested/lib/nested/nested.c b/applications/external/mifare_nested/lib/nested/nested.c index 4d04b99d5..b289b74fb 100644 --- a/applications/external/mifare_nested/lib/nested/nested.c +++ b/applications/external/mifare_nested/lib/nested/nested.c @@ -5,28 +5,6 @@ #include "../../lib/crypto1/crypto1.h" #define TAG "Nested" -void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest) { - furi_assert(dest); - furi_assert(len <= 8); - - while(len--) { - dest[len] = (uint8_t)src; - src >>= 8; - } -} - -uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) { - furi_assert(src); - furi_assert(len <= 8); - - uint64_t res = 0; - while(len--) { - res = (res << 8) | (*src); - src++; - } - return res; -} - uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) { uint16_t crc = 0x6363; // NFCA_CRC_INIT uint8_t byte = 0; diff --git a/applications/external/mifare_nested/mifare_nested.c b/applications/external/mifare_nested/mifare_nested.c index 237eaef9a..bb6947a91 100644 --- a/applications/external/mifare_nested/mifare_nested.c +++ b/applications/external/mifare_nested/mifare_nested.c @@ -396,6 +396,7 @@ void mifare_nested_blink_stop(MifareNested* mifare_nested) { int32_t mifare_nested_app(void* p) { UNUSED(p); + MifareNested* mifare_nested = mifare_nested_alloc(); scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneStart); diff --git a/applications/external/mifare_nested/mifare_nested_i.h b/applications/external/mifare_nested/mifare_nested_i.h index 59aab5825..69907dcd0 100644 --- a/applications/external/mifare_nested/mifare_nested_i.h +++ b/applications/external/mifare_nested/mifare_nested_i.h @@ -21,7 +21,7 @@ #include #include "mifare_nested_icons.h" -#define NESTED_VERSION_APP "1.4.6" +#define NESTED_VERSION_APP "1.5.0" #define NESTED_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNested" #define NESTED_RECOVER_KEYS_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNestedRecovery" #define NESTED_NONCE_FORMAT_VERSION "3" @@ -99,6 +99,7 @@ struct MifareNested { NestedState* nested_state; CheckKeysState* keys_state; + SaveNoncesResult_t* save_state; MifareNestedWorkerState collecting_type; diff --git a/applications/external/mifare_nested/mifare_nested_worker.c b/applications/external/mifare_nested/mifare_nested_worker.c index 6901e98ab..965fcc245 100644 --- a/applications/external/mifare_nested/mifare_nested_worker.c +++ b/applications/external/mifare_nested/mifare_nested_worker.c @@ -296,7 +296,7 @@ uint32_t mifare_nested_worker_predict_delay( } // This part of attack is my attempt to implement it on Flipper. - // Proxmark can do this in 2 fucking steps, but idk how. + // Check README.md for more info // First, we find RPNG rounds per 1000 us for(uint32_t rtr = 0; rtr < 25; rtr++) { @@ -448,7 +448,7 @@ uint32_t mifare_nested_worker_predict_delay( return 1; } -void mifare_nested_worker_write_nonces( +SaveNoncesResult_t* mifare_nested_worker_write_nonces( FuriHalNfcDevData* data, Storage* storage, NonceList_t* nonces, @@ -459,6 +459,11 @@ void mifare_nested_worker_write_nonces( uint32_t distance) { FuriString* path = furi_string_alloc(); Stream* file_stream = file_stream_alloc(storage); + SaveNoncesResult_t* result = malloc(sizeof(SaveNoncesResult_t)); + result->saved = 0; + result->invalid = 0; + result->skipped = 0; + mifare_nested_worker_get_nonces_file_path(data, path); file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS); @@ -472,23 +477,26 @@ void mifare_nested_worker_write_nonces( for(uint8_t tries = 0; tries < tries_count; tries++) { for(uint8_t sector = 0; sector < sector_count; sector++) { for(uint8_t key_type = 0; key_type < 2; key_type++) { - if(nonces->nonces[sector][key_type][tries]->collected && - !nonces->nonces[sector][key_type][tries]->skipped) { + if(nonces->nonces[sector][key_type][tries]->invalid) { + result->invalid++; + } else if(nonces->nonces[sector][key_type][tries]->skipped) { + result->skipped++; + } else if(nonces->nonces[sector][key_type][tries]->collected) { if(nonces->nonces[sector][key_type][tries]->hardnested) { - FuriString* path = furi_string_alloc(); + FuriString* hardnested_path = furi_string_alloc(); mifare_nested_worker_get_hardnested_file_path( - data, path, sector, key_type); + data, hardnested_path, sector, key_type); FuriString* str = furi_string_alloc_printf( "HardNested: Key %c cuid 0x%08lx file %s sec %u\n", !key_type ? 'A' : 'B', nonces->cuid, - furi_string_get_cstr(path), + furi_string_get_cstr(hardnested_path), sector); stream_write_string(file_stream, str); - furi_string_free(path); + furi_string_free(hardnested_path); furi_string_free(str); } else { FuriString* str = furi_string_alloc_printf( @@ -515,6 +523,8 @@ void mifare_nested_worker_write_nonces( stream_write_string(file_stream, str); furi_string_free(str); } + + result->saved++; } } } @@ -529,10 +539,20 @@ void mifare_nested_worker_write_nonces( } free_nonces(nonces, sector_count, free_tries_count); - furi_string_free(path); file_stream_close(file_stream); free(file_stream); + + if(!result->saved) { + FURI_LOG_E(TAG, "No nonces collected, removing file..."); + if(!storage_simply_remove(storage, furi_string_get_cstr(path))) { + FURI_LOG_E(TAG, "Failed to remove .nonces file"); + } + } + + furi_string_free(path); furi_record_close(RECORD_STORAGE); + + return result; } bool mifare_nested_worker_check_initial_keys( @@ -760,7 +780,7 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste mifare_nested_worker_get_block_by_sector(sector), key_type); - info->skipped = true; + info->invalid = true; nonces.nonces[sector][key_type][0] = info; @@ -819,12 +839,20 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste break; } - mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); + SaveNoncesResult_t* result = + mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); free(mf_data); - mifare_nested_worker->callback( - MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + if(result->saved) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + } else { + mifare_nested_worker->context->save_state = result; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context); + } nfc_deactivate(); } @@ -932,7 +960,7 @@ void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_ mifare_nested_worker_get_block_by_sector(sector), key_type); - info->skipped = true; + info->invalid = true; nonces.nonces[sector][key_type][0] = info; mifare_nested_worker->context->nonces = &nonces; @@ -1061,12 +1089,20 @@ void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_ } } - mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); + SaveNoncesResult_t* result = + mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); free(mf_data); - mifare_nested_worker->callback( - MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + if(result->saved) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + } else { + mifare_nested_worker->context->save_state = result; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context); + } nfc_deactivate(); } @@ -1371,13 +1407,20 @@ void mifare_nested_worker_collect_nonces(MifareNestedWorker* mifare_nested_worke break; } - mifare_nested_worker_write_nonces( + SaveNoncesResult_t* result = mifare_nested_worker_write_nonces( &data, storage, &nonces, tries_count, 3, sector_count, delay, distance); free(mf_data); - mifare_nested_worker->callback( - MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + if(result->saved) { + mifare_nested_worker->callback( + MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); + } else { + mifare_nested_worker->context->save_state = result; + + mifare_nested_worker->callback( + MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context); + } nfc_deactivate(); } diff --git a/applications/external/mifare_nested/mifare_nested_worker.h b/applications/external/mifare_nested/mifare_nested_worker.h index 561620676..2421b35eb 100644 --- a/applications/external/mifare_nested/mifare_nested_worker.h +++ b/applications/external/mifare_nested/mifare_nested_worker.h @@ -22,6 +22,7 @@ typedef enum { MifareNestedWorkerEventReserved = 1000, MifareNestedWorkerEventNoTagDetected, + MifareNestedWorkerEventNoNoncesCollected, MifareNestedWorkerEventNoncesCollected, MifareNestedWorkerEventCollecting, @@ -64,8 +65,9 @@ typedef struct { uint32_t target_nt[2]; uint32_t target_ks[2]; uint8_t parity[2][4]; - bool collected; bool skipped; + bool invalid; + bool collected; bool hardnested; } Nonces; @@ -87,3 +89,9 @@ typedef struct { uint32_t sector_keys; bool tag_lost; } KeyInfo_t; + +typedef struct { + uint32_t saved; + uint32_t invalid; + uint32_t skipped; +} SaveNoncesResult_t; \ No newline at end of file diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c index cb07f81a3..9aa46f698 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_about.c @@ -51,7 +51,7 @@ void mifare_nested_scene_about_on_enter(void* context) { 14, AlignCenter, AlignBottom, - "\e#\e! Flipper (Mifare) Nested \e!\n", + "\e#\e! Flipper Nested \e!\n", false); widget_add_text_scroll_element( mifare_nested->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str)); diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c index 4eb344703..45837ff92 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_check.c @@ -56,14 +56,7 @@ bool mifare_nested_scene_check_on_event(void* context, SceneManagerEvent event) bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == MifareNestedWorkerEventNoncesCollected) { - scene_manager_next_scene( - mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); - consumed = true; - } else if(event.event == MifareNestedWorkerEventAttackFailed) { - scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed); - consumed = true; - } else if(event.event == MifareNestedWorkerEventCollecting) { + if(event.event == MifareNestedWorkerEventCollecting) { if(mifare_nested->run == NestedRunAttack) { if(mifare_nested->settings->only_hardnested) { FURI_LOG_I("MifareNested", "Using Hard Nested because user settings"); diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c index f0071b7aa..b06953eeb 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_check_keys.c @@ -84,13 +84,6 @@ bool mifare_nested_scene_check_keys_on_event(void* context, SceneManagerEvent ev if(event.event == GuiButtonTypeCenter) { scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); consumed = true; - } else if(event.event == MifareNestedWorkerEventNoncesCollected) { - scene_manager_next_scene( - mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); - consumed = true; - } else if(event.event == MifareNestedWorkerEventNeedKey) { - scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneNoKeys); - consumed = true; } else if(event.event == MifareNestedWorkerEventKeysFound) { scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneAddedKeys); consumed = true; diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c index 05c96d97d..281210107 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_collecting.c @@ -120,6 +120,10 @@ bool mifare_nested_scene_collecting_on_event(void* context, SceneManagerEvent ev scene_manager_next_scene( mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); consumed = true; + } else if(event.event == MifareNestedWorkerEventNoNoncesCollected) { + scene_manager_next_scene( + mifare_nested->scene_manager, MifareNestedSceneNoNoncesCollected); + consumed = true; } else if(event.event == MifareNestedWorkerEventAttackFailed) { scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed); consumed = true; diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h b/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h index 14cf52c4e..648f0bd73 100644 --- a/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_config.h @@ -10,4 +10,5 @@ ADD_SCENE(mifare_nested, about, About) ADD_SCENE(mifare_nested, static_encrypted_nonce, StaticEncryptedNonce) ADD_SCENE(mifare_nested, need_key_recovery, NeedKeyRecovery) ADD_SCENE(mifare_nested, need_collection, NeedCollection) -ADD_SCENE(mifare_nested, settings, Settings) \ No newline at end of file +ADD_SCENE(mifare_nested, settings, Settings) +ADD_SCENE(mifare_nested, no_nonces_collected, NoNoncesCollected) \ No newline at end of file diff --git a/applications/external/mifare_nested/scenes/mifare_nested_scene_no_nonces_collected.c b/applications/external/mifare_nested/scenes/mifare_nested_scene_no_nonces_collected.c new file mode 100644 index 000000000..74e2459e8 --- /dev/null +++ b/applications/external/mifare_nested/scenes/mifare_nested_scene_no_nonces_collected.c @@ -0,0 +1,94 @@ +#include "../mifare_nested_i.h" + +void mifare_nested_scene_no_nonces_collected_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + MifareNested* mifare_nested = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result); + } +} + +void mifare_nested_scene_no_nonces_collected_on_enter(void* context) { + MifareNested* mifare_nested = context; + Widget* widget = mifare_nested->widget; + SaveNoncesResult_t* save_state = mifare_nested->save_state; + + notification_message(mifare_nested->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 12, &I_DolphinCry); + widget_add_string_element( + widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "No nonces collected"); + + uint32_t index = 12; + + if(save_state->skipped) { + char append_skipped[8] = {'s', 'e', 'c', 't', 'o', 'r', ' ', '\0'}; + if(save_state->skipped != 1) { + append_skipped[6] = 's'; + } + + char draw_str[32] = {}; + snprintf( + draw_str, sizeof(draw_str), "Skipped: %lu %s", save_state->skipped, append_skipped); + + widget_add_string_element(widget, 0, index, AlignLeft, AlignTop, FontSecondary, draw_str); + + widget_add_string_element( + widget, 0, index + 10, AlignLeft, AlignTop, FontSecondary, "(already has keys)"); + + index += 20; + } + + if(save_state->invalid) { + char append_invalid[8] = {'s', 'e', 'c', 't', 'o', 'r', ' ', '\0'}; + if(save_state->invalid != 1) { + append_invalid[6] = 's'; + } + + char draw_str[32] = {}; + snprintf( + draw_str, sizeof(draw_str), "Invalid: %lu %s", save_state->invalid, append_invalid); + + widget_add_string_element(widget, 0, index, AlignLeft, AlignTop, FontSecondary, draw_str); + + widget_add_string_element( + widget, 0, index + 10, AlignLeft, AlignTop, FontSecondary, "(can't auth)"); + } + + free(save_state); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Back", + mifare_nested_scene_no_nonces_collected_widget_callback, + mifare_nested); + + // Setup and start worker + view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget); +} + +bool mifare_nested_scene_no_nonces_collected_on_event(void* context, SceneManagerEvent event) { + MifareNested* mifare_nested = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeBack) { + scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); + consumed = true; + } + + return consumed; +} + +void mifare_nested_scene_no_nonces_collected_on_exit(void* context) { + MifareNested* mifare_nested = context; + + widget_reset(mifare_nested->widget); +} diff --git a/applications/external/subghz_remote/application.fam b/applications/external/subghz_remote/application.fam index 0523e911c..7f12c31f9 100644 --- a/applications/external/subghz_remote/application.fam +++ b/applications/external/subghz_remote/application.fam @@ -11,7 +11,7 @@ App( "gui", "dialogs", ], - stack_size=4 * 1024, + stack_size=2 * 1024, order=11, fap_libs=["assets"], fap_icon="subghz_remote_10px.png", diff --git a/applications/external/subghz_remote/helpers/subrem_custom_event.h b/applications/external/subghz_remote/helpers/subrem_custom_event.h index 46ab8ad54..8d93ab1fd 100644 --- a/applications/external/subghz_remote/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote/helpers/subrem_custom_event.h @@ -1,12 +1,14 @@ #pragma once typedef enum { - //SubmenuIndex - SubmenuIndexSubRemOpenMapFile, + // StartSubmenuIndex + SubmenuIndexSubRemOpenMapFile = 0, +#if FURI_DEBUG SubmenuIndexSubRemRemoteView, - SubmenuIndexSubRemAbout, +#endif + // SubmenuIndexSubRemAbout, - //SubRemCustomEvent + // SubRemCustomEvent SubRemCustomEventViewRemoteStartUP = 100, SubRemCustomEventViewRemoteStartDOWN, SubRemCustomEventViewRemoteStartLEFT, diff --git a/applications/external/subghz_remote/helpers/subrem_presets.c b/applications/external/subghz_remote/helpers/subrem_presets.c index 9601aae6c..e5823b721 100644 --- a/applications/external/subghz_remote/helpers/subrem_presets.c +++ b/applications/external/subghz_remote/helpers/subrem_presets.c @@ -8,7 +8,7 @@ SubRemSubFilePreset* subrem_sub_file_preset_alloc() { sub_preset->fff_data = flipper_format_string_alloc(); sub_preset->file_path = furi_string_alloc(); sub_preset->protocaol_name = furi_string_alloc(); - sub_preset->label = furi_string_alloc_set_str("N/A"); + sub_preset->label = furi_string_alloc(); sub_preset->freq_preset.name = furi_string_alloc(); @@ -34,7 +34,7 @@ void subrem_sub_file_preset_free(SubRemSubFilePreset* sub_preset) { void subrem_sub_file_preset_reset(SubRemSubFilePreset* sub_preset) { furi_assert(sub_preset); - furi_string_set_str(sub_preset->label, "N/A"); + furi_string_set_str(sub_preset->label, ""); furi_string_reset(sub_preset->protocaol_name); furi_string_reset(sub_preset->file_path); @@ -77,7 +77,7 @@ SubRemLoadSubState subrem_sub_preset_load( break; } - SubGhzSetting* setting = subghz_txrx_get_setting(txrx); // txrx->setting; + SubGhzSetting* setting = subghz_txrx_get_setting(txrx); //Load frequency or using default from settings ret = SubRemLoadSubStateErrorFreq; @@ -147,8 +147,7 @@ SubRemLoadSubState subrem_sub_preset_load( if(protocol->flag & SubGhzProtocolFlag_Send) { if((protocol->type == SubGhzProtocolTypeStatic) || (protocol->type == SubGhzProtocolTypeDynamic) || - // TODO: BINRAW It probably works, but checks are needed. - // (protocol->type == SubGhzProtocolTypeBinRAW) || + (protocol->type == SubGhzProtocolTypeBinRAW) || (protocol->type == SubGhzProtocolTypeRAW)) { sub_preset->type = protocol->type; } else { @@ -175,5 +174,6 @@ SubRemLoadSubState subrem_sub_preset_load( } while(false); furi_string_free(temp_str); + sub_preset->load_state = ret; return ret; } diff --git a/applications/external/subghz_remote/helpers/subrem_presets.h b/applications/external/subghz_remote/helpers/subrem_presets.h index 9b0b6b08a..d66181b90 100644 --- a/applications/external/subghz_remote/helpers/subrem_presets.h +++ b/applications/external/subghz_remote/helpers/subrem_presets.h @@ -1,9 +1,10 @@ #pragma once #include "subrem_types.h" +#include "txrx/subghz_txrx.h" + #include -#include -#include "applications/main/subghz/helpers/subghz_txrx.h" +#include typedef struct { FuriString* name; diff --git a/applications/external/subghz_remote/helpers/subrem_types.h b/applications/external/subghz_remote/helpers/subrem_types.h index def807898..b392de17e 100644 --- a/applications/external/subghz_remote/helpers/subrem_types.h +++ b/applications/external/subghz_remote/helpers/subrem_types.h @@ -3,9 +3,8 @@ #include #include -// TODO: File version/type logic -// #define SUBREM_APP_APP_FILE_VERSION 1 -// #define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file" +#define SUBREM_APP_APP_FILE_VERSION 1 +#define SUBREM_APP_APP_FILE_TYPE "Flipper SubRem Map file" #define SUBREM_APP_EXTENSION ".txt" typedef enum { @@ -18,10 +17,7 @@ typedef enum { } SubRemSubKeyName; typedef enum { - SubRemViewSubmenu, - SubRemViewWidget, - SubRemViewPopup, - SubRemViewTextInput, + SubRemViewIDSubmenu, SubRemViewIDRemote, } SubRemViewID; @@ -29,6 +25,7 @@ typedef enum { SubRemLoadSubStateNotSet = 0, SubRemLoadSubStatePreloaded, SubRemLoadSubStateError, + SubRemLoadSubStateErrorIncorectPath, SubRemLoadSubStateErrorNoFile, SubRemLoadSubStateErrorFreq, SubRemLoadSubStateErrorMod, diff --git a/applications/external/subghz_remote/helpers/txrx/subghz_txrx.h b/applications/external/subghz_remote/helpers/txrx/subghz_txrx.h new file mode 100644 index 000000000..0ca780b43 --- /dev/null +++ b/applications/external/subghz_remote/helpers/txrx/subghz_txrx.h @@ -0,0 +1,3 @@ +#pragma once + +#include "../../../../main/subghz/helpers/subghz_txrx.h" diff --git a/applications/external/subghz_remote/scenes/subrem_scene_config.h b/applications/external/subghz_remote/scenes/subrem_scene_config.h index 93d4de642..45e55850a 100644 --- a/applications/external/subghz_remote/scenes/subrem_scene_config.h +++ b/applications/external/subghz_remote/scenes/subrem_scene_config.h @@ -1,3 +1,5 @@ +#ifndef SUBREM_LIGHT ADD_SCENE(subrem, start, Start) -ADD_SCENE(subrem, openmapfile, OpenMapFile) +#endif +ADD_SCENE(subrem, open_map_file, OpenMapFile) ADD_SCENE(subrem, remote, Remote) \ No newline at end of file diff --git a/applications/external/subghz_remote/scenes/subrem_scene_open_map_file.c b/applications/external/subghz_remote/scenes/subrem_scene_open_map_file.c new file mode 100644 index 000000000..1e917580c --- /dev/null +++ b/applications/external/subghz_remote/scenes/subrem_scene_open_map_file.c @@ -0,0 +1,43 @@ +#include "../subghz_remote_app_i.h" + +void subrem_scene_open_map_file_on_enter(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + SubRemLoadMapState load_state = subrem_load_from_file(app); + + if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { + scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); + } else { + if(load_state != SubRemLoadMapStateBack) { +#ifdef SUBREM_LIGHT + dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); +#else + DialogMessage* message = dialog_message_alloc(); + + dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter); + dialog_message_set_text( + message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter); + dialog_message_set_buttons(message, "Back", NULL, NULL); + dialog_message_show(app->dialogs, message); + + dialog_message_free(message); +#endif + } + // TODO: Map Preset Reset + if(!scene_manager_previous_scene(app->scene_manager)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } + } +} + +bool subrem_scene_open_map_file_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void subrem_scene_open_map_file_on_exit(void* context) { + UNUSED(context); +} diff --git a/applications/external/subghz_remote/scenes/subrem_scene_openmapfile.c b/applications/external/subghz_remote/scenes/subrem_scene_openmapfile.c deleted file mode 100644 index 796699c83..000000000 --- a/applications/external/subghz_remote/scenes/subrem_scene_openmapfile.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "../subghz_remote_app_i.h" - -void subrem_scene_openmapfile_on_enter(void* context) { - SubGhzRemoteApp* app = context; - SubRemLoadMapState load_state = subrem_load_from_file(app); - - if(load_state != SubRemLoadMapStateOK && load_state != SubRemLoadMapStateNotAllOK && - load_state != SubRemLoadMapStateBack) { -#ifdef SUBREM_LIGHT - dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); -#else - DialogMessage* message = dialog_message_alloc(); - - dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter); - dialog_message_set_text(message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter); - dialog_message_set_buttons(message, "Back", NULL, NULL); - dialog_message_show(app->dialogs, message); - - dialog_message_free(message); -#endif - } - if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { - scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); - } else { - // TODO: Map Preset Reset - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneStart)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } - } -} - -bool subrem_scene_openmapfile_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; -} - -void subrem_scene_openmapfile_on_exit(void* context) { - UNUSED(context); -} diff --git a/applications/external/subghz_remote/scenes/subrem_scene_remote.c b/applications/external/subghz_remote/scenes/subrem_scene_remote.c index eaa1c41d9..a2e307fd9 100644 --- a/applications/external/subghz_remote/scenes/subrem_scene_remote.c +++ b/applications/external/subghz_remote/scenes/subrem_scene_remote.c @@ -35,24 +35,10 @@ static uint8_t subrem_scene_remote_event_to_index(SubRemCustomEvent event_id) { return ret; } -static bool subrem_scene_remote_update_data_show(void* context) { - SubGhzRemoteApp* app = context; - - const char* labels[SubRemSubKeyNameMaxCount]; - - for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { - labels[i] = furi_string_get_cstr(app->map_preset->subs_preset[i]->label); - } - - subrem_view_remote_add_data_to_show(app->subrem_remote_view, labels); - - return true; -} - void subrem_scene_remote_on_enter(void* context) { SubGhzRemoteApp* app = context; - subrem_scene_remote_update_data_show(app); + subrem_view_remote_update_data_labels(app->subrem_remote_view, app->map_preset->subs_preset); subrem_view_remote_set_callback(app->subrem_remote_view, subrem_scene_remote_callback, app); @@ -63,13 +49,9 @@ bool subrem_scene_remote_on_event(void* context, SceneManagerEvent event) { SubGhzRemoteApp* app = context; if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubRemCustomEventViewRemoteBack) { - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneOpenMapFile)) { - if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneStart)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } + if(!scene_manager_previous_scene(app->scene_manager)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); } return true; } else if( diff --git a/applications/external/subghz_remote/scenes/subrem_scene_start.c b/applications/external/subghz_remote/scenes/subrem_scene_start.c index a4bfa5047..e780b54ce 100644 --- a/applications/external/subghz_remote/scenes/subrem_scene_start.c +++ b/applications/external/subghz_remote/scenes/subrem_scene_start.c @@ -33,13 +33,11 @@ void subrem_scene_start_on_enter(void* context) { // SubmenuIndexSubGhzRemoteAbout, // subrem_scene_start_submenu_callback, // app); - - // TODO: set scene state in subrem alloc - // submenu_set_selected_item( - // submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); - submenu_set_selected_item(submenu, SubmenuIndexSubRemOpenMapFile); - - view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewSubmenu); +#ifndef SUBREM_LIGHT + submenu_set_selected_item( + submenu, scene_manager_get_scene_state(app->scene_manager, SubRemSceneStart)); +#endif + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); } bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { @@ -50,6 +48,10 @@ bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexSubRemOpenMapFile) { +#ifndef SUBREM_LIGHT + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemOpenMapFile); +#endif scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); consumed = true; } diff --git a/applications/external/subghz_remote/subghz_remote_app.c b/applications/external/subghz_remote/subghz_remote_app.c index e48009415..ed9800781 100644 --- a/applications/external/subghz_remote/subghz_remote_app.c +++ b/applications/external/subghz_remote/subghz_remote_app.c @@ -1,8 +1,6 @@ #include "subghz_remote_app_i.h" #include -#include - static bool subghz_remote_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); SubGhzRemoteApp* app = context; @@ -71,9 +69,9 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { // SubMenu app->submenu = submenu_alloc(); view_dispatcher_add_view( - app->view_dispatcher, SubRemViewSubmenu, submenu_get_view(app->submenu)); + app->view_dispatcher, SubRemViewIDSubmenu, submenu_get_view(app->submenu)); - //Dialog + // Dialog app->dialogs = furi_record_open(RECORD_DIALOGS); // Remote view @@ -92,13 +90,13 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { subghz_txrx_set_need_save_callback(app->txrx, subrem_save_active_sub, app); - app->tx_running = false; - - // #ifdef SUBREM_LIGHT +#ifdef SUBREM_LIGHT scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); - // #else - // scene_manager_next_scene(app->scene_manager, SubRemSceneStart); - // #endif +#else + scene_manager_next_scene(app->scene_manager, SubRemSceneStart); + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemOpenMapFile); +#endif return app; } @@ -114,10 +112,10 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { furi_hal_subghz_init_radio_type(SubGhzRadioInternal); // Submenu - view_dispatcher_remove_view(app->view_dispatcher, SubRemViewSubmenu); + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDSubmenu); submenu_free(app->submenu); - //Dialog + // Dialog furi_record_close(RECORD_DIALOGS); // Remote view diff --git a/applications/external/subghz_remote/subghz_remote_app_i.c b/applications/external/subghz_remote/subghz_remote_app_i.c index 3ba437ffa..26659ccb1 100644 --- a/applications/external/subghz_remote/subghz_remote_app_i.c +++ b/applications/external/subghz_remote/subghz_remote_app_i.c @@ -2,23 +2,18 @@ #include #include -#include - -#include "applications/main/subghz/helpers/subghz_txrx_i.h" +#include "helpers/txrx/subghz_txrx.h" // #include // #include +#ifdef APP_SUBGHZREMOTE +#include #include +#endif #define TAG "SubGhzRemote" -// XXX Using TxRx -// [x] use TxRx preset subrem_sub_preset_load & subrem_tx_start_sub -// [x] subrem_sub_preset_load & drop subrem_set_preset_data -// [x] subrem_tx_start_sub -// [x] subrem_tx_stop_sub - static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { [SubRemSubKeyNameUp] = {"UP", "ULABEL"}, [SubRemSubKeyNameDown] = {"DOWN", "DLABEL"}, @@ -45,30 +40,25 @@ static SubRemLoadMapState subrem_map_preset_check( bool all_loaded = true; SubRemLoadMapState ret = SubRemLoadMapStateErrorBrokenFile; - SubRemLoadSubState sub_preset_loaded; + SubRemLoadSubState sub_loadig_state; SubRemSubFilePreset* sub_preset; for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { sub_preset = map_preset->subs_preset[i]; - sub_preset_loaded = SubRemLoadSubStateErrorNoFile; + sub_loadig_state = SubRemLoadSubStateErrorNoFile; if(furi_string_empty(sub_preset->file_path)) { // FURI_LOG_I(TAG, "Empty file path"); } else if(!flipper_format_file_open_existing( fff_data_file, furi_string_get_cstr(sub_preset->file_path))) { + sub_preset->load_state = SubRemLoadSubStateErrorNoFile; FURI_LOG_W(TAG, "Error open file %s", furi_string_get_cstr(sub_preset->file_path)); } else { - sub_preset_loaded = subrem_sub_preset_load(sub_preset, txrx, fff_data_file); + sub_loadig_state = subrem_sub_preset_load(sub_preset, txrx, fff_data_file); } - // TODO: - // Load file state logic - // Label depending on the state - // Move to remote scene - - if(sub_preset_loaded != SubRemLoadSubStateOK) { - furi_string_set_str(sub_preset->label, "N/A"); + if(sub_loadig_state != SubRemLoadSubStateOK) { all_loaded = false; } else { ret = SubRemLoadMapStateNotAllOK; @@ -96,6 +86,9 @@ static bool subrem_map_preset_load(SubRemMapPreset* map_preset, FlipperFormat* f FURI_LOG_W(TAG, "No file patch for %s", map_file_labels[i][0]); #endif sub_preset->type = SubGhzProtocolTypeUnknown; + } else if(!path_contains_only_ascii(furi_string_get_cstr(sub_preset->file_path))) { + FURI_LOG_E(TAG, "Incorrect characters in [%s] file path", map_file_labels[i][0]); + sub_preset->type = SubGhzProtocolTypeUnknown; } else if(!flipper_format_rewind(fff_data_file)) { // Rewind error } else if(!flipper_format_read_string( @@ -103,8 +96,6 @@ static bool subrem_map_preset_load(SubRemMapPreset* map_preset, FlipperFormat* f #if FURI_DEBUG FURI_LOG_W(TAG, "No Label for %s", map_file_labels[i][0]); #endif - // TODO move to remote scene - path_extract_filename(sub_preset->file_path, sub_preset->label, true); ret = true; } else { ret = true; @@ -237,17 +228,15 @@ bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset) NULL, 0); - subghz_custom_btn_set(SUBGHZ_CUSTOM_BTN_OK); - keeloq_reset_original_btn(); +#ifdef APP_SUBGHZREMOTE subghz_custom_btns_reset(); +#endif if(subghz_txrx_tx_start(app->txrx, sub_preset->fff_data) == SubGhzTxRxStartTxStateOk) { ret = true; } } - app->tx_running = ret; - return ret; } @@ -256,22 +245,14 @@ bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced) { SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; if(forced || (sub_preset->type != SubGhzProtocolTypeRAW)) { - // XXX drop app->tx_running - if(app->tx_running) { - subghz_txrx_stop(app->txrx); - - if(sub_preset->type == SubGhzProtocolTypeDynamic) { - keeloq_reset_mfname(); - keeloq_reset_kl_type(); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); - star_line_reset_mfname(); - star_line_reset_kl_type(); - } - - app->tx_running = false; - return true; + subghz_txrx_stop(app->txrx); +#ifdef APP_SUBGHZREMOTE + if(sub_preset->type == SubGhzProtocolTypeDynamic) { + subghz_txrx_reset_dynamic_and_custom_btns(app->txrx); } + subghz_custom_btns_reset(); +#endif + return true; } return false; @@ -284,7 +265,7 @@ SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { SubRemLoadMapState ret = SubRemLoadMapStateBack; DialogsFileBrowserOptions browser_options; - dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_sub1_10px); + dialog_file_browser_set_basic_options(&browser_options, SUBREM_APP_EXTENSION, &I_subrem_10px); browser_options.base_path = SUBREM_APP_FOLDER; // Input events and views are managed by file_select diff --git a/applications/external/subghz_remote/subghz_remote_app_i.h b/applications/external/subghz_remote/subghz_remote_app_i.h index 4542fffab..9291d54f2 100644 --- a/applications/external/subghz_remote/subghz_remote_app_i.h +++ b/applications/external/subghz_remote/subghz_remote_app_i.h @@ -2,34 +2,31 @@ #include "helpers/subrem_types.h" #include "helpers/subrem_presets.h" +#include "scenes/subrem_scene.h" -#include "applications/main/subghz/helpers/subghz_txrx.h" +#include "helpers/txrx/subghz_txrx.h" +#ifdef APP_SUBGHZREMOTE #include +#else +#include +#endif #include "views/remote.h" -#include "scenes/subrem_scene.h" - #include #include #include #include #include -#include #include -#include -#include #include +#include +#include +#include #include -#include - -#include -#include -#include - #define SUBREM_APP_FOLDER EXT_PATH("subghz/remote") #define SUBREM_MAX_LEN_NAME 64 @@ -42,7 +39,6 @@ typedef struct { Submenu* submenu; FuriString* file_path; - // char file_name_tmp[SUBREM_MAX_LEN_NAME]; SubRemViewRemote* subrem_remote_view; @@ -50,8 +46,6 @@ typedef struct { SubGhzTxRx* txrx; - bool tx_running; - uint8_t chusen_sub; } SubGhzRemoteApp; diff --git a/applications/external/subghz_remote/views/remote.c b/applications/external/subghz_remote/views/remote.c index e062f11b1..c2b41cfd6 100644 --- a/applications/external/subghz_remote/views/remote.c +++ b/applications/external/subghz_remote/views/remote.c @@ -4,7 +4,11 @@ #include #include -#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 12 +#include + +#define SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH 30 +#define SUBREM_VIEW_REMOTE_LEFT_OFFSET 10 +#define SUBREM_VIEW_REMOTE_RIGHT_OFFSET 22 struct SubRemViewRemote { View* view; @@ -12,19 +16,8 @@ struct SubRemViewRemote { void* context; }; -// TODO: model typedef struct { - // FuriString* up_label; - // FuriString* down_label; - // FuriString* left_label; - // FuriString* right_label; - // FuriString* ok_label; - - char* up_label; - char* down_label; - char* left_label; - char* right_label; - char* ok_label; + char* labels[SubRemSubKeyNameMaxCount]; SubRemViewRemoteState state; @@ -41,26 +34,61 @@ void subrem_view_remote_set_callback( subrem_view_remote->context = context; } -void subrem_view_remote_add_data_to_show(SubRemViewRemote* subrem_view_remote, const char** labels) { +void subrem_view_remote_update_data_labels( + SubRemViewRemote* subrem_view_remote, + SubRemSubFilePreset** subs_presets) { furi_assert(subrem_view_remote); + furi_assert(subs_presets); + + FuriString* labels[SubRemSubKeyNameMaxCount]; + SubRemSubFilePreset* sub_preset; + + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = subs_presets[i]; + switch(sub_preset->load_state) { + case SubRemLoadSubStateOK: + if(!furi_string_empty(sub_preset->label)) { + labels[i] = furi_string_alloc_set(sub_preset->label); + } else if(!furi_string_empty(sub_preset->file_path)) { + labels[i] = furi_string_alloc(); + path_extract_filename(sub_preset->file_path, labels[i], true); + } else { + labels[i] = furi_string_alloc_set("Empty Label"); + } + break; + + case SubRemLoadSubStateErrorNoFile: + labels[i] = furi_string_alloc_set("[X] Can't open file"); + break; + + case SubRemLoadSubStateErrorFreq: + case SubRemLoadSubStateErrorMod: + case SubRemLoadSubStateErrorProtocol: + labels[i] = furi_string_alloc_set("[X] Error in .sub file"); + break; + + default: + labels[i] = furi_string_alloc_set(""); + break; + } + } with_view_model( subrem_view_remote->view, SubRemViewRemoteModel * model, { - strncpy(model->up_label, labels[0], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->down_label, labels[1], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->left_label, labels[2], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->right_label, labels[3], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - strncpy(model->ok_label, labels[4], SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); - - // furi_string_set(model->up_label, up_label); - // furi_string_set(model->down_label, down_label); - // furi_string_set(model->left_label, left_label); - // furi_string_set(model->right_label, right_label); - // furi_string_set(model->ok_label, ok_label); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + strncpy( + model->labels[i], + furi_string_get_cstr(labels[i]), + SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH); + } }, true); + + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + furi_string_free(labels[i]); + } } void subrem_view_remote_set_state( @@ -95,24 +123,32 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { //Labels canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 10, 10, model->up_label); - canvas_draw_str(canvas, 10, 20, model->down_label); - canvas_draw_str(canvas, 10, 30, model->left_label); - canvas_draw_str(canvas, 10, 40, model->right_label); - canvas_draw_str(canvas, 10, 50, model->ok_label); + uint8_t y = 0; + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + elements_text_box( + canvas, + SUBREM_VIEW_REMOTE_LEFT_OFFSET, + y + 2, + 126 - SUBREM_VIEW_REMOTE_LEFT_OFFSET - SUBREM_VIEW_REMOTE_RIGHT_OFFSET, + 12, + AlignLeft, + AlignBottom, + model->labels[i], + false); + y += 10; + } - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - // canvas_draw_str(canvas, 10, 10, furi_string_get_cstr(model->up_label)); - - canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); + if(model->state == SubRemViewRemoteStateOFF) { + elements_button_left(canvas, "Back"); + elements_button_right(canvas, "Save"); + } else { + canvas_draw_str_aligned(canvas, 11, 62, AlignLeft, AlignBottom, "Hold=Exit."); + } //Status text and indicator canvas_draw_icon(canvas, 113, 15, &I_Pin_cell_13x13); - if(model->state == SubRemViewRemoteStateIdle) { + if(model->state == SubRemViewRemoteStateIdle || model->state == SubRemViewRemoteStateOFF) { canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, "Idle"); } else { switch(model->state) { @@ -147,10 +183,6 @@ void subrem_view_remote_draw(Canvas* canvas, SubRemViewRemoteModel* model) { break; } } - //Repeat indicator - //canvas_draw_str_aligned(canvas, 125, 40, AlignRight, AlignBottom, "Repeat:"); - //canvas_draw_icon(canvas, 115, 39, &I_SubGHzRemote_Repeat_12x14); - //canvas_draw_str_aligned(canvas, 125, 62, AlignRight, AlignBottom, int_to_char(app->repeat)); } bool subrem_view_remote_input(InputEvent* event, void* context) { @@ -158,17 +190,6 @@ bool subrem_view_remote_input(InputEvent* event, void* context) { SubRemViewRemote* subrem_view_remote = context; if(event->key == InputKeyBack && event->type == InputTypeLong) { - with_view_model( - subrem_view_remote->view, - SubRemViewRemoteModel * model, - { - strcpy(model->up_label, "N/A"); - strcpy(model->down_label, "N/A"); - strcpy(model->left_label, "N/A"); - strcpy(model->right_label, "N/A"); - strcpy(model->ok_label, "N/A"); - }, - false); subrem_view_remote->callback(SubRemCustomEventViewRemoteBack, subrem_view_remote->context); return true; } else if(event->key == InputKeyBack && event->type == InputTypeShort) { @@ -240,23 +261,10 @@ SubRemViewRemote* subrem_view_remote_alloc() { { model->state = SubRemViewRemoteStateIdle; - model->up_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->down_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->left_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->right_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - model->ok_label = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); - - strcpy(model->up_label, "N/A"); - strcpy(model->down_label, "N/A"); - strcpy(model->left_label, "N/A"); - strcpy(model->right_label, "N/A"); - strcpy(model->ok_label, "N/A"); - - // model->up_label = furi_string_alloc_set_str("N/A"); - // model->down_label = furi_string_alloc_set_str("N/A"); - // model->left_label = furi_string_alloc_set_str("N/A"); - // model->right_label = furi_string_alloc_set_str("N/A"); - // model->ok_label = furi_string_alloc_set_str("N/A"); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + model->labels[i] = malloc(sizeof(char) * SUBREM_VIEW_REMOTE_MAX_LABEL_LENGTH + 1); + strcpy(model->labels[i], ""); + } model->pressed_btn = 0; }, @@ -271,17 +279,9 @@ void subrem_view_remote_free(SubRemViewRemote* subghz_remote) { subghz_remote->view, SubRemViewRemoteModel * model, { - free(model->up_label); - free(model->down_label); - free(model->left_label); - free(model->right_label); - free(model->ok_label); - - // furi_string_free(model->up_label); - // furi_string_free(model->down_label); - // furi_string_free(model->left_label); - // furi_string_free(model->right_label); - // furi_string_free(model->ok_label); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + free(model->labels[i]); + } }, true); view_free(subghz_remote->view); diff --git a/applications/external/subghz_remote/views/remote.h b/applications/external/subghz_remote/views/remote.h index ea274fca4..5b1e8153a 100644 --- a/applications/external/subghz_remote/views/remote.h +++ b/applications/external/subghz_remote/views/remote.h @@ -2,11 +2,13 @@ #include #include "../helpers/subrem_custom_event.h" +#include "../helpers/subrem_presets.h" typedef enum { SubRemViewRemoteStateIdle, SubRemViewRemoteStateLoading, SubRemViewRemoteStateSending, + SubRemViewRemoteStateOFF, } SubRemViewRemoteState; typedef struct SubRemViewRemote SubRemViewRemote; @@ -24,7 +26,9 @@ void subrem_view_remote_free(SubRemViewRemote* subrem_view_remote); View* subrem_view_remote_get_view(SubRemViewRemote* subrem_view_remote); -void subrem_view_remote_add_data_to_show(SubRemViewRemote* subrem_view_remote, const char** labels); +void subrem_view_remote_update_data_labels( + SubRemViewRemote* subrem_view_remote, + SubRemSubFilePreset** subs_presets); void subrem_view_remote_set_state( SubRemViewRemote* subrem_view_remote, diff --git a/applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h b/applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h index 779458c20..da3de2aae 100644 --- a/applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_configurator/helpers/subrem_custom_event.h @@ -9,11 +9,13 @@ typedef enum { } SubRemEditMenuState; typedef enum { - // SubmenuIndex + // StartSubmenuIndex SubmenuIndexSubRemEditMapFile = 0, SubmenuIndexSubRemNewMapFile, +#if FURI_DEBUG SubmenuIndexSubRemRemoteView, - SubmenuIndexSubRemAbout, +#endif + // SubmenuIndexSubRemAbout, // EditSubmenuIndex EditSubmenuIndexEditLabel, @@ -45,8 +47,4 @@ typedef enum { SubRemCustomEventSceneEditPreviewSaved, SubRemCustomEventSceneNewName, - - // // SceneStates - // SubRemSceneOpenMapFileStateOpen, - // SubRemSceneOpenMapFileStateEdit, } SubRemCustomEvent; \ No newline at end of file diff --git a/applications/external/subghz_remote_configurator/helpers/subrem_presets.c b/applications/external/subghz_remote_configurator/helpers/subrem_presets.c index dc298c069..e5823b721 100644 --- a/applications/external/subghz_remote_configurator/helpers/subrem_presets.c +++ b/applications/external/subghz_remote_configurator/helpers/subrem_presets.c @@ -147,8 +147,7 @@ SubRemLoadSubState subrem_sub_preset_load( if(protocol->flag & SubGhzProtocolFlag_Send) { if((protocol->type == SubGhzProtocolTypeStatic) || (protocol->type == SubGhzProtocolTypeDynamic) || - // TODO: BINRAW It probably works, but checks are needed. - // (protocol->type == SubGhzProtocolTypeBinRAW) || + (protocol->type == SubGhzProtocolTypeBinRAW) || (protocol->type == SubGhzProtocolTypeRAW)) { sub_preset->type = protocol->type; } else { diff --git a/applications/external/subghz_remote_configurator/subghz_remote_app_i.h b/applications/external/subghz_remote_configurator/subghz_remote_app_i.h index 7e2f284a2..0bc1c19c2 100644 --- a/applications/external/subghz_remote_configurator/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_configurator/subghz_remote_app_i.h @@ -23,10 +23,6 @@ #include -#include -#include -#include - #define SUBREM_APP_FOLDER EXT_PATH("subghz/remote") #define SUBREM_MAX_LEN_NAME 64 diff --git a/applications/external/totp/features_config.h b/applications/external/totp/features_config.h index c789af27b..15e81b28a 100644 --- a/applications/external/totp/features_config.h +++ b/applications/external/totp/features_config.h @@ -12,3 +12,6 @@ // Target firmware to build for #define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_UL_XFW + +// Max custom fonts value +#define MAX_CUSTOM_FONTS (9) \ No newline at end of file diff --git a/applications/external/totp/ui/fonts/active_font.h b/applications/external/totp/ui/fonts/active_font.h index 054fa4a55..c873ce200 100644 --- a/applications/external/totp/ui/fonts/active_font.h +++ b/applications/external/totp/ui/fonts/active_font.h @@ -10,3 +10,6 @@ #include "712serif/712serif.h" #include "graph35pix/graph35pix.h" #include "karma_future/karma_future.h" +#include "funclimbing/funclimbing.h" +#include "dpcomic/dpcomic.h" +#include "pixelflag/pixelflag.h" diff --git a/applications/external/totp/ui/fonts/dpcomic/dpcomic.c b/applications/external/totp/ui/fonts/dpcomic/dpcomic.c new file mode 100644 index 000000000..e9c5ea1de --- /dev/null +++ b/applications/external/totp/ui/fonts/dpcomic/dpcomic.c @@ -0,0 +1,1114 @@ +#include "dpcomic.h" + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for DPComic 18pt +*/ + +/* Character bitmaps for DPComic 18pt */ +const uint8_t dPComic_18ptBitmaps[] = { + /* @0 '-' (15 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xE0, + 0x3F, + 0xF8, + 0x0F, + 0xF8, + 0x0F, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @34 '0' (15 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xE0, + 0x07, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0xE0, + 0x07, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @68 '1' (15 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xE0, + 0x01, + 0xF8, + 0x01, + 0xF8, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xE0, + 0x0F, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @102 '2' (15 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x07, + 0xC0, + 0x07, + 0xE0, + 0x0F, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x07, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xE0, + 0x3F, + 0xF8, + 0x0F, + 0xF8, + 0x0F, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @136 '3' (15 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x3F, + 0xC0, + 0x3F, + 0xE0, + 0x3F, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x07, + 0xC0, + 0x07, + 0xC0, + 0x07, + 0x00, + 0x0F, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0xE0, + 0x0F, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @170 '4' (15 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0F, + 0xC0, + 0x0F, + 0xC0, + 0x0F, + 0xE0, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0xF8, + 0x0F, + 0xF8, + 0x0F, + 0xF8, + 0x0F, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @204 '5' (15 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x3F, + 0xC0, + 0x3F, + 0xC0, + 0x0F, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x07, + 0xE0, + 0x0F, + 0xE0, + 0x0F, + 0x00, + 0x0E, + 0x00, + 0x0F, + 0x00, + 0x0F, + 0xE0, + 0x07, + 0xF8, + 0x01, + 0xF8, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @238 '6' (15 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x0F, + 0x00, + 0x0F, + 0xC0, + 0x07, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xE0, + 0x07, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0F, + 0x38, + 0x0F, + 0xF8, + 0x07, + 0xE0, + 0x01, + 0xE0, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @272 '7' (15 pixels wide) */ + 0x00, + 0x00, + 0xE0, + 0x0F, + 0xE0, + 0x0F, + 0xF8, + 0x0F, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x07, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xE0, + 0x00, + 0xF8, + 0x00, + 0xF8, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @306 '8' (15 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x0F, + 0xC0, + 0x0F, + 0xE0, + 0x38, + 0xE0, + 0x3E, + 0xE0, + 0x3E, + 0xC0, + 0x0F, + 0xE0, + 0x07, + 0xE0, + 0x07, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0F, + 0xE0, + 0x07, + 0xE0, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @340 '9' (15 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x07, + 0xC0, + 0x07, + 0xE0, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0xF8, + 0x0F, + 0xF8, + 0x0F, + 0xE0, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0xE0, + 0x01, + 0xF8, + 0x00, + 0xF8, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @374 'B' (15 pixels wide) */ + 0xC0, + 0x0F, + 0xE0, + 0x3F, + 0xE0, + 0x3F, + 0xF8, + 0x38, + 0x38, + 0x3E, + 0x38, + 0x3E, + 0xF8, + 0x0F, + 0xF8, + 0x3F, + 0xF8, + 0x3F, + 0x38, + 0x38, + 0x38, + 0x3E, + 0x38, + 0x3E, + 0xF8, + 0x0F, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @408 'C' (15 pixels wide) */ + 0x00, + 0x0F, + 0xC0, + 0x3F, + 0xC0, + 0x3F, + 0xE0, + 0x39, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xF8, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x38, + 0x38, + 0x38, + 0x3E, + 0x38, + 0x3E, + 0xF8, + 0x0F, + 0xE0, + 0x07, + 0xE0, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @442 'D' (15 pixels wide) */ + 0xC0, + 0x07, + 0xE0, + 0x0F, + 0xE0, + 0x0F, + 0xF8, + 0x3E, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x3E, + 0x38, + 0x0F, + 0x38, + 0x0F, + 0xF8, + 0x07, + 0xF8, + 0x01, + 0xF8, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @476 'F' (15 pixels wide) */ + 0x80, + 0x1F, + 0xC0, + 0x0F, + 0xC0, + 0x0F, + 0xF0, + 0x01, + 0x70, + 0x00, + 0x70, + 0x00, + 0xF0, + 0x0F, + 0xF0, + 0x03, + 0xF0, + 0x03, + 0x70, + 0x00, + 0x70, + 0x00, + 0x70, + 0x00, + 0x70, + 0x00, + 0x70, + 0x00, + 0x70, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @510 'G' (15 pixels wide) */ + 0x00, + 0x0F, + 0xC0, + 0x3F, + 0xC0, + 0x3F, + 0xE0, + 0x39, + 0xE0, + 0x00, + 0xE0, + 0x00, + 0xF8, + 0x00, + 0x38, + 0x3E, + 0x38, + 0x3E, + 0x38, + 0x38, + 0x38, + 0x3E, + 0x38, + 0x3E, + 0xF8, + 0x0F, + 0xE0, + 0x07, + 0xE0, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @544 'H' (15 pixels wide) */ + 0x00, + 0x30, + 0x20, + 0x38, + 0x20, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0xF8, + 0x3F, + 0xF8, + 0x3F, + 0xF8, + 0x3F, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @578 'J' (15 pixels wide) */ + 0x00, + 0x08, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x00, + 0x0E, + 0x18, + 0x0F, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0xE0, + 0x01, + 0xE0, + 0x01, + + /* @612 'K' (15 pixels wide) */ + 0x20, + 0x30, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x3E, + 0x38, + 0x0F, + 0x38, + 0x0F, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x38, + 0x0F, + 0x38, + 0x3E, + 0x38, + 0x3E, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @646 'M' (15 pixels wide) */ + 0x08, + 0x10, + 0x3E, + 0x1C, + 0x3E, + 0x1C, + 0x7E, + 0x1E, + 0xFE, + 0x1F, + 0xFE, + 0x1F, + 0xCE, + 0x1D, + 0x0E, + 0x1C, + 0x0E, + 0x1C, + 0x0E, + 0x1C, + 0x0E, + 0x1C, + 0x0E, + 0x1C, + 0x0E, + 0x1C, + 0x0E, + 0x1C, + 0x0E, + 0x1C, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @680 'N' (15 pixels wide) */ + 0x20, + 0x30, + 0xF8, + 0x38, + 0xF8, + 0x38, + 0xF8, + 0x38, + 0xF8, + 0x39, + 0xF8, + 0x39, + 0xF8, + 0x39, + 0x38, + 0x3F, + 0x38, + 0x3F, + 0x38, + 0x3F, + 0x38, + 0x3E, + 0x38, + 0x3E, + 0x38, + 0x3E, + 0x38, + 0x38, + 0x38, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @714 'P' (15 pixels wide) */ + 0xC0, + 0x07, + 0xE0, + 0x0F, + 0xE0, + 0x0F, + 0xF8, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0F, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0xF8, + 0x01, + 0x38, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @748 'Q' (15 pixels wide) */ + 0x00, + 0x0F, + 0xC0, + 0x3F, + 0xC0, + 0x3F, + 0xE0, + 0x39, + 0xE0, + 0x38, + 0xE0, + 0x38, + 0xF8, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x3E, + 0x38, + 0x3E, + 0xF8, + 0x0F, + 0xE0, + 0x3F, + 0xE0, + 0x3F, + 0x00, + 0x38, + 0x00, + 0x38, + + /* @782 'R' (15 pixels wide) */ + 0xC0, + 0x07, + 0xE0, + 0x0F, + 0xE0, + 0x0F, + 0xF8, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0F, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0xF8, + 0x01, + 0x38, + 0x07, + 0x38, + 0x07, + 0x38, + 0x0F, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @816 'T' (15 pixels wide) */ + 0x00, + 0x7E, + 0xE0, + 0x3F, + 0xE0, + 0x3F, + 0xF8, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @850 'V' (15 pixels wide) */ + 0x20, + 0x30, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x07, + 0x38, + 0x07, + 0xE0, + 0x07, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @884 'W' (15 pixels wide) */ + 0x04, + 0x40, + 0x07, + 0x70, + 0x07, + 0x70, + 0x07, + 0x71, + 0xC7, + 0x71, + 0xC7, + 0x71, + 0xC7, + 0x71, + 0xC7, + 0x71, + 0xC7, + 0x71, + 0xC7, + 0x71, + 0xE7, + 0x39, + 0xE7, + 0x39, + 0x3C, + 0x0F, + 0x1C, + 0x07, + 0x1C, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @918 'X' (15 pixels wide) */ + 0x18, + 0x30, + 0x38, + 0x38, + 0x38, + 0x38, + 0xF8, + 0x3E, + 0xE0, + 0x0F, + 0xE0, + 0x0F, + 0xC0, + 0x07, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xE0, + 0x07, + 0x38, + 0x0F, + 0x38, + 0x0F, + 0x38, + 0x3E, + 0x18, + 0x38, + 0x18, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @952 'Y' (15 pixels wide) */ + 0x18, + 0x08, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0x38, + 0x0E, + 0xF8, + 0x0F, + 0xF8, + 0x0F, + 0xE0, + 0x07, + 0xE0, + 0x01, + 0xE0, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +/* Character descriptors for DPComic 18pt */ +/* { [Char width in bits], [Offset into dPComic_18ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO dPComic_18ptDescriptors[] = { + {15, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {15, 34}, /* 0 */ + {15, 68}, /* 1 */ + {15, 102}, /* 2 */ + {15, 136}, /* 3 */ + {15, 170}, /* 4 */ + {15, 204}, /* 5 */ + {15, 238}, /* 6 */ + {15, 272}, /* 7 */ + {15, 306}, /* 8 */ + {15, 340}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {15, 374}, /* B */ + {15, 408}, /* C */ + {15, 442}, /* D */ + {0, 0}, /* E */ + {15, 476}, /* F */ + {15, 510}, /* G */ + {15, 544}, /* H */ + {0, 0}, /* I */ + {15, 578}, /* J */ + {15, 612}, /* K */ + {0, 0}, /* L */ + {15, 646}, /* M */ + {15, 680}, /* N */ + {0, 0}, /* O */ + {15, 714}, /* P */ + {15, 748}, /* Q */ + {15, 782}, /* R */ + {0, 0}, /* S */ + {15, 816}, /* T */ + {0, 0}, /* U */ + {15, 850}, /* V */ + {15, 884}, /* W */ + {15, 918}, /* X */ + {15, 952}, /* Y */ +}; + +/* Font information for DPComic 18pt */ +const FONT_INFO dPComic_18ptFontInfo = { + 17, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 2, /* Width, in pixels, of space character */ + dPComic_18ptDescriptors, /* Character descriptor array */ + dPComic_18ptBitmaps, /* Character bitmap array */ +}; diff --git a/applications/external/totp/ui/fonts/dpcomic/dpcomic.h b/applications/external/totp/ui/fonts/dpcomic/dpcomic.h new file mode 100644 index 000000000..bac49b4d6 --- /dev/null +++ b/applications/external/totp/ui/fonts/dpcomic/dpcomic.h @@ -0,0 +1,7 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font_info.h" + +extern const FONT_INFO dPComic_18ptFontInfo; \ No newline at end of file diff --git a/applications/external/totp/ui/fonts/funclimbing/funclimbing.c b/applications/external/totp/ui/fonts/funclimbing/funclimbing.c new file mode 100644 index 000000000..d6b1a0c97 --- /dev/null +++ b/applications/external/totp/ui/fonts/funclimbing/funclimbing.c @@ -0,0 +1,1172 @@ +#include "funclimbing.h" + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for fun climbing (Demo) 18pt +*/ + +/* Character bitmaps for fun climbing (Demo) 18pt */ +const uint8_t funclimbingDemo_18ptBitmaps[] = { + /* @0 '-' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xE0, + 0x03, + 0xE0, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @36 '0' (16 pixels wide) */ + 0x00, + 0x00, + 0x80, + 0x00, + 0xE0, + 0x03, + 0x20, + 0x02, + 0x10, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x08, + 0x04, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x20, + 0x02, + 0xE0, + 0x01, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @72 '1' (16 pixels wide) */ + 0x00, + 0x02, + 0x00, + 0x03, + 0x80, + 0x03, + 0xC0, + 0x02, + 0x60, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x00, + + /* @108 '2' (16 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x07, + 0x60, + 0x04, + 0x20, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x08, + 0x02, + 0x08, + 0x02, + 0x00, + 0x01, + 0x00, + 0x01, + 0x80, + 0x00, + 0x80, + 0x00, + 0x40, + 0x00, + 0x60, + 0x00, + 0xC0, + 0x03, + 0x00, + 0x1C, + 0x00, + 0x00, + + /* @144 '3' (16 pixels wide) */ + 0x00, + 0x02, + 0x80, + 0x05, + 0x40, + 0x08, + 0x40, + 0x08, + 0x40, + 0x10, + 0x40, + 0x10, + 0x00, + 0x10, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0x0C, + 0x00, + 0x06, + 0x00, + 0x03, + 0x80, + 0x0F, + 0x00, + 0x10, + 0x00, + 0x10, + 0x30, + 0x08, + 0xC0, + 0x07, + 0x00, + 0x00, + + /* @180 '4' (16 pixels wide) */ + 0x00, + 0x10, + 0x00, + 0x10, + 0x40, + 0x10, + 0x40, + 0x10, + 0x40, + 0x10, + 0x40, + 0x10, + 0x40, + 0x10, + 0x20, + 0x10, + 0x20, + 0x10, + 0x20, + 0x10, + 0x20, + 0x10, + 0x30, + 0x10, + 0xF0, + 0x1F, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + + /* @216 '5' (16 pixels wide) */ + 0x00, + 0x00, + 0x60, + 0x00, + 0xA0, + 0x03, + 0x20, + 0x04, + 0x20, + 0x00, + 0x30, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0xF0, + 0x00, + 0x80, + 0x03, + 0x00, + 0x04, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0x04, + 0x80, + 0x03, + 0xF0, + 0x00, + 0x00, + 0x00, + + /* @252 '6' (16 pixels wide) */ + 0x00, + 0x00, + 0x40, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x18, + 0x03, + 0xC8, + 0x06, + 0x28, + 0x0C, + 0x18, + 0x08, + 0x18, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x10, + 0x08, + 0x30, + 0x0C, + 0xC0, + 0x07, + 0x00, + 0x00, + + /* @288 '7' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x0F, + 0xF0, + 0x09, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x06, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x03, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x01, + 0x00, + 0x00, + + /* @324 '8' (16 pixels wide) */ + 0x80, + 0x01, + 0x60, + 0x02, + 0x30, + 0x04, + 0x10, + 0x08, + 0x10, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x10, + 0x0C, + 0x10, + 0x04, + 0x60, + 0x03, + 0xC0, + 0x01, + 0x40, + 0x03, + 0x20, + 0x04, + 0x20, + 0x04, + 0x20, + 0x04, + 0x20, + 0x04, + 0xC0, + 0x03, + 0x00, + 0x00, + + /* @360 '9' (16 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x01, + 0x20, + 0x02, + 0x10, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0xE0, + 0x03, + 0x00, + 0x02, + 0x00, + 0x02, + 0x00, + 0x01, + 0x00, + 0x01, + 0x80, + 0x00, + 0x80, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @396 'B' (16 pixels wide) */ + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0xE8, + 0x0F, + 0x38, + 0x10, + 0x10, + 0x10, + 0x10, + 0x30, + 0x10, + 0x10, + 0x10, + 0x18, + 0xF0, + 0x07, + 0x20, + 0x00, + + /* @432 'C' (16 pixels wide) */ + 0x00, + 0x03, + 0x80, + 0x06, + 0x40, + 0x04, + 0x40, + 0x04, + 0x40, + 0x08, + 0x40, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x40, + 0x00, + 0x40, + 0x08, + 0x40, + 0x08, + 0x40, + 0x08, + 0xC0, + 0x08, + 0x80, + 0x04, + 0x80, + 0x05, + 0x00, + 0x02, + + /* @468 'D' (16 pixels wide) */ + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x80, + 0x07, + 0x40, + 0x04, + 0x20, + 0x04, + 0x20, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x30, + 0x04, + 0x20, + 0x04, + 0x20, + 0x04, + 0x40, + 0x04, + 0x80, + 0x05, + 0x00, + 0x07, + + /* @504 'F' (16 pixels wide) */ + 0x00, + 0x02, + 0x80, + 0x0D, + 0xC0, + 0x08, + 0x40, + 0x10, + 0x60, + 0x10, + 0x20, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0xF8, + 0x01, + 0x20, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x20, + 0x00, + 0x40, + 0x00, + + /* @540 'G' (16 pixels wide) */ + 0x80, + 0x00, + 0x60, + 0x01, + 0x20, + 0x03, + 0x30, + 0x02, + 0x10, + 0x02, + 0x10, + 0x02, + 0x10, + 0x02, + 0x10, + 0x02, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0xD0, + 0x0F, + 0x10, + 0x02, + 0x10, + 0x01, + 0x20, + 0x01, + 0xE0, + 0x00, + 0x40, + 0x00, + + /* @576 'H' (16 pixels wide) */ + 0x00, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0x18, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x0F, + 0x90, + 0x09, + 0xD0, + 0x18, + 0x50, + 0x10, + 0x30, + 0x10, + 0x30, + 0x10, + 0x10, + 0x10, + 0x00, + 0x00, + + /* @612 'J' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x00, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x10, + 0x04, + 0x20, + 0x04, + 0x20, + 0x02, + 0x20, + 0x02, + 0x60, + 0x03, + 0xC0, + 0x01, + 0x00, + 0x00, + + /* @648 'K' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x08, + 0x10, + 0x0C, + 0x10, + 0x02, + 0xB0, + 0x01, + 0xE0, + 0x00, + 0x60, + 0x00, + 0x60, + 0x00, + 0xA0, + 0x00, + 0x20, + 0x01, + 0x20, + 0x02, + 0x20, + 0x0C, + 0x20, + 0x08, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @684 'M' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x10, + 0x10, + 0x30, + 0x18, + 0x30, + 0x18, + 0x50, + 0x34, + 0x50, + 0x24, + 0xC8, + 0x22, + 0x88, + 0x22, + 0x88, + 0x21, + 0x08, + 0x21, + 0x04, + 0x60, + 0x04, + 0x40, + 0x04, + 0x40, + 0x04, + 0x40, + 0x02, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @720 'N' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x02, + 0x01, + 0x86, + 0x07, + 0x44, + 0x04, + 0x24, + 0x08, + 0x24, + 0x08, + 0x14, + 0x18, + 0x14, + 0x10, + 0x1C, + 0x10, + 0x0C, + 0x10, + 0x0C, + 0x10, + 0x08, + 0x10, + 0x00, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @756 'P' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0xE0, + 0x01, + 0x20, + 0x02, + 0x20, + 0x04, + 0x60, + 0x04, + 0x40, + 0x04, + 0x40, + 0x04, + 0x40, + 0x04, + 0x40, + 0x06, + 0x40, + 0x02, + 0xC0, + 0x01, + 0xC0, + 0x00, + 0x40, + 0x00, + 0x40, + 0x00, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @792 'Q' (16 pixels wide) */ + 0x00, + 0x00, + 0xC0, + 0x03, + 0x30, + 0x06, + 0x18, + 0x08, + 0x08, + 0x10, + 0x04, + 0x10, + 0x04, + 0x20, + 0x04, + 0x20, + 0x04, + 0x20, + 0x08, + 0x21, + 0x08, + 0x33, + 0x10, + 0x12, + 0x30, + 0x0E, + 0xC0, + 0x07, + 0x00, + 0x08, + 0x00, + 0x08, + 0x00, + 0x10, + 0x00, + 0x00, + + /* @828 'R' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x07, + 0x88, + 0x0D, + 0x48, + 0x08, + 0x68, + 0x00, + 0x28, + 0x00, + 0x28, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x10, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @864 'T' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0xE0, + 0x03, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x00, + 0x80, + 0x04, + 0x80, + 0x04, + 0x80, + 0x04, + 0x80, + 0x04, + 0x80, + 0x05, + 0x00, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @900 'V' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x08, + 0x10, + 0x10, + 0x10, + 0x10, + 0x18, + 0x10, + 0x08, + 0x10, + 0x08, + 0x10, + 0x04, + 0x10, + 0x04, + 0x20, + 0x04, + 0x20, + 0x02, + 0x20, + 0x02, + 0x20, + 0x01, + 0x40, + 0x01, + 0xC0, + 0x01, + 0xC0, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @936 'W' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x80, + 0x02, + 0x80, + 0x02, + 0x40, + 0x02, + 0x40, + 0x02, + 0x41, + 0x86, + 0x42, + 0x84, + 0x42, + 0x44, + 0x44, + 0x44, + 0x64, + 0x24, + 0x28, + 0x28, + 0x28, + 0x18, + 0x30, + 0x18, + 0x30, + 0x18, + 0x20, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @972 'X' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x08, + 0x08, + 0x10, + 0x04, + 0x20, + 0x04, + 0x40, + 0x02, + 0x80, + 0x03, + 0x80, + 0x01, + 0x80, + 0x03, + 0x40, + 0x02, + 0x30, + 0x04, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + + /* @1008 'Y' (16 pixels wide) */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x08, + 0x08, + 0x08, + 0x08, + 0x08, + 0x0C, + 0x08, + 0x0C, + 0x08, + 0x0A, + 0x10, + 0x0A, + 0xF0, + 0x09, + 0x00, + 0x0C, + 0x10, + 0x04, + 0x10, + 0x04, + 0x20, + 0x02, + 0xE0, + 0x03, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +/* Character descriptors for fun climbing (Demo) 18pt */ +/* { [Char width in bits], [Offset into funclimbingDemo_18ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO funclimbingDemo_18ptDescriptors[] = { + {16, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {16, 36}, /* 0 */ + {16, 72}, /* 1 */ + {16, 108}, /* 2 */ + {16, 144}, /* 3 */ + {16, 180}, /* 4 */ + {16, 216}, /* 5 */ + {16, 252}, /* 6 */ + {16, 288}, /* 7 */ + {16, 324}, /* 8 */ + {16, 360}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {16, 396}, /* B */ + {16, 432}, /* C */ + {16, 468}, /* D */ + {0, 0}, /* E */ + {16, 504}, /* F */ + {16, 540}, /* G */ + {16, 576}, /* H */ + {0, 0}, /* I */ + {16, 612}, /* J */ + {16, 648}, /* K */ + {0, 0}, /* L */ + {16, 684}, /* M */ + {16, 720}, /* N */ + {0, 0}, /* O */ + {16, 756}, /* P */ + {16, 792}, /* Q */ + {16, 828}, /* R */ + {0, 0}, /* S */ + {16, 864}, /* T */ + {0, 0}, /* U */ + {16, 900}, /* V */ + {16, 936}, /* W */ + {16, 972}, /* X */ + {16, 1008}, /* Y */ +}; + +/* Font information for fun climbing (Demo) 18pt */ +const FONT_INFO funclimbingDemo_18ptFontInfo = { + 18, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 2, /* Width, in pixels, of space character */ + funclimbingDemo_18ptDescriptors, /* Character descriptor array */ + funclimbingDemo_18ptBitmaps, /* Character bitmap array */ +}; diff --git a/applications/external/totp/ui/fonts/funclimbing/funclimbing.h b/applications/external/totp/ui/fonts/funclimbing/funclimbing.h new file mode 100644 index 000000000..26614adf1 --- /dev/null +++ b/applications/external/totp/ui/fonts/funclimbing/funclimbing.h @@ -0,0 +1,7 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font_info.h" + +extern const FONT_INFO funclimbingDemo_18ptFontInfo; \ No newline at end of file diff --git a/applications/external/totp/ui/fonts/pixelflag/pixelflag.c b/applications/external/totp/ui/fonts/pixelflag/pixelflag.c new file mode 100644 index 000000000..2b7be9eb8 --- /dev/null +++ b/applications/external/totp/ui/fonts/pixelflag/pixelflag.c @@ -0,0 +1,1114 @@ +#include "pixelflag.h" + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +/* +** Font data for {PixelFlag} 18pt +*/ + +/* Character bitmaps for {PixelFlag} 18pt */ +const uint8_t pixelFlag_18ptBitmaps[] = { + /* @0 '-' (13 pixels wide) */ + 0xFE, + 0x07, + 0xFE, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFE, + 0x07, + 0xFE, + 0x07, + + /* @34 '0' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xF8, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @68 '1' (13 pixels wide) */ + 0xff, + 0xff, + 0xff, + 0xff, + 0x00, + 0xe0, + 0xc0, + 0xe0, + 0xc0, + 0xe0, + 0xe0, + 0xe0, + 0xe0, + 0xe0, + 0xc0, + 0xe0, + 0xc0, + 0xe0, + 0xc0, + 0xe0, + 0xc0, + 0xe0, + 0xc0, + 0xe0, + 0xe0, + 0xe3, + 0xe0, + 0xe3, + 0x00, + 0xe0, + 0xff, + 0xff, + 0xff, + 0xff, + + /* @102 '2' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x07, + 0xFC, + 0x07, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x18, + 0xF8, + 0x07, + 0xFC, + 0x07, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0xFC, + 0x1F, + 0xFC, + 0x1F, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @136 '3' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x07, + 0xFC, + 0x07, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x18, + 0xE0, + 0x07, + 0xE0, + 0x1F, + 0x00, + 0x18, + 0x00, + 0x18, + 0xFC, + 0x1F, + 0xFC, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @170 '4' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x00, + 0x06, + 0x00, + 0x06, + 0x00, + 0x07, + 0xC0, + 0x07, + 0xC0, + 0x06, + 0x60, + 0x06, + 0x78, + 0x06, + 0x18, + 0x06, + 0xFC, + 0x1F, + 0xFC, + 0x1F, + 0x00, + 0x06, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @204 '5' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x1F, + 0xFC, + 0x1F, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0xFC, + 0x07, + 0xFC, + 0x1F, + 0x00, + 0x18, + 0x00, + 0x18, + 0xFC, + 0x1F, + 0xFC, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @238 '6' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x00, + 0xFC, + 0x07, + 0xFC, + 0x1F, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xF8, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @272 '7' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x1F, + 0xFC, + 0x1F, + 0x00, + 0x06, + 0x00, + 0x07, + 0x00, + 0x03, + 0xC0, + 0x00, + 0xE0, + 0x00, + 0x60, + 0x00, + 0x18, + 0x00, + 0x1C, + 0x00, + 0x0C, + 0x00, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @306 '8' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xF8, + 0x07, + 0xFC, + 0x1F, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xF8, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @340 '9' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xF8, + 0x1F, + 0xF8, + 0x1F, + 0x00, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xF8, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @374 'B' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x07, + 0xFC, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x07, + 0xFC, + 0x1F, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xFC, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @408 'C' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xF8, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @442 'D' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x07, + 0xFC, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xFC, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @476 'F' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x1F, + 0xFC, + 0x1F, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0xFC, + 0x03, + 0xFC, + 0x03, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @510 'G' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x00, + 0xCC, + 0x1F, + 0xCC, + 0x1F, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xF8, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @544 'H' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xFC, + 0x1F, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @578 'J' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x18, + 0x00, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x1F, + 0xF8, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @612 'K' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x06, + 0x0C, + 0x07, + 0x0C, + 0x03, + 0xFC, + 0x00, + 0xFC, + 0x03, + 0x0C, + 0x03, + 0x0C, + 0x06, + 0x0C, + 0x1E, + 0x0C, + 0x18, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @646 'M' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x1C, + 0x1E, + 0x7C, + 0x1F, + 0x6C, + 0x1B, + 0xCC, + 0x18, + 0xCC, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @680 'N' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x1C, + 0x18, + 0x7C, + 0x18, + 0x6C, + 0x18, + 0xCC, + 0x18, + 0xCC, + 0x1B, + 0x0C, + 0x1B, + 0x0C, + 0x1E, + 0x0C, + 0x1E, + 0x0C, + 0x18, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @714 'P' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x07, + 0xFC, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x07, + 0xFC, + 0x07, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x0C, + 0x00, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @748 'Q' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xF8, + 0x07, + 0xF8, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xCC, + 0x18, + 0xCC, + 0x1B, + 0x0C, + 0x1B, + 0x0C, + 0x1E, + 0xFC, + 0x1F, + 0xF8, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @782 'R' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x07, + 0xFC, + 0x07, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xFC, + 0x07, + 0xFC, + 0x1F, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @816 'T' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0xFC, + 0x1F, + 0xFC, + 0x1F, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @850 'V' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x1C, + 0x1E, + 0x18, + 0x06, + 0x60, + 0x03, + 0xE0, + 0x03, + 0xC0, + 0x00, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @884 'W' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0xCC, + 0x18, + 0xCC, + 0x18, + 0xCC, + 0x18, + 0xCC, + 0x18, + 0xCC, + 0x18, + 0xCC, + 0x18, + 0xFC, + 0x1F, + 0x78, + 0x07, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @918 'X' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x18, + 0x06, + 0x78, + 0x07, + 0x60, + 0x03, + 0xC0, + 0x00, + 0xE0, + 0x03, + 0x60, + 0x03, + 0x18, + 0x06, + 0x1C, + 0x1E, + 0x0C, + 0x18, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, + + /* @952 'Y' (13 pixels wide) */ + 0xFF, + 0x1F, + 0xFF, + 0x1F, + 0x00, + 0x00, + 0x0C, + 0x18, + 0x0C, + 0x18, + 0x18, + 0x06, + 0x78, + 0x07, + 0x60, + 0x03, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0xC0, + 0x00, + 0x00, + 0x00, + 0xFF, + 0x1F, + 0xFF, + 0x1F, +}; + +/* Character descriptors for {PixelFlag} 18pt */ +/* { [Char width in bits], [Offset into pixelFlag_18ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO pixelFlag_18ptDescriptors[] = { + {13, 0}, /* - */ + {0, 0}, /* . */ + {0, 0}, /* / */ + {13, 34}, /* 0 */ + {13, 68}, /* 1 */ + {13, 102}, /* 2 */ + {13, 136}, /* 3 */ + {13, 170}, /* 4 */ + {13, 204}, /* 5 */ + {13, 238}, /* 6 */ + {13, 272}, /* 7 */ + {13, 306}, /* 8 */ + {13, 340}, /* 9 */ + {0, 0}, /* : */ + {0, 0}, /* ; */ + {0, 0}, /* < */ + {0, 0}, /* = */ + {0, 0}, /* > */ + {0, 0}, /* ? */ + {0, 0}, /* @ */ + {0, 0}, /* A */ + {13, 374}, /* B */ + {13, 408}, /* C */ + {13, 442}, /* D */ + {0, 0}, /* E */ + {13, 476}, /* F */ + {13, 510}, /* G */ + {13, 544}, /* H */ + {0, 0}, /* I */ + {13, 578}, /* J */ + {13, 612}, /* K */ + {0, 0}, /* L */ + {13, 646}, /* M */ + {13, 680}, /* N */ + {0, 0}, /* O */ + {13, 714}, /* P */ + {13, 748}, /* Q */ + {13, 782}, /* R */ + {0, 0}, /* S */ + {13, 816}, /* T */ + {0, 0}, /* U */ + {13, 850}, /* V */ + {13, 884}, /* W */ + {13, 918}, /* X */ + {13, 952}, /* Y */ +}; + +/* Font information for {PixelFlag} 18pt */ +const FONT_INFO pixelFlag_18ptFontInfo = { + 17, /* Character height */ + '-', /* Start character */ + 'Y', /* End character */ + 0, /* Width, in pixels, of space character */ + pixelFlag_18ptDescriptors, /* Character descriptor array */ + pixelFlag_18ptBitmaps, /* Character bitmap array */ +}; diff --git a/applications/external/totp/ui/fonts/pixelflag/pixelflag.h b/applications/external/totp/ui/fonts/pixelflag/pixelflag.h new file mode 100644 index 000000000..dc339c84d --- /dev/null +++ b/applications/external/totp/ui/fonts/pixelflag/pixelflag.h @@ -0,0 +1,7 @@ +#pragma once + +/* GENERATED BY https://github.com/pavius/the-dot-factory */ + +#include "../font_info.h" + +extern const FONT_INFO pixelFlag_18ptFontInfo; \ No newline at end of file diff --git a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c index 0bdc7aee3..bf76b7c82 100644 --- a/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c +++ b/applications/external/totp/ui/scenes/app_settings/totp_app_settings.c @@ -250,7 +250,7 @@ bool totp_scene_app_settings_handle_event( #endif else if(scene_state->selected_control == FontSelector) { totp_roll_value_uint8_t( - &scene_state->selected_font, 1, 0, 6, RollOverflowBehaviorStop); + &scene_state->selected_font, 1, 0, MAX_CUSTOM_FONTS, RollOverflowBehaviorStop); } break; case InputKeyLeft: @@ -274,7 +274,7 @@ bool totp_scene_app_settings_handle_event( #endif else if(scene_state->selected_control == FontSelector) { totp_roll_value_uint8_t( - &scene_state->selected_font, -1, 0, 6, RollOverflowBehaviorStop); + &scene_state->selected_font, -1, 0, MAX_CUSTOM_FONTS, RollOverflowBehaviorStop); } break; case InputKeyOk: diff --git a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c index e55f34ea2..da99623fd 100644 --- a/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c +++ b/applications/external/totp/ui/scenes/generate_token/totp_scene_generate_token.c @@ -165,6 +165,15 @@ static void draw_totp_code(Canvas* const canvas, const PluginState* const plugin case 6: current_font = &karmaFuture_14ptFontInfo; break; + case 7: + current_font = &funclimbingDemo_18ptFontInfo; + break; + case 8: + current_font = &dPComic_18ptFontInfo; + break; + case 9: + current_font = &pixelFlag_18ptFontInfo; + break; default: current_font = &modeNine_15ptFontInfo; break; @@ -222,6 +231,15 @@ static void on_new_token_code_generated(bool time_left, void* context) { case 6: current_font = &karmaFuture_14ptFontInfo; break; + case 7: + current_font = &funclimbingDemo_18ptFontInfo; + break; + case 8: + current_font = &dPComic_18ptFontInfo; + break; + case 9: + current_font = &pixelFlag_18ptFontInfo; + break; default: current_font = &modeNine_15ptFontInfo; break; diff --git a/applications/external/uart_terminal/scenes/uart_terminal_scene_start.c b/applications/external/uart_terminal/scenes/uart_terminal_scene_start.c index d4de748b6..60411b34c 100644 --- a/applications/external/uart_terminal/scenes/uart_terminal_scene_start.c +++ b/applications/external/uart_terminal/scenes/uart_terminal_scene_start.c @@ -28,7 +28,7 @@ const UART_TerminalItem items[NUM_MENU_ITEMS] = { 9, {"115200", "2400", "9600", "19200", "38400", "57600", "230400", "460800", "921600"}, NO_ARGS, - FOCUS_CONSOLE_TOGGLE, + FOCUS_CONSOLE_END, NO_TIP}, {"Send command", {""}, 1, {""}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP}, {"Send AT command", {""}, 1, {"AT"}, INPUT_ARGS, FOCUS_CONSOLE_END, NO_TIP}, diff --git a/applications/external/wifi_marauder_companion/wifi_marauder_app.h b/applications/external/wifi_marauder_companion/wifi_marauder_app.h index 5457f89d8..3a342bbba 100644 --- a/applications/external/wifi_marauder_companion/wifi_marauder_app.h +++ b/applications/external/wifi_marauder_companion/wifi_marauder_app.h @@ -4,7 +4,7 @@ extern "C" { #endif -#define WIFI_MARAUDER_APP_VERSION "v0.3.7" +#define WIFI_MARAUDER_APP_VERSION "v0.4.0" typedef struct WifiMarauderApp WifiMarauderApp; diff --git a/applications/main/infrared/scenes/infrared_scene_universal_ac.c b/applications/main/infrared/scenes/infrared_scene_universal_ac.c index 68a6ea942..58f067735 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_ac.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_ac.c @@ -11,7 +11,6 @@ void infrared_scene_universal_ac_on_enter(void* context) { infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/ac.ir")); - //TODO Improve A/C universal remote button_panel_reserve(button_panel, 2, 3); uint32_t i = 0; button_panel_add_item( @@ -20,77 +19,74 @@ void infrared_scene_universal_ac_on_enter(void* context) { 0, 0, 3, - 24, - &I_Power_25x27, - &I_Power_hvr_25x27, + 22, + &I_Off_25x27, + &I_Off_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Off"); button_panel_add_item( button_panel, i, 1, 0, 36, - 24, - &I_Mode_25x27, - &I_Mode_hvr_25x27, + 22, + &I_Dehumidify_25x27, + &I_Dehumidify_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MODE"); + infrared_brute_force_add_record(brute_force, i++, "Dh"); button_panel_add_item( button_panel, i, 0, 1, 3, - 66, - &I_Vol_up_25x27, - &I_Vol_up_hvr_25x27, + 59, + &I_CoolHi_25x27, + &I_CoolHi_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "TEMP+"); + infrared_brute_force_add_record(brute_force, i++, "Cool_hi"); button_panel_add_item( button_panel, i, 1, 1, 36, - 66, - &I_Vol_down_25x27, - &I_Vol_down_hvr_25x27, + 59, + &I_HeatHi_25x27, + &I_HeatHi_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "TEMP-"); + infrared_brute_force_add_record(brute_force, i++, "Heat_hi"); button_panel_add_item( button_panel, i, 0, 2, 3, - 98, - &I_Swing_25x27, - &I_Swing_hvr_25x27, + 91, + &I_CoolLo_25x27, + &I_CoolLo_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "SWING"); + infrared_brute_force_add_record(brute_force, i++, "Cool_lo"); button_panel_add_item( button_panel, i, 1, 2, 36, - 98, - &I_Timer_25x27, - &I_Timer_hvr_25x27, + 91, + &I_HeatLo_25x27, + &I_HeatLo_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "TIMER"); + infrared_brute_force_add_record(brute_force, i++, "Heat_lo"); - button_panel_add_label(button_panel, 6, 11, FontPrimary, "AC remote"); - button_panel_add_label(button_panel, 20, 63, FontSecondary, "Temp"); - button_panel_add_label(button_panel, 8, 23, FontSecondary, "Pwr"); - button_panel_add_label(button_panel, 40, 23, FontSecondary, "Mod"); + button_panel_add_label(button_panel, 6, 10, FontPrimary, "AC remote"); view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); diff --git a/applications/main/infrared/scenes/infrared_scene_universal_audio.c b/applications/main/infrared/scenes/infrared_scene_universal_audio.c index d3b7e083b..00c86fff4 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_audio.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_audio.c @@ -10,8 +10,8 @@ void infrared_scene_universal_audio_on_enter(void* context) { InfraredBruteForce* brute_force = infrared->brute_force; infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/audio.ir")); - //TODO Improve Audio universal remote - button_panel_reserve(button_panel, 2, 2); + + button_panel_reserve(button_panel, 2, 4); uint32_t i = 0; button_panel_add_item( button_panel, @@ -19,51 +19,98 @@ void infrared_scene_universal_audio_on_enter(void* context) { 0, 0, 3, - 19, + 11, &I_Power_25x27, &I_Power_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Power"); button_panel_add_item( button_panel, i, 1, 0, 36, - 19, + 11, &I_Mute_25x27, &I_Mute_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MUTE"); + infrared_brute_force_add_record(brute_force, i++, "Mute"); button_panel_add_item( button_panel, i, 0, 1, 3, - 64, - &I_Vol_up_25x27, - &I_Vol_up_hvr_25x27, + 41, + &I_Play_25x27, + &I_Play_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL+"); + infrared_brute_force_add_record(brute_force, i++, "Play"); button_panel_add_item( button_panel, i, 1, 1, 36, - 64, + 41, + &I_Pause_25x27, + &I_Pause_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Pause"); + button_panel_add_item( + button_panel, + i, + 0, + 2, + 3, + 71, + &I_TrackPrev_25x27, + &I_TrackPrev_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Prev"); + button_panel_add_item( + button_panel, + i, + 1, + 2, + 36, + 71, + &I_TrackNext_25x27, + &I_TrackNext_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Next"); + button_panel_add_item( + button_panel, + i, + 0, + 3, + 3, + 101, &I_Vol_down_25x27, &I_Vol_down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL-"); + infrared_brute_force_add_record(brute_force, i++, "Vol_dn"); + button_panel_add_item( + button_panel, + i, + 1, + 3, + 36, + 101, + &I_Vol_up_25x27, + &I_Vol_up_hvr_25x27, + infrared_scene_universal_common_item_callback, + context); + infrared_brute_force_add_record(brute_force, i++, "Vol_up"); - button_panel_add_label(button_panel, 5, 11, FontSecondary, "Audio remote"); - button_panel_add_label(button_panel, 17, 60, FontSecondary, "Volume"); + button_panel_add_label(button_panel, 1, 8, FontPrimary, "Mus. remote"); view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); diff --git a/applications/main/infrared/scenes/infrared_scene_universal_fan.c b/applications/main/infrared/scenes/infrared_scene_universal_fan.c index 37657ac3c..967e15c24 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_fan.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_fan.c @@ -25,7 +25,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Power_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Power"); button_panel_add_item( button_panel, i, @@ -37,7 +37,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Mode_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MODE"); + infrared_brute_force_add_record(brute_force, i++, "Mode"); button_panel_add_item( button_panel, i, @@ -49,7 +49,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Vol_up_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "SPEED+"); + infrared_brute_force_add_record(brute_force, i++, "Speed_up"); button_panel_add_item( button_panel, i, @@ -61,7 +61,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Vol_down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "SPEED-"); + infrared_brute_force_add_record(brute_force, i++, "Speed_dn"); button_panel_add_item( button_panel, i, @@ -73,7 +73,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Rotate_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "ROTATE"); + infrared_brute_force_add_record(brute_force, i++, "Rotate"); button_panel_add_item( button_panel, i, @@ -85,7 +85,7 @@ void infrared_scene_universal_fan_on_enter(void* context) { &I_Timer_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "TIMER"); + infrared_brute_force_add_record(brute_force, i++, "Timer"); button_panel_add_label(button_panel, 5, 11, FontPrimary, "Fan remote"); button_panel_add_label(button_panel, 20, 63, FontSecondary, "Speed"); diff --git a/applications/main/infrared/scenes/infrared_scene_universal_projector.c b/applications/main/infrared/scenes/infrared_scene_universal_projector.c index 11a0077f5..32d84dde6 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_projector.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_projector.c @@ -24,7 +24,7 @@ void infrared_scene_universal_projector_on_enter(void* context) { &I_Power_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Power"); button_panel_add_item( button_panel, i, @@ -36,7 +36,7 @@ void infrared_scene_universal_projector_on_enter(void* context) { &I_Mute_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MUTE"); + infrared_brute_force_add_record(brute_force, i++, "Mute"); button_panel_add_item( button_panel, i, @@ -48,7 +48,7 @@ void infrared_scene_universal_projector_on_enter(void* context) { &I_Vol_up_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL+"); + infrared_brute_force_add_record(brute_force, i++, "Vol_up"); button_panel_add_item( button_panel, i, @@ -60,7 +60,7 @@ void infrared_scene_universal_projector_on_enter(void* context) { &I_Vol_down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL-"); + infrared_brute_force_add_record(brute_force, i++, "Vol_dn"); button_panel_add_label(button_panel, 10, 11, FontPrimary, "Projector"); button_panel_add_label(button_panel, 17, 60, FontSecondary, "Volume"); diff --git a/applications/main/infrared/scenes/infrared_scene_universal_tv.c b/applications/main/infrared/scenes/infrared_scene_universal_tv.c index 583f21fa3..e21bf8f90 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal_tv.c +++ b/applications/main/infrared/scenes/infrared_scene_universal_tv.c @@ -24,7 +24,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Power_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "POWER"); + infrared_brute_force_add_record(brute_force, i++, "Power"); button_panel_add_item( button_panel, i, @@ -36,7 +36,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Mute_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "MUTE"); + infrared_brute_force_add_record(brute_force, i++, "Mute"); button_panel_add_item( button_panel, i, @@ -48,7 +48,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Vol_up_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL+"); + infrared_brute_force_add_record(brute_force, i++, "Vol_up"); button_panel_add_item( button_panel, i, @@ -60,7 +60,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Up_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "CH+"); + infrared_brute_force_add_record(brute_force, i++, "Ch_next"); button_panel_add_item( button_panel, i, @@ -72,7 +72,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Vol_down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "VOL-"); + infrared_brute_force_add_record(brute_force, i++, "Vol_dn"); button_panel_add_item( button_panel, i, @@ -84,7 +84,7 @@ void infrared_scene_universal_tv_on_enter(void* context) { &I_Down_hvr_25x27, infrared_scene_universal_common_item_callback, context); - infrared_brute_force_add_record(brute_force, i++, "CH-"); + infrared_brute_force_add_record(brute_force, i++, "Ch_prev"); button_panel_add_label(button_panel, 6, 11, FontPrimary, "TV remote"); button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol"); diff --git a/applications/main/lfrfid/helpers/rfid_writer.c b/applications/main/lfrfid/helpers/rfid_writer.c deleted file mode 100644 index 7cc6326c4..000000000 --- a/applications/main/lfrfid/helpers/rfid_writer.c +++ /dev/null @@ -1,96 +0,0 @@ -#include "rfid_writer.h" -#include - -void writer_start() { - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read_start(); - - // do not ground the antenna - furi_hal_rfid_pin_pull_release(); -} - -void writer_stop() { - furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); - furi_hal_rfid_pins_reset(); -} - -void write_gap(uint32_t gap_time) { - furi_hal_rfid_tim_read_stop(); - furi_delay_us(gap_time * 8); - furi_hal_rfid_tim_read_start(); -} - -void write_bit(T55xxTiming* t55xxtiming, bool value) { - if(value) { - furi_delay_us(t55xxtiming->data_1 * 8); - } else { - furi_delay_us(t55xxtiming->data_0 * 8); - } - write_gap(t55xxtiming->write_gap); -} - -void write_block( - T55xxTiming* t55xxtiming, - uint8_t page, - uint8_t block, - bool lock_bit, - uint32_t data, - bool password_enable, - uint32_t password) { - furi_delay_us(t55xxtiming->wait_time * 8); - - //client: https://github.com/Proxmark/proxmark3/blob/6116334485ca77343eda51c557cdc81032afcf38/client/cmdlft55xx.c#L944 - //hardware: https://github.com/Proxmark/proxmark3/blob/555fa197730c061bbf0ab01334e99bc47fb3dc06/armsrc/lfops.c#L1465 - //hardware: https://github.com/Proxmark/proxmark3/blob/555fa197730c061bbf0ab01334e99bc47fb3dc06/armsrc/lfops.c#L1396 - - // start gap - write_gap(t55xxtiming->start_gap); - - // opcode - switch(page) { - case 0: - write_bit(t55xxtiming, 1); - write_bit(t55xxtiming, 0); - break; - case 1: - write_bit(t55xxtiming, 1); - write_bit(t55xxtiming, 1); - break; - default: - furi_check(false); - break; - } - - // password - if(password_enable) { - for(uint8_t i = 0; i < 32; i++) { - write_bit(t55xxtiming, (password >> (31 - i)) & 1); - } - } - - // lock bit - write_bit(t55xxtiming, lock_bit); - - // data - for(uint8_t i = 0; i < 32; i++) { - write_bit(t55xxtiming, (data >> (31 - i)) & 1); - } - - // block address - write_bit(t55xxtiming, (block >> 2) & 1); - write_bit(t55xxtiming, (block >> 1) & 1); - write_bit(t55xxtiming, (block >> 0) & 1); - - furi_delay_us(t55xxtiming->program * 8); - - furi_delay_us(t55xxtiming->wait_time * 8); - write_reset(t55xxtiming); -} - -void write_reset(T55xxTiming* t55xxtiming) { - write_gap(t55xxtiming->start_gap); - write_bit(t55xxtiming, 1); - write_bit(t55xxtiming, 0); -} \ No newline at end of file diff --git a/applications/main/lfrfid/helpers/rfid_writer.h b/applications/main/lfrfid/helpers/rfid_writer.h deleted file mode 100644 index 2b97bd321..000000000 --- a/applications/main/lfrfid/helpers/rfid_writer.h +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include - -typedef struct { - uint16_t wait_time; - uint8_t start_gap; - uint8_t write_gap; - uint8_t data_0; - uint8_t data_1; - uint16_t program; -} T55xxTiming; - -void writer_start(); -void writer_stop(); -void write_gap(uint32_t gap_time); -void write_bit(T55xxTiming* t55xxtiming, bool value); -void write_block( - T55xxTiming* t55xxtiming, - uint8_t page, - uint8_t block, - bool lock_bit, - uint32_t data, - bool password_enable, - uint32_t password); - -void write_reset(T55xxTiming* t55xxtiming); \ No newline at end of file diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c index 1c4cae3c6..c58bf9e4f 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c @@ -1,17 +1,7 @@ #include "../lfrfid_i.h" -#include "../helpers/rfid_writer.h" - -static void writer_initialize(T55xxTiming* t55xxtiming) { - t55xxtiming->wait_time = 400; - t55xxtiming->start_gap = 30; - t55xxtiming->write_gap = 18; - t55xxtiming->data_0 = 24; - t55xxtiming->data_1 = 56; - t55xxtiming->program = 700; -} +#define TAG "Clear T5577" static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) { - T55xxTiming* t55xxtiming = malloc(sizeof(T55xxTiming)); Popup* popup = app->popup; char curr_buf[32] = {}; @@ -36,30 +26,27 @@ static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) { 0x07d7bb0b, 0x9636ef8f, 0xb5f44686, 0x9E3779B9, 0xC6EF3720, 0x7854794A, 0xF1EA5EED, 0x69314718, 0x57721566, 0x93C467E3, 0x27182818, 0x50415353}; const uint8_t default_passwords_len = sizeof(default_passwords) / sizeof(uint32_t); - const uint32_t em_config_block_data = - 0b00000000000101001000000001000000; //no pwd&aor config block - - writer_initialize(t55xxtiming); popup_set_header(popup, "Removing\npassword", 90, 36, AlignCenter, AlignCenter); popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); popup_set_text(popup, curr_buf, 90, 56, AlignCenter, AlignCenter); notification_message(app->notifications, &sequence_blink_start_magenta); + LFRFIDT5577 data = { + .block[0] = 0b00000000000101001000000001000000, + .blocks_to_write = 1, + }; + for(uint8_t i = 0; i < default_passwords_len; i++) { - FURI_CRITICAL_ENTER(); snprintf(curr_buf, sizeof(curr_buf), "Pass %d of %d", i, default_passwords_len); view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup); - writer_start(); - write_block(t55xxtiming, 0, 0, false, em_config_block_data, true, default_passwords[i]); - write_reset(t55xxtiming); - writer_stop(); - FURI_CRITICAL_EXIT(); + + t5577_write_with_pass(&data, default_passwords[i]); furi_delay_ms(8); } + notification_message(app->notifications, &sequence_blink_stop); popup_reset(app->popup); - free(t55xxtiming); } void lfrfid_scene_clear_t5577_on_enter(void* context) { diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index f7ec3feb6..8b4c47e26 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -53,7 +53,7 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { furi_string_cat_printf( temp_str, "\e#%s\n", nfc_mf_classic_type(dev_data->mf_classic_data.type)); } else if(protocol == NfcDeviceProtocolMifareDesfire) { - furi_string_cat_printf(temp_str, "\e#MIFARE DESfire\n"); + furi_string_cat_printf(temp_str, "\e#MIFARE DESFire\n"); } else if(protocol == NfcDeviceProtocolNfcV) { switch(dev_data->nfcv_data.sub_type) { case NfcVTypePlain: diff --git a/applications/main/subghz/helpers/subghz_txrx.c b/applications/main/subghz/helpers/subghz_txrx.c index c1f519ba0..3275b7288 100644 --- a/applications/main/subghz/helpers/subghz_txrx.c +++ b/applications/main/subghz/helpers/subghz_txrx.c @@ -1,5 +1,6 @@ #include "subghz_txrx_i.h" #include +#include #define TAG "SubGhz" @@ -557,6 +558,13 @@ bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance) { return instance->debug_pin_state; } +void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance) { + furi_assert(instance); + subghz_environment_reset_keeloq(instance->environment); + + subghz_custom_btns_reset(); +} + SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance) { furi_assert(instance); return instance->receiver; diff --git a/applications/main/subghz/helpers/subghz_txrx.h b/applications/main/subghz/helpers/subghz_txrx.h index 75a614b5c..8aa717684 100644 --- a/applications/main/subghz/helpers/subghz_txrx.h +++ b/applications/main/subghz/helpers/subghz_txrx.h @@ -297,6 +297,8 @@ void subghz_txrx_set_raw_file_encoder_worker_callback_end( void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state); bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance); +void subghz_txrx_reset_dynamic_and_custom_btns(SubGhzTxRx* instance); + SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance); // TODO use only in DecodeRaw #ifdef __cplusplus diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 2d89de731..e3ff485d2 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -1,7 +1,5 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -#include -#include #include @@ -108,7 +106,6 @@ void subghz_scene_receiver_info_draw_widget(SubGhz* subghz) { void subghz_scene_receiver_info_on_enter(void* context) { SubGhz* subghz = context; - keeloq_reset_original_btn(); subghz_custom_btns_reset(); subghz_scene_receiver_info_draw_widget(subghz); @@ -191,10 +188,5 @@ void subghz_scene_receiver_info_on_exit(void* context) { SubGhz* subghz = context; widget_reset(subghz->widget); - keeloq_reset_mfname(); - keeloq_reset_kl_type(); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); - star_line_reset_mfname(); - star_line_reset_kl_type(); + subghz_txrx_reset_dynamic_and_custom_btns(subghz->txrx); } diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index abff9c55a..4e99729f1 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -1,6 +1,4 @@ #include "../subghz_i.h" -#include -#include #include @@ -109,10 +107,5 @@ void subghz_scene_rpc_on_exit(void* context) { popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); popup_set_icon(popup, 0, 0, NULL); - keeloq_reset_mfname(); - keeloq_reset_kl_type(); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); - star_line_reset_mfname(); - star_line_reset_kl_type(); + subghz_txrx_reset_dynamic_and_custom_btns(subghz->txrx); } diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index e5b53ad25..010c81e1a 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -2,8 +2,6 @@ #include "../views/transmitter.h" #include #include -#include -#include #include @@ -53,7 +51,6 @@ void fav_timer_callback(void* context) { void subghz_scene_transmitter_on_enter(void* context) { SubGhz* subghz = context; - keeloq_reset_original_btn(); subghz_custom_btns_reset(); if(!subghz_scene_transmitter_update_data_show(subghz)) { @@ -136,10 +133,6 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { void subghz_scene_transmitter_on_exit(void* context) { SubGhz* subghz = context; subghz->state_notifications = SubGhzNotificationStateIDLE; - keeloq_reset_mfname(); - keeloq_reset_kl_type(); - keeloq_reset_original_btn(); - subghz_custom_btns_reset(); - star_line_reset_mfname(); - star_line_reset_kl_type(); + + subghz_txrx_reset_dynamic_and_custom_btns(subghz->txrx); } diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index a9640699e..956a1cbf8 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -43,11 +43,32 @@ static void desktop_lock_icon_draw_callback(Canvas* canvas, void* context) { canvas_draw_icon(canvas, 0, 0, &I_Lock_7x8); } -static void desktop_toggle_clock_view(Desktop* desktop, bool is_enabled) { +static void desktop_clock_upd_time(Desktop* desktop, bool forced) { furi_assert(desktop); - // clock type upd after 1 minute - desktop->clock_type = (locale_get_time_format() == LocaleTimeFormat24h); + FuriHalRtcDateTime curr_dt; + furi_hal_rtc_get_datetime(&curr_dt); + + if(forced) { + desktop->clock_type = (locale_get_time_format() == LocaleTimeFormat24h); + } + + if(forced || (desktop->minute != curr_dt.minute)) { + if(desktop->clock_type) { + desktop->hour = curr_dt.hour; + } else { + desktop->hour = (curr_dt.hour > 12) ? curr_dt.hour - 12 : + ((curr_dt.hour == 0) ? 12 : curr_dt.hour); + } + desktop->minute = curr_dt.minute; + view_port_update(desktop->clock_viewport); + } +} + +static void desktop_clock_toggle_view(Desktop* desktop, bool is_enabled) { + furi_assert(desktop); + + desktop_clock_upd_time(desktop, true); if(is_enabled) { // && !furi_timer_is_running(desktop->update_clock_timer)) { furi_timer_start(desktop->update_clock_timer, furi_ms_to_ticks(1000)); @@ -135,7 +156,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { // locking and unlocking DESKTOP_SETTINGS_LOAD(&desktop->settings); - desktop_toggle_clock_view(desktop, desktop->settings.display_clock); + desktop_clock_toggle_view(desktop, desktop->settings.display_clock); desktop_auto_lock_arm(desktop); return true; @@ -202,24 +223,12 @@ static void desktop_auto_lock_inhibit(Desktop* desktop) { } } -static void desktop_update_clock_timer_callback(void* context) { +static void desktop_clock_timer_callback(void* context) { furi_assert(context); Desktop* desktop = context; if(gui_get_count_of_enabled_view_port_in_layer(desktop->gui, GuiLayerStatusBarLeft) < 6) { - FuriHalRtcDateTime curr_dt; - furi_hal_rtc_get_datetime(&curr_dt); - - if(desktop->minute != curr_dt.minute) { - if(desktop->clock_type) { - desktop->hour = curr_dt.hour; - } else { - desktop->hour = (curr_dt.hour > 12) ? curr_dt.hour - 12 : - ((curr_dt.hour == 0) ? 12 : curr_dt.hour); - } - desktop->minute = curr_dt.minute; - view_port_update(desktop->clock_viewport); - } + desktop_clock_upd_time(desktop, false); view_port_enabled_set(desktop->clock_viewport, true); } else { @@ -403,18 +412,12 @@ Desktop* desktop_alloc() { desktop->status_pubsub = furi_pubsub_alloc(); desktop->update_clock_timer = - furi_timer_alloc(desktop_update_clock_timer_callback, FuriTimerTypePeriodic, desktop); + furi_timer_alloc(desktop_clock_timer_callback, FuriTimerTypePeriodic, desktop); FuriHalRtcDateTime curr_dt; furi_hal_rtc_get_datetime(&curr_dt); - if(desktop->clock_type) { - desktop->hour = curr_dt.hour; - } else { - desktop->hour = (curr_dt.hour > 12) ? curr_dt.hour - 12 : - ((curr_dt.hour == 0) ? 12 : curr_dt.hour); - } - desktop->minute = curr_dt.minute; + desktop_clock_upd_time(desktop, true); furi_record_create(RECORD_DESKTOP, desktop); @@ -460,7 +463,7 @@ int32_t desktop_srv(void* p) { DESKTOP_SETTINGS_SAVE(&desktop->settings); } - desktop_toggle_clock_view(desktop, desktop->settings.display_clock); + desktop_clock_toggle_view(desktop, desktop->settings.display_clock); scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index 2989cf2fb..4dc3eac48 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -265,7 +265,7 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str(canvas, 2, 8, model->header); elements_slightly_rounded_frame(canvas, 1, 12, 126, 15); - char buf[model->text_buffer_size + 1]; + char buf[text_length + 1]; if(model->text_buffer) { strlcpy(buf, model->text_buffer, sizeof(buf)); } diff --git a/applications/external/subghz_remote/subghz_remote_10px.png b/assets/icons/Archive/subrem_10px.png similarity index 100% rename from applications/external/subghz_remote/subghz_remote_10px.png rename to assets/icons/Archive/subrem_10px.png diff --git a/assets/icons/Infrared/CoolHi_25x27.png b/assets/icons/Infrared/CoolHi_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..cea29a5b9e764c88ae56f305368568d04e544876 GIT binary patch literal 3680 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/CoolHi_hvr_25x27.png b/assets/icons/Infrared/CoolHi_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..692ac7b8be718dfe02b460c9ce9a710857feb562 GIT binary patch literal 3669 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/CoolLo_25x27.png b/assets/icons/Infrared/CoolLo_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..23288e44f158d4034bebfd6a2a9005514b132a9d GIT binary patch literal 3676 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/CoolLo_hvr_25x27.png b/assets/icons/Infrared/CoolLo_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..ae5316e4d49992b01a39a4298e36cac1fd365388 GIT binary patch literal 3657 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 P_yK!sCtMlE=iI*m`3F!x literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Dehumidify_25x27.png b/assets/icons/Infrared/Dehumidify_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..dca77ae410bcc2196a693023640372da1b1912ea GIT binary patch literal 3665 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 Y0_*BPx59$cJUb46GqS>#p?%qL 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 Tfe|}@hk%WR1FiydCgT49&LB(v literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/HeatHi_25x27.png b/assets/icons/Infrared/HeatHi_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..a1724f995562587ec54740789f37729d567e0f88 GIT binary patch literal 3676 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/HeatHi_hvr_25x27.png b/assets/icons/Infrared/HeatHi_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..b92108d68de2ab09bed6b451e36396881e5611ea GIT binary patch literal 3661 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 T-|@M}j{(?QJ7Y`Hry~9hE1FGt literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/HeatLo_25x27.png b/assets/icons/Infrared/HeatLo_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..af2e59d4940aefa657c280acb8073800408dabba GIT binary patch literal 3670 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 O0dr$(Y#G`u;{O0;Ay2me literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Off_25x27.png b/assets/icons/Infrared/Off_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..c15100606ac9b2c46fec8d5ed290d72345fb22e2 GIT binary patch literal 9530 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 T&A>rCE`gSso@%+Wb;y4K-_9ky literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Off_hvr_25x27.png b/assets/icons/Infrared/Off_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..d5e5e6f45d78e070d06e033bd529d0067de94301 GIT binary patch literal 8460 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Pause_25x27.png b/assets/icons/Infrared/Pause_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..a371ba81718e864efe908e61f34bc842079cc20d GIT binary patch literal 3634 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 literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Pause_hvr_25x27.png b/assets/icons/Infrared/Pause_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..472d583db0ff9adc5ef810675c8b915c6e5a899c GIT binary patch literal 3623 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 HpN{x9W3^Ap literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/Play_hvr_25x27.png b/assets/icons/Infrared/Play_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..6708dcdbf2c7ac0c656bbb1c2441fb0f4d6fc9c5 GIT binary patch literal 3643 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 diff --git a/assets/icons/Infrared/TrackNext_25x27.png b/assets/icons/Infrared/TrackNext_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..7b8f283915e45ba2289fbee3ff5413fea15fb461 GIT binary patch literal 3651 zcmaJ^c{o(>+dsBKS&}6rV?>K(W-P^I?8~STjcrt_F$TkI%?xIQENPQ1Th@e<8rqae zwxp0PiiEOcNoYt+vi-*Q_pSH+PT85Co`Qx;teWhSs7hoHX45P!cc*mKon9kcb8vbzK@| zfyQmXedkBs;y?-j5Luy?VBn4fF!jUUR0QZLPVQF#dh)jyivn>1K*nynor31ifK#rK zXl=pTIv|g24%QW}Eft9Hc%o+~7*Qnx1jS<#rOZzO5gC@+Eda@wN(g&63T;i z)(jS(q{eWN0zhqZYHRwTPJLNU>Kmot?=yqLYQuHJ2bNfcJ<>j6BjD`xEcLC(aUoRO zW&luH?0CLvWR^HSHZnBkGfw3Gc$vQ%Fhc>Gs?83pR$dVl2BZ(Sb9+yYj&=)C8wBnL z)&vwE1A5&6zkx+h{XVh0qvCHu7GqgP%jP?BZ#XrYsB9PCv}szy>qZsybFAr_{t#s_ zHhh8qbhR&J1~{E*o>5X;5WR95OAabU$B#D)Tf)e^arM=Pn6oSKdpd><9vs(}yF81z z#Bl;UG_ancldRR6Qio+G&g#vormcu22TK6#^NzKLpKN^GOsoz6CLkCqiRlai%){q& zt|)Cv0;GKn^jJIqNUm8-FxL_QTGIGc(cJUkA(kv8RYT-S?kM9d9L=Kn4(YIUX0$0h9E(@&SAN$_1NKmoQ424f42AjGMj<24pz4doP67{Od~{Qv7YG# ze~^f=Wov#@+o6`LablO`)|1J|osvygM-GdtX(Z~|Z?X?S_91l&oeNDnr3u+6&B;Vk z)29*9hY@U0dQy3!RHEb6rKT4n<+AXX7l%<|`8&~tDKZBQ@n)mKH?QkiX5`&D(psGR zPV~-2`1Paqq`V*}i1UTwtpZ2()q}wq;}6*f+tk`5+Ro?*>6qy}==Lx1DG4vx z-y70f-Rm_?o0gxR?BxbhbIfzJbLQbBI4@AFVqe9PikOPN!1k}EZ*h~X39>hU0 zRJ?Ilc0ew+`a@;ka$L+!o9vedWB0{2r1hqSHjAV=r199-+)UkAZu4&M+4kMXC$%R@ z-R?vuW%sPjS@5jpC$~$oO6r5MNCUFNvI%=S_slz!dtp<{Q{q#ZQyZp@7qAN&3#5g1 zm6q)?D%}Sd2SRC#z?L8)wQ{m>$lyhBeesJ4cVA`S8}ytxLxo$15}RexgVGh8Nkx~7 z$k#)fQ%9A)RdhanJ719XEUUld1L@tz7R1Z2yGstbS;|eGFA!XdA2U46@adM%IYn7T zb#sa1kP|^CJWecC?QndQt(n^mB{lZd9~-P{K646giopMBn-DU6Wh!_*#{GZT* zeA)g)G!ZwI#fjkD;Y2bo{Ir=(mtkz(DK>p+q`s#fap^N%aGaQ_pFNW4lE%Q5j`rt2 zRT!ISYt9We@i6pA3^j_mCX@cqY&05V=>*y4I9fz@P}%zZTvm*uO?7@;{*edeoP#D; z$8y|K7mPk02($X-ciz!9@Rh!pBU+1Le+Tg51_(9@}<|$w5{j zkG|6%@LB!3sJ%VEOCmN#tbVB$>_gsJVBr%HN{v&G{LL66M*rQRS1Q zgP#~TLj33BTgzHsw+b0z4X2N_JYn~Jzp<}iAtdLlXS3T%$=&km51PH*H6Me|%t=P8 z$Q}5^O_{2Eti^N>sIm#0CwG2}`k0{PrCd=n7XFcA7wq^lH{s09GaDCdxRd@23bFrQ zP0d3w5_(_U4kVm9niWCm&6>^(eoQ^OSF+Ax^!cuVTcKw@JAJv)_M-nq>p;fY@_Ero zBulFkUK7aHDInz`Zd7rxUZ&^%gLG_w{tWq=6?n) zOe+M7e?#?qh9ofWEm!xheBJm<>g(CE)d%=m(%{ciwWr!&ct~+2#V+KormVfaFw|++ zV%Mc^s~(q-qpGSbp;YzVyDfRB=wZ>;_SfNVYphB7-SL5y;iW_EnB|_CO^dPZHKnZL zIU4tF@jZBhdV^|Z8w)XeYq_MYFO19KRtz*$sb=h6HeYp`>-dFhD0<__GaV0IU54<^ z%`HV3YiwEnzGT>77|s+QMlhC!2Q0iPUU-l_3G0hTT>M;Few*S8^H&_57H00R8qpfCHu%#Uyjr9z)L3&Wweh73w1g5V8g~6fw;QGd(e=jiK8_nAXj<&Y_ z*B5_<0Q)f*R5%0@92~40tglO<`9fgE#>Nn+9z;)1hmX*qv&alAQ-@4f|E*w+r{ib@ zDuX~FgVq(XUX(xv0?d!}zbTNYe`Lw@e~*cOU=Svj3W4cD*Hiipba43pp(N5DG@XIQ z|4+RCr!d`xMa4tVcseDJhT|8`M}6HD6>detV;K~h3xz`beTq(g6b6OvN1=lFe-OLf z31n|dFn!NIa0dstJ(`im0)-#qK)pRVOE{`5Vb%x`uYzpIVR>%sgtVuKUP z#b#}7jc>Zvy$$D2?)KIeF3jHSP7BFekf=z98Lx&>K=MDDA@ZU}#OlZIW; zYaf(sSJQYCr&l)Vat5Q;hq}lgT3>>D*N)^wp-Qu#5F5V|FVMEQ=g1uw+zj}53CJkC SxG~3f0odCdwl1|i74;vAA8iN# literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/TrackNext_hvr_25x27.png b/assets/icons/Infrared/TrackNext_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..a4de4fc3cbe582349b8c79bbb7ec6e931e8bc792 GIT binary patch literal 3639 zcmaJ^c|26@+dsBKS+a&?jCd-`7+XxnzKpVtZHO|)U@%KFgBeL8ZHkdCYeI>JHf55n zQfMquB$OpfLPJ9KcRatR=lA~c_MXq@-1l|g=llI$*L7dl`Fzf~DtKbOp6J-}#?}e|5lJY9n3*3Cn`NQV3V;lG0n5FTZG0emz5?y8 z`k~Sjqy!d%2WViYw`Csf(v@PRzm<>tF*`J(Jn|y!fdyLjfOw$LC^$DWM@14b!DrvT z69D9wJD+bDnldKFM~BA)C&D;CUlneI&Jw{U%5#GoHCK4~0ddC;PTz^Ku^v8B6VLtd z`q0v2K%WN?Jh<$u+b>k$E&MiWIgxI-X0|u~rgO8g;vV50J7!eE5ZuCdZ0w=T0vdSBZ;@3~22@w^@qzN{^1(dKfp|a7GaArN}K<9|w10N0P%X6qp zEN8Go6a6VN#Y(v)eMDmNjLw`=#=1~yqzJ$~@6_PRN(aGBus24R5b9)N3_qC3)X&@Q1WU`GMF)xzDKe?MiF%=LRz6A zAI%Zm$D0@{IW2hnocN2dI0nNOWskDFqdKipDN!xxDHMMW`rK&&_)hLPOMw&nD z0Rv^jRQs;HS2A*o7kc5t_xW#U@?ixLkX+DF(jf z^Qhp%SSBblrHUcOaJshI@^Z9F3ij&ah`mtZK4fv4#1Vb0=@|d58#)$Q1!XR6rTOm# z%Pzuhc-!F%BAg+v7fL1d!n0M|a%3#o#hOLkZ?kbhxTRpoB(+-TQ~X}*%(t0cp>SFXhwQ;Or4f4F!T;F9i+PKZzk_BQ}jupg*OYLlbdwk{)YjH!jR9savt>HT zs5>__A6@scrhn~f!Y%9ES4R>J5}PvmGNRc684ejs%1InQzi%0J@Ye`K5K`Te0#rGwgWBzk?2{m%E^-Eq!PRWaT z#suVe#Bs0VtF?Qb9_6a#_h{pr`x}o9)v{0d!A#)TmG((Klh-D^H==G_sJmSU9)#Da z#Pq~u#cW^8Up>6SUQhm2KTQ82Gv_Ga$Mc+LjHmXj{Mko*p?pgGS^T%Q>kC{Jc(x6) z(?r^0r;v!35;>LFAp1jM8KXN8q>O?LgAeV%ht^u&34P6Vk*W43ZKf3 zPqwr3BaOZEy%^Dk3D+euADWKEgDjjOyPd{L2o8#pKhEVOI9b;fUM+NaP{lf8d~H0> zBYn~E)8W&WE5YZTY{Fmb3OOOw=_zv8o~q0{cv$s(W_El$`BBp-EjKN<2q}Wgs8s); zUA4c;DNtQKRb-Stj(?+&dg0B|sLC>BzF#^l!M?Mo5?SFaDq|11qfR@v`xuRds6}|c z*BuPp__nOFBTgo|mT}*ib^lQ>i{>>q1g^J!CZm$*DjTT<^+i?(&~UR|r`f^mhZ*b6 zBPgW%j}ZF6k0fM#*R5NY>T#ZW>7{8cY(m9P@241Pbb5e0CnU4`n8%revgs$7B<7up zU-xZT<0GDqC%U5-==i?A&qu1>%uFGsil+$7C9nE>M`}aNyWgIl6)9JkyE>+D0)ON) z^=4GaLQ-30+nY8%eYF0}vDPQd{vS6DiWZ~t&iJxD*30i!)qPa!>#6?~d1_uXUQzn+ zXHMF5&0}?%XK1bU=>m-8!{>(V8^79-` z;qS8s=u7r%S)slzzO_M?9r>oR)bI9HCze{~KTjn4&eo8Af|vaJRjZDc!zs$Y}eMRisnaYg^*arO2FTV!Aj+b6y98sYQ`5S4Q?=B2?*|yqt ztJtVqP0mwNQV@}^{SnZfI$ZLwM6%;ejK?N@igI^iaD8O;Xa{PocXr2eVn=-iy>y<; zxm$V<)}+#;RMSp}&)r@tZ|^_NVR5Pln`)J^_OF?3IL~*kV46zaIxU$@L~pD?md?$u z#u};a+WNkvTBE40#6W5!nv4a^1Bm`ukR2W!ghgV}0rZnCSYrU-Q^vWWs3-?}7>0<~ zLT_QTXm}Er4FJZbG!hyUilu`5u|YTj9L#xE4+h}^;9yUE2W3gEF+G>C=|BT!&8IQVZ}7}ws~hJZnTL#Ux}@PC3rIXHtXiDWED zU&}xf1J%<39Wv5_8fY8o=xKm-w4sL}+J_)eT}^E$OxpmaYXth|0&~5Q0|H@4E1Q3O zaaV9~FqKMzK_HQlky??uT10XX1Zret1ku)k=;&y25tinF z;)n#$mLl4p7*2(Qxsm=S1w83rSpwysW8xkdgoY+Tpjz5nDg6dIIQ;)mJpNxag^I-f zH{SnKnBqn!VIfE?g&0o8a0?fxvgL{dvm|5DR3h1pNDTXZiq64ADv=UQB!Rep5c@rG zgaBeB<-p%?2M3rPfkH(SFjzY)IG8J-g~J8Ftc;-ghSrDlEX{RnpipZIBV7w4Yb!%N zsDXunKGah8H`j`Y3CCjz)Zg5I|8n*J$ldA$Jc;Ys3QNXCU;}K(L_Fy4jA6Jx$D;E` zy??j?e~v}>k6Z{h7|2##|5u%VZ*iMv%lx-%xr=}M9!uahJDJl!w8alk zDeY>kp|~AdTZ7UyBBNe!)1@}fM@zkwF>BBwXe=SwzVUu<@Av)j^_}ZF=eeKf`Tc(PeLweouIrr3sN>cm!g9g@0EpNi zEYRFhmV3(!@^PQl8}D5KK-ipMZjQ1sHwRIuWN$(M9sn4<+4jMhq$O#ifhD|{lUdKq z!?b|&09ctV*eLFjCw>jUUKE!wc@-5S>?A3*BMaeJf1yhlksULfyRY2G^h%6ttmCP} z-xd1{pM-^Qrl(gvtW=I?jjy&b+r=VwNT?-_<@o^y=qN*2k79xyqQ0prf>#PL$PW@9 zYp(MVcm)76d`w0-{ekf+&wVn$3sAZ=RU{gQHXM>fDZEl=6iOw@_~?ixmuky zgGKI?sB#1kP}`i+ns%&HN3uNStz7Wj%;2!na9zMdGpx*hac`j!a8_ET@=nA!AF^#b z0LU$OyjVYM%o-mX85;8*58(WGmACFcLk1fu%?_+rUghNn#E-Xgdfi7yyZI;$JP!hE z{EJQky-tAdz_Oc8pHQx=@Y|5(SmxnXlRY^%QH_QQyM?!Hn^yI_S*7(Q)@Va#h&&h@ zzR2BO?+cj$&SaRR7uV)TuARY>f=bZwGAwvEJF8ML;+|bM)CysRU@^4x5&&d z(G8(Ir$Lo8h&yHSi`CZ%(!R2KrP3OjeE!i1zW2O=CeQ9D%3XP#OY5NPin&Fk=J|KX zmF|H@Jk2ZYIQBJ=4uoBa$3=8NMZK?n#Gbl($7P0B` zh~T3LHYhEzj3vghySCEwa->WW_9|u=DU_#zE=ZO*s)sio<-c`9+bliz?upi-ocDrv zV_-L2ZHT!+D2V-~qMf>d8LF+B(&o(t8u?vsGYCF}C11z{y+Y_yeU0QmhgVqOa`E;M_V%N!zm;;LkLZuSl zNTk40oKnJ5#_u{f(j1Mun0L21+;bGWciJiJww2>!)R!Wm_tN*eiWD557wMO@p@Y#0 zsP+@?`PJ@g7k=SH9z{o4}q27?* z>R!)j>a_IqWG^R>l5LW$p1lAg!j=MsD)cK(R76$u1-5@PdWV~2P6#c$SrDE0)M33q z{E@#P^NrKZ=}_a9{ne6UsYgE)Lz<(d=81Snr$PVUxeNT_R)4JQTaAmlWtsKrXsmv0LuzkoXtO}7ZR!&Hx|5L;(`mu!1KXzi)TH_(vD-NS zCGVWMJrkDM{Pa$7W^sK`CUHP=STbRM=l%tIQZICBbxL?DV`|H^!6J51b&~R4Po)&+jQU$cOD0 zfDXV-WtK;j-z`7Sxb)LbgYQBjeFXkQoZH%WkxgWUH`q?qX(?on>`iT;7R?W#vZ=uZ?9p zr7Rx)bR^9Dmv6M4Rp4tKAv^RzW}@u1XUg-oP8Qvt+3g?CeAF;V&PvY8M~e_rOAmg~ zD%)3P=Y8;ClE?^ijQB=A>C&5}5#?pte4kW66tW|~6kUQ6l}1AD9Auo_b&^qzs6x2D z*BS6$|F*2W?Sgb@73%@2{K4a%a)!(7Ah^czxwLYuy-cts)D2zX#URXdhBf;(KT2Ig z4P(%bbAHVJxp;JB=dD}j2QN75rW7SNHIqtyxIV*4VN<*uIeuwfC!Nk6kV$c8Q`mP( zem<}&9~*W)?%ox;z$Eteem+|EW_l7aSujarFS*p*KU(Ey+VwViMxYLVRm!>zh_SJ*?jJ$(E<=zPX$F`HLah=iHi|){5_yRex0L?XLM0e0E+mQbFp- zXHN1|<&%R9Xa6e8umw`*_Y0pAY zkq{BBAGZeqql{)okb5(yGlHK`Tn~uWnU22LJ8(Pn>=)G6n{6-qU$zdUpDSAsoJ24W zcEV}`*&6x8T=>l@&eyB?*$Sr>tgFj5!a2|{xWERz1m~RG?0xXr<&g_XUkbenbFz;c z!{4X(GnbI7>Hcmf+^T%c+jER%=--iL?n_PcpT`s2W-2K^z)PNes%6KD;U#eEaLU>c z;{HkUBz~!R+S#y#{=;_iNC)TLxnF*@U9=BBKWMt$U{-NnPsx{&)IRMlSFKq18MHVp z6D<54+3yyTz_`C!-MjW}>o2iy=StTf;%kY6KRs$a+F!beaYThK<*X-fyt_2iY29Mo zrEH}fmyoTfC@&&cHRsiqG*tMgaA*6QaHkFCB<u}EENx!dXYWxAR8jq2am>My_jd3@P+`ur$lhT&@r}17>-QT z#BO3V8AJ+~4FHD53T4Nj>#BpawV;O}T8AJ|9StogOiLf8V*vX50&~4ly}V&)3#-3< zac6L_FP%<-K_J1w!J5H3nq;aE1ZrSl0MXKhXlrY55gIfmiH>DxkZ8)k6)f;H9F;(! z6UZdcrXtpp97u(dbwb4sT-t2Xh592?Q^gu8xI{fdy30+*C&k3biydHMi0+H9e$d zU}|A@*aE8mn`=SF1rqTj`fsk+f4KU8*Z?&P1o$CJ3tPUUtr@sO!A_l?+sLONJ( zY;15%$GUgn+`-Mp!qkD$o7HJ5TnpN6(XqT#LoX^8XlhZpH7x&GNv* z`Q5buW?fWKQ4+F2m`Q{qjEWslcQqjzHTL19bZk&t&=I8I9KEtGJ}>H61P_3x W@<`O{ko&lf02|BW7A0mL7ybo9V{1nM literal 0 HcmV?d00001 diff --git a/assets/icons/Infrared/TrackPrev_hvr_25x27.png b/assets/icons/Infrared/TrackPrev_hvr_25x27.png new file mode 100644 index 0000000000000000000000000000000000000000..838055341e568fed60b3e28a280fe839d2c9db9e GIT binary patch literal 3644 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 +#include #include #include @@ -118,6 +119,13 @@ static void furi_hal_resources_init_input_pins(GpioMode mode) { } void furi_hal_resources_init_early() { + furi_hal_bus_enable(FuriHalBusGPIOA); + furi_hal_bus_enable(FuriHalBusGPIOB); + furi_hal_bus_enable(FuriHalBusGPIOC); + furi_hal_bus_enable(FuriHalBusGPIOD); + furi_hal_bus_enable(FuriHalBusGPIOE); + furi_hal_bus_enable(FuriHalBusGPIOH); + furi_hal_resources_init_input_pins(GpioModeInput); // SD Card stepdown control @@ -162,6 +170,12 @@ void furi_hal_resources_init_early() { void furi_hal_resources_deinit_early() { furi_hal_resources_init_input_pins(GpioModeAnalog); + furi_hal_bus_disable(FuriHalBusGPIOA); + furi_hal_bus_disable(FuriHalBusGPIOB); + furi_hal_bus_disable(FuriHalBusGPIOC); + furi_hal_bus_disable(FuriHalBusGPIOD); + furi_hal_bus_disable(FuriHalBusGPIOE); + furi_hal_bus_disable(FuriHalBusGPIOH); } void furi_hal_resources_init() { diff --git a/firmware/targets/f18/furi_hal/furi_hal_spi_config.c b/firmware/targets/f18/furi_hal/furi_hal_spi_config.c index 0fbe55e2a..5ac84906f 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_spi_config.c +++ b/firmware/targets/f18/furi_hal/furi_hal_spi_config.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -96,28 +97,17 @@ void furi_hal_spi_config_init() { static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_r_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_r_mutex); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_r_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_r_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI1); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI1); } } @@ -131,28 +121,17 @@ FuriMutex* furi_hal_spi_bus_d_mutex = NULL; static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_d_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_d_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_d_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_d_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI2); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI2); } } diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 195d40526..1875dd47b 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,+,27.1,, +Version,+,28.1,, Header,+,applications/main/archive/helpers/favorite_timeout.h,, Header,+,applications/main/fap_loader/fap_loader_app.h,, Header,+,applications/main/subghz/helpers/subghz_txrx.h,, @@ -40,8 +40,10 @@ Header,+,applications/services/notification/notification_messages.h,, Header,+,applications/services/power/power_service/power.h,, Header,+,applications/services/rpc/rpc_app.h,, Header,+,applications/services/storage/storage.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_bus.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_clock.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_console.h,, +Header,+,firmware/targets/f7/furi_hal/furi_hal_dma.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_flash.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_gpio.h,, Header,+,firmware/targets/f7/furi_hal/furi_hal_i2c_config.h,, @@ -1137,6 +1139,12 @@ Function,+,furi_hal_bt_stop_tone_tx,void, Function,+,furi_hal_bt_unlock_core2,void, Function,+,furi_hal_bt_update_battery_level,void,uint8_t Function,+,furi_hal_bt_update_power_state,void, +Function,+,furi_hal_bus_deinit_early,void, +Function,+,furi_hal_bus_disable,void,FuriHalBus +Function,+,furi_hal_bus_enable,void,FuriHalBus +Function,+,furi_hal_bus_init_early,void, +Function,+,furi_hal_bus_is_enabled,_Bool,FuriHalBus +Function,+,furi_hal_bus_reset,void,FuriHalBus Function,+,furi_hal_cdc_get_ctrl_line_state,uint8_t,uint8_t Function,+,furi_hal_cdc_get_port_settings,usb_cdc_line_coding*,uint8_t Function,+,furi_hal_cdc_receive,int32_t,"uint8_t, uint8_t*, uint16_t" @@ -1179,6 +1187,8 @@ Function,+,furi_hal_debug_disable,void, Function,+,furi_hal_debug_enable,void, Function,+,furi_hal_debug_is_gdb_session_active,_Bool, Function,-,furi_hal_deinit_early,void, +Function,+,furi_hal_dma_deinit_early,void, +Function,+,furi_hal_dma_init_early,void, Function,-,furi_hal_flash_erase,void,uint8_t Function,-,furi_hal_flash_get_base,size_t, Function,-,furi_hal_flash_get_cycles_count,size_t, @@ -1348,6 +1358,7 @@ Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t" Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId Function,+,furi_hal_random_fill_buf,void,"uint8_t*, uint32_t" Function,+,furi_hal_random_get,uint32_t, +Function,+,furi_hal_random_init,void, Function,+,furi_hal_region_get,const FuriHalRegion*, Function,+,furi_hal_region_get_band,const FuriHalRegionBand*,uint32_t Function,+,furi_hal_region_get_name,const char*, @@ -1358,31 +1369,23 @@ Function,-,furi_hal_resources_deinit_early,void, Function,+,furi_hal_resources_get_ext_pin_number,int32_t,const GpioPin* Function,-,furi_hal_resources_init,void, Function,-,furi_hal_resources_init_early,void, -Function,+,furi_hal_rfid_change_read_config,void,"float, float" 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_init,void, Function,+,furi_hal_rfid_pin_pull_pulldown,void, Function,+,furi_hal_rfid_pin_pull_release,void, -Function,+,furi_hal_rfid_pins_emulate,void, -Function,+,furi_hal_rfid_pins_read,void, Function,+,furi_hal_rfid_pins_reset,void, -Function,+,furi_hal_rfid_set_emulate_period,void,uint32_t -Function,+,furi_hal_rfid_set_emulate_pulse,void,uint32_t Function,+,furi_hal_rfid_set_read_period,void,uint32_t Function,+,furi_hal_rfid_set_read_pulse,void,uint32_t -Function,+,furi_hal_rfid_tim_emulate,void,float Function,+,furi_hal_rfid_tim_emulate_dma_start,void,"uint32_t*, uint32_t*, size_t, FuriHalRfidDMACallback, void*" Function,+,furi_hal_rfid_tim_emulate_dma_stop,void, -Function,+,furi_hal_rfid_tim_emulate_start,void,"FuriHalRfidEmulateCallback, void*" -Function,+,furi_hal_rfid_tim_emulate_stop,void, -Function,+,furi_hal_rfid_tim_read,void,"float, float" Function,+,furi_hal_rfid_tim_read_capture_start,void,"FuriHalRfidReadCaptureCallback, void*" Function,+,furi_hal_rfid_tim_read_capture_stop,void, -Function,+,furi_hal_rfid_tim_read_start,void, +Function,+,furi_hal_rfid_tim_read_continue,void, +Function,+,furi_hal_rfid_tim_read_pause,void, +Function,+,furi_hal_rfid_tim_read_start,void,"float, float" Function,+,furi_hal_rfid_tim_read_stop,void, -Function,+,furi_hal_rfid_tim_reset,void, Function,+,furi_hal_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime* Function,-,furi_hal_rtc_deinit_early,void, Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode, @@ -1864,9 +1867,6 @@ Function,-,j1f,float,float Function,-,jn,double,"int, double" Function,-,jnf,float,"int, float" Function,-,jrand48,long,unsigned short[3] -Function,+,keeloq_reset_kl_type,void, -Function,+,keeloq_reset_mfname,void, -Function,+,keeloq_reset_original_btn,void, Function,-,l64a,char*,long Function,-,labs,long,long Function,-,lcong48,void,unsigned short[7] @@ -2619,8 +2619,6 @@ Function,+,srand,void,unsigned Function,-,srand48,void,long Function,-,srandom,void,unsigned Function,+,sscanf,int,"const char*, const char*, ..." -Function,+,star_line_reset_kl_type,void, -Function,+,star_line_reset_mfname,void, Function,+,storage_common_copy,FS_Error,"Storage*, const char*, const char*" Function,+,storage_common_exists,_Bool,"Storage*, const char*" Function,+,storage_common_fs_info,FS_Error,"Storage*, const char*, uint64_t*, uint64_t*" @@ -2768,13 +2766,6 @@ 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_custom_btn_get,uint8_t, -Function,-,subghz_custom_btn_get_original,uint8_t, -Function,-,subghz_custom_btn_is_allowed,_Bool, -Function,+,subghz_custom_btn_set,_Bool,uint8_t -Function,-,subghz_custom_btn_set_max,void,uint8_t -Function,-,subghz_custom_btn_set_original,void,uint8_t -Function,+,subghz_custom_btns_reset,void, 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* @@ -2784,6 +2775,7 @@ Function,+,subghz_environment_get_nice_flor_s_rainbow_table_file_name,const char Function,+,subghz_environment_get_protocol_name_registry,const char*,"SubGhzEnvironment*, size_t" Function,+,subghz_environment_get_protocol_registry,void*,SubGhzEnvironment* Function,+,subghz_environment_load_keystore,_Bool,"SubGhzEnvironment*, const char*" +Function,+,subghz_environment_reset_keeloq,void,SubGhzEnvironment* Function,+,subghz_environment_set_alutech_at_4n_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" Function,+,subghz_environment_set_came_atomo_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" Function,+,subghz_environment_set_nice_flor_s_rainbow_table_file_name,void,"SubGhzEnvironment*, const char*" @@ -2794,6 +2786,7 @@ Function,-,subghz_keystore_get_data,SubGhzKeyArray_t*,SubGhzKeystore* Function,-,subghz_keystore_load,_Bool,"SubGhzKeystore*, const char*" Function,-,subghz_keystore_raw_encrypted_save,_Bool,"const char*, const char*, uint8_t*" Function,-,subghz_keystore_raw_get_data,_Bool,"const char*, size_t, uint8_t*, size_t" +Function,-,subghz_keystore_reset_kl,void,SubGhzKeystore* Function,-,subghz_keystore_save,_Bool,"SubGhzKeystore*, const char*, uint8_t*" Function,-,subghz_protocol_alutech_at_4n_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" Function,+,subghz_protocol_blocks_add_bit,void,"SubGhzBlockDecoder*, uint8_t" @@ -3467,6 +3460,7 @@ Function,+,submenu_set_header,void,"Submenu*, const char*" Function,+,submenu_set_selected_item,void,"Submenu*, uint32_t" Function,-,system,int,const char* Function,+,t5577_write,void,LFRFIDT5577* +Function,-,t5577_write_with_pass,void,"LFRFIDT5577*, uint32_t" Function,-,tan,double,double Function,-,tanf,float,float Function,-,tanh,double,double @@ -3640,6 +3634,8 @@ Function,+,version_get,const Version*, Function,+,version_get_builddate,const char*,const Version* Function,+,version_get_custom_name,const char*,const Version* Function,+,version_get_dirty_flag,_Bool,const Version* +Function,+,version_get_firmware_origin,const char*,const Version* +Function,+,version_get_git_origin,const char*,const Version* Function,+,version_get_gitbranch,const char*,const Version* Function,+,version_get_gitbranchnum,const char*,const Version* Function,+,version_get_githash,const char*,const Version* diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index 1378b6955..ff1167abd 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -19,6 +19,8 @@ bool furi_hal_is_normal_boot() { void furi_hal_init_early() { furi_hal_cortex_init_early(); furi_hal_clock_init_early(); + furi_hal_bus_init_early(); + furi_hal_dma_init_early(); furi_hal_resources_init_early(); furi_hal_os_init(); furi_hal_spi_config_init_early(); @@ -32,12 +34,15 @@ void furi_hal_deinit_early() { furi_hal_i2c_deinit_early(); furi_hal_spi_config_deinit_early(); furi_hal_resources_deinit_early(); + furi_hal_dma_deinit_early(); + furi_hal_bus_deinit_early(); furi_hal_clock_deinit_early(); } void furi_hal_init() { furi_hal_mpu_init(); furi_hal_clock_init(); + furi_hal_random_init(); furi_hal_console_init(); furi_hal_rtc_init(); furi_hal_interrupt_init(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index a56f54484..4f95cf0fb 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "battery_service.h" #include @@ -80,6 +81,11 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { FuriHalBtProfileConfig* current_profile = NULL; void furi_hal_bt_init() { + furi_hal_bus_enable(FuriHalBusHSEM); + furi_hal_bus_enable(FuriHalBusIPCC); + furi_hal_bus_enable(FuriHalBusAES2); + furi_hal_bus_enable(FuriHalBusPKA); + if(!furi_hal_bt_core2_mtx) { furi_hal_bt_core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal); furi_assert(furi_hal_bt_core2_mtx); @@ -269,6 +275,11 @@ void furi_hal_bt_reinit() { furi_delay_ms(100); ble_glue_thread_stop(); + furi_hal_bus_disable(FuriHalBusHSEM); + furi_hal_bus_disable(FuriHalBusIPCC); + furi_hal_bus_disable(FuriHalBusAES2); + furi_hal_bus_disable(FuriHalBusPKA); + FURI_LOG_I(TAG, "Start BT initialization"); furi_hal_bt_init(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bus.c b/firmware/targets/f7/furi_hal/furi_hal_bus.c new file mode 100644 index 000000000..0a07e9f9e --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_bus.c @@ -0,0 +1,302 @@ +#include +#include + +#include + +/* Bus bitmask definitions */ +#define FURI_HAL_BUS_IGNORE (0x0U) + +#define FURI_HAL_BUS_AHB1_GRP1 \ + (LL_AHB1_GRP1_PERIPH_DMA1 | LL_AHB1_GRP1_PERIPH_DMA2 | LL_AHB1_GRP1_PERIPH_DMAMUX1 | \ + LL_AHB1_GRP1_PERIPH_CRC | LL_AHB1_GRP1_PERIPH_TSC) + +#if defined(ADC_SUPPORT_5_MSPS) +#define FURI_HAL_BUS_AHB2_GRP1 \ + (LL_AHB2_GRP1_PERIPH_GPIOA | LL_AHB2_GRP1_PERIPH_GPIOB | LL_AHB2_GRP1_PERIPH_GPIOC | \ + LL_AHB2_GRP1_PERIPH_GPIOD | LL_AHB2_GRP1_PERIPH_GPIOE | LL_AHB2_GRP1_PERIPH_GPIOH | \ + LL_AHB2_GRP1_PERIPH_ADC | LL_AHB2_GRP1_PERIPH_AES1) + +#define FURI_HAL_BUS_APB2_GRP1 \ + (LL_APB2_GRP1_PERIPH_TIM1 | LL_APB2_GRP1_PERIPH_SPI1 | LL_APB2_GRP1_PERIPH_USART1 | \ + LL_APB2_GRP1_PERIPH_TIM16 | LL_APB2_GRP1_PERIPH_TIM17 | LL_APB2_GRP1_PERIPH_SAI1) +#else +#define FURI_HAL_BUS_AHB2_GRP1 \ + (LL_AHB2_GRP1_PERIPH_GPIOA | LL_AHB2_GRP1_PERIPH_GPIOB | LL_AHB2_GRP1_PERIPH_GPIOC | \ + LL_AHB2_GRP1_PERIPH_GPIOD | LL_AHB2_GRP1_PERIPH_GPIOE | LL_AHB2_GRP1_PERIPH_GPIOH | \ + LL_AHB2_GRP1_PERIPH_AES1) + +#define FURI_HAL_BUS_APB2_GRP1 \ + (LL_APB2_GRP1_PERIPH_ADC | LL_APB2_GRP1_PERIPH_TIM1 | LL_APB2_GRP1_PERIPH_SPI1 | \ + LL_APB2_GRP1_PERIPH_USART1 | LL_APB2_GRP1_PERIPH_TIM16 | LL_APB2_GRP1_PERIPH_TIM17 | \ + LL_APB2_GRP1_PERIPH_SAI1) +#endif + +#define FURI_HAL_BUS_AHB3_GRP1 \ + (LL_AHB3_GRP1_PERIPH_QUADSPI | LL_AHB3_GRP1_PERIPH_PKA | LL_AHB3_GRP1_PERIPH_AES2 | \ + LL_AHB3_GRP1_PERIPH_RNG | LL_AHB3_GRP1_PERIPH_HSEM | LL_AHB3_GRP1_PERIPH_IPCC) +// LL_AHB3_GRP1_PERIPH_FLASH enabled by default + +#define FURI_HAL_BUS_APB1_GRP1 \ + (LL_APB1_GRP1_PERIPH_TIM2 | LL_APB1_GRP1_PERIPH_LCD | LL_APB1_GRP1_PERIPH_RTCAPB | \ + LL_APB1_GRP1_PERIPH_SPI2 | LL_APB1_GRP1_PERIPH_I2C1 | LL_APB1_GRP1_PERIPH_I2C3 | \ + LL_APB1_GRP1_PERIPH_CRS | LL_APB1_GRP1_PERIPH_USB | LL_APB1_GRP1_PERIPH_LPTIM1) + +#define FURI_HAL_BUS_APB1_GRP2 (LL_APB1_GRP2_PERIPH_LPUART1 | LL_APB1_GRP2_PERIPH_LPTIM2) +#define FURI_HAL_BUS_APB3_GRP1 (LL_APB3_GRP1_PERIPH_RF) + +/* Test macro definitions */ +#define FURI_HAL_BUS_IS_ALL_CLEAR(reg, value) (READ_BIT((reg), (value)) == 0UL) +#define FURI_HAL_BUS_IS_ALL_SET(reg, value) (READ_BIT((reg), (value)) == (value)) + +#define FURI_HAL_BUS_IS_CLOCK_ENABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_SET(RCC->bus##ENR##__VA_ARGS__, (value))) +#define FURI_HAL_BUS_IS_CLOCK_DISABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_CLEAR(RCC->bus##ENR##__VA_ARGS__, (value))) + +#define FURI_HAL_BUS_IS_RESET_ASSERTED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_SET(RCC->bus##RSTR##__VA_ARGS__, (value))) +#define FURI_HAL_BUS_IS_RESET_DEASSERTED(bus, value, ...) \ + (FURI_HAL_BUS_IS_ALL_CLEAR(RCC->bus##RSTR##__VA_ARGS__, (value))) + +#define FURI_HAL_BUS_IS_PERIPH_ENABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_RESET_DEASSERTED(bus, (value), __VA_ARGS__) && \ + FURI_HAL_BUS_IS_CLOCK_ENABLED(bus, (value), __VA_ARGS__)) + +#define FURI_HAL_BUS_IS_PERIPH_DISABLED(bus, value, ...) \ + (FURI_HAL_BUS_IS_CLOCK_DISABLED(bus, (value), __VA_ARGS__) && \ + FURI_HAL_BUS_IS_RESET_ASSERTED(bus, (value), __VA_ARGS__)) + +/* Control macro definitions */ +#define FURI_HAL_BUS_RESET_ASSERT(bus, value, grp) LL_##bus##_GRP##grp##_ForceReset(value) +#define FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) LL_##bus##_GRP##grp##_ReleaseReset(value) + +#define FURI_HAL_BUS_CLOCK_ENABLE(bus, value, grp) LL_##bus##_GRP##grp##_EnableClock(value) +#define FURI_HAL_BUS_CLOCK_DISABLE(bus, value, grp) LL_##bus##_GRP##grp##_DisableClock(value) + +#define FURI_HAL_BUS_PERIPH_ENABLE(bus, value, grp) \ + FURI_HAL_BUS_CLOCK_ENABLE(bus, value, grp); \ + FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) + +#define FURI_HAL_BUS_PERIPH_DISABLE(bus, value, grp) \ + FURI_HAL_BUS_RESET_ASSERT(bus, value, grp); \ + FURI_HAL_BUS_CLOCK_DISABLE(bus, value, grp) + +#define FURI_HAL_BUS_PERIPH_RESET(bus, value, grp) \ + FURI_HAL_BUS_RESET_ASSERT(bus, value, grp); \ + FURI_HAL_BUS_RESET_DEASSERT(bus, value, grp) + +static const uint32_t furi_hal_bus[] = { + [FuriHalBusAHB1_GRP1] = FURI_HAL_BUS_AHB1_GRP1, + [FuriHalBusDMA1] = LL_AHB1_GRP1_PERIPH_DMA1, + [FuriHalBusDMA2] = LL_AHB1_GRP1_PERIPH_DMA2, + [FuriHalBusDMAMUX1] = LL_AHB1_GRP1_PERIPH_DMAMUX1, + [FuriHalBusCRC] = LL_AHB1_GRP1_PERIPH_CRC, + [FuriHalBusTSC] = LL_AHB1_GRP1_PERIPH_TSC, + + [FuriHalBusAHB2_GRP1] = FURI_HAL_BUS_AHB2_GRP1, + [FuriHalBusGPIOA] = LL_AHB2_GRP1_PERIPH_GPIOA, + [FuriHalBusGPIOB] = LL_AHB2_GRP1_PERIPH_GPIOB, + [FuriHalBusGPIOC] = LL_AHB2_GRP1_PERIPH_GPIOC, + [FuriHalBusGPIOD] = LL_AHB2_GRP1_PERIPH_GPIOD, + [FuriHalBusGPIOE] = LL_AHB2_GRP1_PERIPH_GPIOE, + [FuriHalBusGPIOH] = LL_AHB2_GRP1_PERIPH_GPIOH, +#if defined(ADC_SUPPORT_5_MSPS) + [FuriHalBusADC] = LL_AHB2_GRP1_PERIPH_ADC, +#endif + [FuriHalBusAES1] = LL_AHB2_GRP1_PERIPH_AES1, + + [FuriHalBusAHB3_GRP1] = FURI_HAL_BUS_AHB3_GRP1, + [FuriHalBusQUADSPI] = LL_AHB3_GRP1_PERIPH_QUADSPI, + [FuriHalBusPKA] = LL_AHB3_GRP1_PERIPH_PKA, + [FuriHalBusAES2] = LL_AHB3_GRP1_PERIPH_AES2, + [FuriHalBusRNG] = LL_AHB3_GRP1_PERIPH_RNG, + [FuriHalBusHSEM] = LL_AHB3_GRP1_PERIPH_HSEM, + [FuriHalBusIPCC] = LL_AHB3_GRP1_PERIPH_IPCC, + [FuriHalBusFLASH] = LL_AHB3_GRP1_PERIPH_FLASH, + + [FuriHalBusAPB1_GRP1] = FURI_HAL_BUS_APB1_GRP1, + [FuriHalBusTIM2] = LL_APB1_GRP1_PERIPH_TIM2, + [FuriHalBusLCD] = LL_APB1_GRP1_PERIPH_LCD, + [FuriHalBusSPI2] = LL_APB1_GRP1_PERIPH_SPI2, + [FuriHalBusI2C1] = LL_APB1_GRP1_PERIPH_I2C1, + [FuriHalBusI2C3] = LL_APB1_GRP1_PERIPH_I2C3, + [FuriHalBusCRS] = LL_APB1_GRP1_PERIPH_CRS, + [FuriHalBusUSB] = LL_APB1_GRP1_PERIPH_USB, + [FuriHalBusLPTIM1] = LL_APB1_GRP1_PERIPH_LPTIM1, + + [FuriHalBusAPB1_GRP2] = FURI_HAL_BUS_APB1_GRP2, + [FuriHalBusLPUART1] = LL_APB1_GRP2_PERIPH_LPUART1, + [FuriHalBusLPTIM2] = LL_APB1_GRP2_PERIPH_LPTIM2, + + [FuriHalBusAPB2_GRP1] = FURI_HAL_BUS_APB2_GRP1, +#if defined(ADC_SUPPORT_2_5_MSPS) + [FuriHalBusADC] = LL_APB2_GRP1_PERIPH_ADC, +#endif + [FuriHalBusTIM1] = LL_APB2_GRP1_PERIPH_TIM1, + [FuriHalBusSPI1] = LL_APB2_GRP1_PERIPH_SPI1, + [FuriHalBusUSART1] = LL_APB2_GRP1_PERIPH_USART1, + [FuriHalBusTIM16] = LL_APB2_GRP1_PERIPH_TIM16, + [FuriHalBusTIM17] = LL_APB2_GRP1_PERIPH_TIM17, + [FuriHalBusSAI1] = LL_APB2_GRP1_PERIPH_SAI1, + + [FuriHalBusAPB3_GRP1] = FURI_HAL_BUS_IGNORE, // APB3_GRP1 clocking cannot be changed + [FuriHalBusRF] = LL_APB3_GRP1_PERIPH_RF, +}; + +void furi_hal_bus_init_early() { + FURI_CRITICAL_ENTER(); + + FURI_HAL_BUS_PERIPH_DISABLE(AHB1, FURI_HAL_BUS_AHB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(AHB2, FURI_HAL_BUS_AHB2_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(AHB3, FURI_HAL_BUS_AHB3_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, FURI_HAL_BUS_APB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, FURI_HAL_BUS_APB1_GRP2, 2); + FURI_HAL_BUS_PERIPH_DISABLE(APB2, FURI_HAL_BUS_APB2_GRP1, 1); + + FURI_HAL_BUS_RESET_ASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_deinit_early() { + FURI_CRITICAL_ENTER(); + + FURI_HAL_BUS_PERIPH_ENABLE(AHB1, FURI_HAL_BUS_AHB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(AHB2, FURI_HAL_BUS_AHB2_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(AHB3, FURI_HAL_BUS_AHB3_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, FURI_HAL_BUS_APB1_GRP1, 1); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, FURI_HAL_BUS_APB1_GRP2, 2); + FURI_HAL_BUS_PERIPH_ENABLE(APB2, FURI_HAL_BUS_APB2_GRP1, 1); + + FURI_HAL_BUS_RESET_DEASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_enable(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(!value) { + return; + } + + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(AHB1, value)); + FURI_HAL_BUS_PERIPH_ENABLE(AHB1, value, 1); + } else if(bus < FuriHalBusAHB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(AHB2, value)); + FURI_HAL_BUS_PERIPH_ENABLE(AHB2, value, 1); + } else if(bus < FuriHalBusAPB1_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(AHB3, value)); + FURI_HAL_BUS_PERIPH_ENABLE(AHB3, value, 1); + } else if(bus < FuriHalBusAPB1_GRP2) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(APB1, value, 1)); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(APB1, value, 2)); + FURI_HAL_BUS_PERIPH_ENABLE(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_DISABLED(APB2, value)); + FURI_HAL_BUS_PERIPH_ENABLE(APB2, value, 1); + } else { + furi_check(FURI_HAL_BUS_IS_RESET_ASSERTED(APB3, value)); + FURI_HAL_BUS_RESET_DEASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + } + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_reset(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(!value) { + return; + } + + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB1, value)); + FURI_HAL_BUS_PERIPH_RESET(AHB1, value, 1); + } else if(bus < FuriHalBusAHB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB2, value)); + FURI_HAL_BUS_PERIPH_RESET(AHB2, value, 1); + } else if(bus < FuriHalBusAPB1_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB3, value)); + FURI_HAL_BUS_PERIPH_RESET(AHB3, value, 1); + } else if(bus < FuriHalBusAPB1_GRP2) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 1)); + FURI_HAL_BUS_PERIPH_RESET(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 2)); + FURI_HAL_BUS_PERIPH_RESET(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB2, value)); + FURI_HAL_BUS_PERIPH_RESET(APB2, value, 1); + } else { + furi_check(FURI_HAL_BUS_IS_RESET_DEASSERTED(APB3, value)); + FURI_HAL_BUS_PERIPH_RESET(APB3, value, 1); + } + FURI_CRITICAL_EXIT(); +} + +void furi_hal_bus_disable(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(!value) { + return; + } + + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB1, value)); + FURI_HAL_BUS_PERIPH_DISABLE(AHB1, value, 1); + } else if(bus < FuriHalBusAHB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB2, value)); + FURI_HAL_BUS_PERIPH_DISABLE(AHB2, value, 1); + } else if(bus < FuriHalBusAPB1_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB3, value)); + FURI_HAL_BUS_PERIPH_DISABLE(AHB3, value, 1); + } else if(bus < FuriHalBusAPB1_GRP2) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 1)); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 2)); + FURI_HAL_BUS_PERIPH_DISABLE(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + furi_check(FURI_HAL_BUS_IS_PERIPH_ENABLED(APB2, value)); + FURI_HAL_BUS_PERIPH_DISABLE(APB2, value, 1); + } else { + furi_check(FURI_HAL_BUS_IS_RESET_DEASSERTED(APB3, value)); + FURI_HAL_BUS_RESET_ASSERT(APB3, FURI_HAL_BUS_APB3_GRP1, 1); + } + FURI_CRITICAL_EXIT(); +} + +bool furi_hal_bus_is_enabled(FuriHalBus bus) { + furi_check(bus < FuriHalBusMAX); + const uint32_t value = furi_hal_bus[bus]; + if(value == FURI_HAL_BUS_IGNORE) { + return true; + } + + bool ret = false; + FURI_CRITICAL_ENTER(); + if(bus < FuriHalBusAHB2_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB1, value); + } else if(bus < FuriHalBusAHB3_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB2, value); + } else if(bus < FuriHalBusAPB1_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(AHB3, value); + } else if(bus < FuriHalBusAPB1_GRP2) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 1); + } else if(bus < FuriHalBusAPB2_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(APB1, value, 2); + } else if(bus < FuriHalBusAPB3_GRP1) { + ret = FURI_HAL_BUS_IS_PERIPH_ENABLED(APB2, value); + } else { + ret = FURI_HAL_BUS_IS_RESET_DEASSERTED(APB3, value); + } + FURI_CRITICAL_EXIT(); + + return ret; +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_bus.h b/firmware/targets/f7/furi_hal/furi_hal_bus.h new file mode 100644 index 000000000..ad4bbec32 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_bus.h @@ -0,0 +1,112 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stm32wbxx.h" +#include "stdbool.h" + +typedef enum { + FuriHalBusAHB1_GRP1, + FuriHalBusDMA1, + FuriHalBusDMA2, + FuriHalBusDMAMUX1, + FuriHalBusCRC, + FuriHalBusTSC, + + FuriHalBusAHB2_GRP1, + FuriHalBusGPIOA, + FuriHalBusGPIOB, + FuriHalBusGPIOC, + FuriHalBusGPIOD, + FuriHalBusGPIOE, + FuriHalBusGPIOH, +#if defined(ADC_SUPPORT_5_MSPS) + FuriHalBusADC, +#endif + FuriHalBusAES1, + + FuriHalBusAHB3_GRP1, + FuriHalBusQUADSPI, + FuriHalBusPKA, + FuriHalBusAES2, + FuriHalBusRNG, + FuriHalBusHSEM, + FuriHalBusIPCC, + FuriHalBusFLASH, + + FuriHalBusAPB1_GRP1, + FuriHalBusTIM2, + FuriHalBusLCD, + FuriHalBusSPI2, + FuriHalBusI2C1, + FuriHalBusI2C3, + FuriHalBusCRS, + FuriHalBusUSB, + FuriHalBusLPTIM1, + + FuriHalBusAPB1_GRP2, + FuriHalBusLPUART1, + FuriHalBusLPTIM2, + + FuriHalBusAPB2_GRP1, +#if defined(ADC_SUPPORT_2_5_MSPS) + FuriHalBusADC, +#endif + FuriHalBusTIM1, + FuriHalBusSPI1, + FuriHalBusUSART1, + FuriHalBusTIM16, + FuriHalBusTIM17, + FuriHalBusSAI1, + + FuriHalBusAPB3_GRP1, + FuriHalBusRF, + + FuriHalBusMAX, +} FuriHalBus; + +/** Early initialization */ +void furi_hal_bus_init_early(); + +/** Early de-initialization */ +void furi_hal_bus_deinit_early(); + +/** + * Enable a peripheral by turning the clocking on and deasserting the reset. + * @param [in] bus Peripheral to be enabled. + * @warning Peripheral must be in disabled state in order to be enabled. + */ +void furi_hal_bus_enable(FuriHalBus bus); + +/** + * Reset a peripheral by sequentially asserting and deasserting the reset. + * @param [in] bus Peripheral to be reset. + * @warning Peripheral must be in enabled state in order to be reset. + */ +void furi_hal_bus_reset(FuriHalBus bus); + +/** + * Disable a peripheral by turning the clocking off and asserting the reset. + * @param [in] bus Peripheral to be disabled. + * @warning Peripheral must be in enabled state in order to be disabled. + */ +void furi_hal_bus_disable(FuriHalBus bus); + +/** Check if peripheral is enabled + * + * @warning FuriHalBusAPB3_GRP1 is a special group of shared peripherals, for + * core1 its clock is always on and the only status we can report is + * peripheral reset status. Check code and Reference Manual for + * details. + * + * @param[in] bus The peripheral to check + * + * @return true if enabled or always enabled, false otherwise + */ +bool furi_hal_bus_is_enabled(FuriHalBus bus); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_clock.c b/firmware/targets/f7/furi_hal/furi_hal_clock.c index 6283efabc..fd362bad5 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_clock.c +++ b/firmware/targets/f7/furi_hal/furi_hal_clock.c @@ -6,7 +6,6 @@ #include #include #include -#include #define TAG "FuriHalClock" @@ -19,36 +18,9 @@ void furi_hal_clock_init_early() { LL_SetSystemCoreClock(CPU_CLOCK_HZ_EARLY); LL_Init1msTick(SystemCoreClock); - - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH); - - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); - - LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPTIM2); - - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); } void furi_hal_clock_deinit_early() { - LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C3); - - LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_SPI2); - - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOC); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOD); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOE); - LL_AHB2_GRP1_DisableClock(LL_AHB2_GRP1_PERIPH_GPIOH); } void furi_hal_clock_init() { @@ -141,68 +113,12 @@ void furi_hal_clock_init() { SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), TICK_INT_PRIORITY, 0)); NVIC_EnableIRQ(SysTick_IRQn); - LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); - LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); - LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1); - LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); - LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); - LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_PLLSAI1); LL_RCC_HSI_EnableInStopMode(); // Ensure that MR is capable of work in STOP0 LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI); LL_RCC_SetSMPSPrescaler(LL_RCC_SMPS_DIV_1); LL_RCC_SetRFWKPClockSource(LL_RCC_RFWKP_CLKSOURCE_LSE); - // AHB1 GRP1 - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2); - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMAMUX1); - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_CRC); - // LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_TSC); - - // AHB2 GRP1 - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC); - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_AES1); - - // AHB3 GRP1 - // LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_QUADSPI); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PKA); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_AES2); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_RNG); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_HSEM); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_IPCC); - LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_FLASH); - - // APB1 GRP1 - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); - // LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LCD); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); - // LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_WWDG); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_CRS); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USB); - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPTIM1); - - // APB1 GRP2 - LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1); - - // APB2 - // LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM16); - LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM17); - // LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SAI1); - FURI_LOG_I(TAG, "Init OK"); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_crypto.c b/firmware/targets/f7/furi_hal/furi_hal_crypto.c index 0026636a4..e463edeba 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_crypto.c +++ b/firmware/targets/f7/furi_hal/furi_hal_crypto.c @@ -1,8 +1,9 @@ #include #include #include +#include + #include -#include #include #include @@ -244,6 +245,8 @@ bool furi_hal_crypto_store_load_key(uint8_t slot, const uint8_t* iv) { furi_assert(furi_hal_crypto_mutex); furi_check(furi_mutex_acquire(furi_hal_crypto_mutex, FuriWaitForever) == FuriStatusOk); + furi_hal_bus_enable(FuriHalBusAES1); + if(!furi_hal_bt_is_alive()) { return false; } @@ -270,10 +273,7 @@ bool furi_hal_crypto_store_unload_key(uint8_t slot) { SHCI_CmdStatus_t shci_state = SHCI_C2_FUS_UnloadUsrKey(slot); furi_assert(shci_state == SHCI_Success); - FURI_CRITICAL_ENTER(); - LL_AHB2_GRP1_ForceReset(LL_AHB2_GRP1_PERIPH_AES1); - LL_AHB2_GRP1_ReleaseReset(LL_AHB2_GRP1_PERIPH_AES1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusAES1); furi_check(furi_mutex_release(furi_hal_crypto_mutex) == FuriStatusOk); return (shci_state == SHCI_Success); diff --git a/firmware/targets/f7/furi_hal/furi_hal_dma.c b/firmware/targets/f7/furi_hal/furi_hal_dma.c new file mode 100644 index 000000000..a6a30d906 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_dma.c @@ -0,0 +1,14 @@ +#include +#include + +void furi_hal_dma_init_early() { + furi_hal_bus_enable(FuriHalBusDMA1); + furi_hal_bus_enable(FuriHalBusDMA2); + furi_hal_bus_enable(FuriHalBusDMAMUX1); +} + +void furi_hal_dma_deinit_early() { + furi_hal_bus_disable(FuriHalBusDMA1); + furi_hal_bus_disable(FuriHalBusDMA2); + furi_hal_bus_disable(FuriHalBusDMAMUX1); +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_dma.h b/firmware/targets/f7/furi_hal/furi_hal_dma.h new file mode 100644 index 000000000..cadcc7733 --- /dev/null +++ b/firmware/targets/f7/furi_hal/furi_hal_dma.h @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** Early initialization */ +void furi_hal_dma_init_early(); + +/** Early de-initialization */ +void furi_hal_dma_deinit_early(); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/furi_hal/furi_hal_flash.c b/firmware/targets/f7/furi_hal/furi_hal_flash.c index 94d269345..796d20b19 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_flash.c +++ b/firmware/targets/f7/furi_hal/furi_hal_flash.c @@ -11,20 +11,20 @@ #define TAG "FuriHalFlash" #define FURI_HAL_CRITICAL_MSG "Critical flash operation fail" -#define FURI_HAL_FLASH_READ_BLOCK 8 -#define FURI_HAL_FLASH_WRITE_BLOCK 8 -#define FURI_HAL_FLASH_PAGE_SIZE 4096 -#define FURI_HAL_FLASH_CYCLES_COUNT 10000 -#define FURI_HAL_FLASH_TIMEOUT 1000 -#define FURI_HAL_FLASH_KEY1 0x45670123U -#define FURI_HAL_FLASH_KEY2 0xCDEF89ABU -#define FURI_HAL_FLASH_TOTAL_PAGES 256 +#define FURI_HAL_FLASH_READ_BLOCK (8U) +#define FURI_HAL_FLASH_WRITE_BLOCK (8U) +#define FURI_HAL_FLASH_PAGE_SIZE (4096U) +#define FURI_HAL_FLASH_CYCLES_COUNT (10000U) +#define FURI_HAL_FLASH_TIMEOUT (1000U) +#define FURI_HAL_FLASH_KEY1 (0x45670123U) +#define FURI_HAL_FLASH_KEY2 (0xCDEF89ABU) +#define FURI_HAL_FLASH_TOTAL_PAGES (256U) #define FURI_HAL_FLASH_SR_ERRORS \ (FLASH_SR_OPERR | FLASH_SR_PROGERR | FLASH_SR_WRPERR | FLASH_SR_PGAERR | FLASH_SR_SIZERR | \ FLASH_SR_PGSERR | FLASH_SR_MISERR | FLASH_SR_FASTERR | FLASH_SR_RDERR | FLASH_SR_OPTVERR) -#define FURI_HAL_FLASH_OPT_KEY1 0x08192A3B -#define FURI_HAL_FLASH_OPT_KEY2 0x4C5D6E7F +#define FURI_HAL_FLASH_OPT_KEY1 (0x08192A3BU) +#define FURI_HAL_FLASH_OPT_KEY2 (0x4C5D6E7FU) #define FURI_HAL_FLASH_OB_TOTAL_WORDS (0x80 / (sizeof(uint32_t) * 2)) /* STM32CubeWB/Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_RfWithFlash/Core/Src/flash_driver.c @@ -35,7 +35,7 @@ > If for any reason this test is never passed, this means there is a failure in the system and there is no other > way to recover than applying a device reset. */ -#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS 3000u /* 3 seconds */ +#define FURI_HAL_FLASH_C2_LOCK_TIMEOUT_MS (3000U) /* 3 seconds */ #define IS_ADDR_ALIGNED_64BITS(__VALUE__) (((__VALUE__)&0x7U) == (0x00UL)) #define IS_FLASH_PROGRAM_ADDRESS(__VALUE__) \ diff --git a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c b/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c index afc4fdf52..f9d88abb3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c +++ b/firmware/targets/f7/furi_hal/furi_hal_i2c_config.c @@ -1,7 +1,8 @@ #include #include #include -#include +#include + #include /** Timing register value is computed with the STM32CubeMX Tool, @@ -21,17 +22,9 @@ FuriMutex* furi_hal_i2c_bus_power_mutex = NULL; static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { if(event == FuriHalI2cBusEventInit) { furi_hal_i2c_bus_power_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalI2cBusEventDeinit) { furi_mutex_free(furi_hal_i2c_bus_power_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventLock) { furi_check( furi_mutex_acquire(furi_hal_i2c_bus_power_mutex, FuriWaitForever) == FuriStatusOk); @@ -39,12 +32,11 @@ static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent furi_check(furi_mutex_release(furi_hal_i2c_bus_power_mutex) == FuriStatusOk); } else if(event == FuriHalI2cBusEventActivate) { FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); + furi_hal_bus_enable(FuriHalBusI2C1); + LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusI2C1); } } @@ -58,17 +50,9 @@ FuriMutex* furi_hal_i2c_bus_external_mutex = NULL; static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { if(event == FuriHalI2cBusEventInit) { furi_hal_i2c_bus_external_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalI2cBusEventDeinit) { furi_mutex_free(furi_hal_i2c_bus_external_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventLock) { furi_check( furi_mutex_acquire(furi_hal_i2c_bus_external_mutex, FuriWaitForever) == FuriStatusOk); @@ -76,13 +60,11 @@ static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEve furi_check(furi_mutex_release(furi_hal_i2c_bus_external_mutex) == FuriStatusOk); } else if(event == FuriHalI2cBusEventActivate) { FURI_CRITICAL_ENTER(); + furi_hal_bus_enable(FuriHalBusI2C3); LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3); FURI_CRITICAL_EXIT(); } else if(event == FuriHalI2cBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusI2C3); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c index c8041c9f2..f8f7e4966 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c +++ b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c @@ -1,14 +1,15 @@ #include #include #include +#include #include -#include #include #define TAG "FuriHalIbutton" #define FURI_HAL_IBUTTON_TIMER TIM1 +#define FURI_HAL_IBUTTON_TIMER_BUS FuriHalBusTIM1 #define FURI_HAL_IBUTTON_TIMER_IRQ FuriHalInterruptIdTim1UpTim16 typedef enum { @@ -49,9 +50,7 @@ void furi_hal_ibutton_emulate_start( furi_hal_ibutton->callback = callback; furi_hal_ibutton->context = context; - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_IBUTTON_TIMER); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FURI_HAL_IBUTTON_TIMER_BUS); furi_hal_interrupt_set_isr(FURI_HAL_IBUTTON_TIMER_IRQ, furi_hal_ibutton_emulate_isr, NULL); @@ -81,10 +80,7 @@ void furi_hal_ibutton_emulate_stop() { furi_hal_ibutton->state = FuriHalIbuttonStateIdle; LL_TIM_DisableCounter(FURI_HAL_IBUTTON_TIMER); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_IBUTTON_TIMER); - FURI_CRITICAL_EXIT(); - + furi_hal_bus_disable(FURI_HAL_IBUTTON_TIMER_BUS); furi_hal_interrupt_set_isr(FURI_HAL_IBUTTON_TIMER_IRQ, NULL, NULL); furi_hal_ibutton->callback = NULL; diff --git a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h index 9f91db14e..e1ffb1b25 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h +++ b/firmware/targets/f7/furi_hal/furi_hal_idle_timer.h @@ -1,8 +1,10 @@ #pragma once #include -#include #include +#include + +#include // Timer used for tickless idle #define FURI_HAL_IDLE_TIMER_MAX 0xFFFF @@ -10,6 +12,7 @@ #define FURI_HAL_IDLE_TIMER_IRQ LPTIM1_IRQn static inline void furi_hal_idle_timer_init() { + furi_hal_bus_enable(FuriHalBusLPTIM1); // Configure clock source LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM1_CLKSOURCE_LSE); // There is a theoretical possibility that we need it @@ -40,7 +43,7 @@ static inline void furi_hal_idle_timer_start(uint32_t count) { static inline void furi_hal_idle_timer_reset() { // Hard reset timer // THE ONLY RELIABLE WAY to stop it according to errata - LL_LPTIM_DeInit(FURI_HAL_IDLE_TIMER); + furi_hal_bus_reset(FuriHalBusLPTIM1); // Prevent IRQ handler call NVIC_ClearPendingIRQ(FURI_HAL_IDLE_TIMER_IRQ); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_info.c b/firmware/targets/f7/furi_hal/furi_hal_info.c index 4c034ff35..47672c97a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_info.c +++ b/firmware/targets/f7/furi_hal/furi_hal_info.c @@ -26,7 +26,7 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { property_value_out(&property_context, NULL, 2, "format", "minor", "1"); } else { property_value_out(&property_context, NULL, 3, "device", "info", "major", "2"); - property_value_out(&property_context, NULL, 3, "device", "info", "minor", "1"); + property_value_out(&property_context, NULL, 3, "device", "info", "minor", "2"); } // Model name @@ -173,6 +173,24 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { &property_context, "%d", 3, "firmware", "api", "major", api_version_major); property_value_out( &property_context, "%d", 3, "firmware", "api", "minor", api_version_minor); + + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "origin", + "fork", + version_get_firmware_origin(firmware_version)); + + property_value_out( + &property_context, + NULL, + 3, + "firmware", + "origin", + "git", + version_get_git_origin(firmware_version)); } if(furi_hal_bt_is_alive()) { diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index e833c4731..e6fb69307 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -1,14 +1,11 @@ #include -#include -#include "stm32wbxx_ll_dma.h" #include #include +#include -#include #include -#include +#include -#include #include #include @@ -21,13 +18,23 @@ (TIM_CCMR2_OC3PE | LL_TIM_OCMODE_FORCED_INACTIVE) /* Space time - force low */ /* DMA Channels definition */ -#define IR_DMA DMA2 -#define IR_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 -#define IR_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 -#define IR_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 -#define IR_DMA_CH2_IRQ FuriHalInterruptIdDma2Ch2 -#define IR_DMA_CH1_DEF IR_DMA, IR_DMA_CH1_CHANNEL -#define IR_DMA_CH2_DEF IR_DMA, IR_DMA_CH2_CHANNEL +#define INFRARED_DMA DMA2 +#define INFRARED_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 +#define INFRARED_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 +#define INFRARED_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 +#define INFRARED_DMA_CH2_IRQ FuriHalInterruptIdDma2Ch2 +#define INFRARED_DMA_CH1_DEF INFRARED_DMA, INFRARED_DMA_CH1_CHANNEL +#define INFRARED_DMA_CH2_DEF INFRARED_DMA, INFRARED_DMA_CH2_CHANNEL + +/* Timers definition */ +#define INFRARED_RX_TIMER TIM2 +#define INFRARED_DMA_TIMER TIM1 +#define INFRARED_RX_TIMER_BUS FuriHalBusTIM2 +#define INFRARED_DMA_TIMER_BUS FuriHalBusTIM1 + +/* Misc */ +#define INFRARED_RX_GPIO_ALT GpioAltFn1TIM2 +#define INFRARED_RX_IRQ FuriHalInterruptIdTIM2 typedef struct { FuriHalInfraredRxCaptureCallback capture_callback; @@ -94,8 +101,8 @@ static void furi_hal_infrared_tim_rx_isr() { static uint32_t previous_captured_ch2 = 0; /* Timeout */ - if(LL_TIM_IsActiveFlag_CC3(TIM2)) { - LL_TIM_ClearFlag_CC3(TIM2); + if(LL_TIM_IsActiveFlag_CC3(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC3(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); /* Timers CNT register starts to counting from 0 to ARR, but it is @@ -111,13 +118,13 @@ static void furi_hal_infrared_tim_rx_isr() { } /* Rising Edge */ - if(LL_TIM_IsActiveFlag_CC1(TIM2)) { - LL_TIM_ClearFlag_CC1(TIM2); + if(LL_TIM_IsActiveFlag_CC1(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC1(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); - if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC1S)) { + if(READ_BIT(INFRARED_RX_TIMER->CCMR1, TIM_CCMR1_CC1S)) { /* Low pin level is a Mark state of INFRARED signal. Invert level for further processing. */ - uint32_t duration = LL_TIM_IC_GetCaptureCH1(TIM2) - previous_captured_ch2; + uint32_t duration = LL_TIM_IC_GetCaptureCH1(INFRARED_RX_TIMER) - previous_captured_ch2; if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 1, duration); } else { @@ -126,13 +133,13 @@ static void furi_hal_infrared_tim_rx_isr() { } /* Falling Edge */ - if(LL_TIM_IsActiveFlag_CC2(TIM2)) { - LL_TIM_ClearFlag_CC2(TIM2); + if(LL_TIM_IsActiveFlag_CC2(INFRARED_RX_TIMER)) { + LL_TIM_ClearFlag_CC2(INFRARED_RX_TIMER); furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); - if(READ_BIT(TIM2->CCMR1, TIM_CCMR1_CC2S)) { + if(READ_BIT(INFRARED_RX_TIMER->CCMR1, TIM_CCMR1_CC2S)) { /* High pin level is a Space state of INFRARED signal. Invert level for further processing. */ - uint32_t duration = LL_TIM_IC_GetCaptureCH2(TIM2); + uint32_t duration = LL_TIM_IC_GetCaptureCH2(INFRARED_RX_TIMER); previous_captured_ch2 = duration; if(infrared_tim_rx.capture_callback) infrared_tim_rx.capture_callback(infrared_tim_rx.capture_context, 0, duration); @@ -146,62 +153,66 @@ void furi_hal_infrared_async_rx_start(void) { furi_assert(furi_hal_infrared_state == InfraredStateIdle); furi_hal_gpio_init_ex( - &gpio_infrared_rx, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn1TIM2); + &gpio_infrared_rx, + GpioModeAltFunctionPushPull, + GpioPullNo, + GpioSpeedLow, + INFRARED_RX_GPIO_ALT); + + furi_hal_bus_enable(INFRARED_RX_TIMER_BUS); LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP; TIM_InitStruct.Autoreload = 0x7FFFFFFE; TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1; - LL_TIM_Init(TIM2, &TIM_InitStruct); + LL_TIM_Init(INFRARED_RX_TIMER, &TIM_InitStruct); - LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); - LL_TIM_DisableARRPreload(TIM2); - LL_TIM_SetTriggerInput(TIM2, LL_TIM_TS_TI1FP1); - LL_TIM_SetSlaveMode(TIM2, LL_TIM_SLAVEMODE_RESET); - LL_TIM_CC_DisableChannel(TIM2, LL_TIM_CHANNEL_CH2); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); - LL_TIM_DisableIT_TRIG(TIM2); - LL_TIM_DisableDMAReq_TRIG(TIM2); - LL_TIM_SetTriggerOutput(TIM2, LL_TIM_TRGO_RESET); - LL_TIM_EnableMasterSlaveMode(TIM2); - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); - LL_TIM_IC_SetFilter(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); - LL_TIM_IC_SetPolarity(TIM2, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); - LL_TIM_IC_SetActiveInput(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); - LL_TIM_IC_SetPrescaler(TIM2, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); + LL_TIM_SetClockSource(INFRARED_RX_TIMER, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableARRPreload(INFRARED_RX_TIMER); + LL_TIM_SetTriggerInput(INFRARED_RX_TIMER, LL_TIM_TS_TI1FP1); + LL_TIM_SetSlaveMode(INFRARED_RX_TIMER, LL_TIM_SLAVEMODE_RESET); + LL_TIM_CC_DisableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2); + LL_TIM_IC_SetFilter(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_IC_POLARITY_FALLING); + LL_TIM_DisableIT_TRIG(INFRARED_RX_TIMER); + LL_TIM_DisableDMAReq_TRIG(INFRARED_RX_TIMER); + LL_TIM_SetTriggerOutput(INFRARED_RX_TIMER, LL_TIM_TRGO_RESET); + LL_TIM_EnableMasterSlaveMode(INFRARED_RX_TIMER); + LL_TIM_IC_SetActiveInput(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI); + LL_TIM_IC_SetPrescaler(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1); + LL_TIM_IC_SetFilter(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1); + LL_TIM_IC_SetPolarity(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING); + LL_TIM_IC_SetActiveInput(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_ACTIVEINPUT_INDIRECTTI); + LL_TIM_IC_SetPrescaler(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2, LL_TIM_ICPSC_DIV1); - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, furi_hal_infrared_tim_rx_isr, NULL); + furi_hal_interrupt_set_isr(INFRARED_RX_IRQ, furi_hal_infrared_tim_rx_isr, NULL); furi_hal_infrared_state = InfraredStateAsyncRx; - LL_TIM_EnableIT_CC1(TIM2); - LL_TIM_EnableIT_CC2(TIM2); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH1); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH2); + LL_TIM_EnableIT_CC1(INFRARED_RX_TIMER); + LL_TIM_EnableIT_CC2(INFRARED_RX_TIMER); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH2); - LL_TIM_SetCounter(TIM2, 0); - LL_TIM_EnableCounter(TIM2); + LL_TIM_SetCounter(INFRARED_RX_TIMER, 0); + LL_TIM_EnableCounter(INFRARED_RX_TIMER); } void furi_hal_infrared_async_rx_stop(void) { furi_assert(furi_hal_infrared_state == InfraredStateAsyncRx); FURI_CRITICAL_ENTER(); - - LL_TIM_DeInit(TIM2); - furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); + furi_hal_bus_disable(INFRARED_RX_TIMER_BUS); + furi_hal_interrupt_set_isr(INFRARED_RX_IRQ, NULL, NULL); furi_hal_infrared_state = InfraredStateIdle; - FURI_CRITICAL_EXIT(); } void furi_hal_infrared_async_rx_set_timeout(uint32_t timeout_us) { - LL_TIM_OC_SetCompareCH3(TIM2, timeout_us); - LL_TIM_OC_SetMode(TIM2, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); - LL_TIM_CC_EnableChannel(TIM2, LL_TIM_CHANNEL_CH3); - LL_TIM_EnableIT_CC3(TIM2); + LL_TIM_OC_SetCompareCH3(INFRARED_RX_TIMER, timeout_us); + LL_TIM_OC_SetMode(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_ACTIVE); + LL_TIM_CC_EnableChannel(INFRARED_RX_TIMER, LL_TIM_CHANNEL_CH3); + LL_TIM_EnableIT_CC3(INFRARED_RX_TIMER); } bool furi_hal_infrared_is_busy(void) { @@ -223,16 +234,16 @@ void furi_hal_infrared_async_rx_set_timeout_isr_callback( } static void furi_hal_infrared_tx_dma_terminate(void) { - LL_DMA_DisableIT_TC(IR_DMA_CH1_DEF); - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); - LL_DMA_DisableIT_TC(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH1_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH2_DEF); furi_assert(furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress); - LL_DMA_DisableIT_TC(IR_DMA_CH1_DEF); - LL_DMA_DisableChannel(IR_DMA_CH2_DEF); - LL_DMA_DisableChannel(IR_DMA_CH1_DEF); - LL_TIM_DisableCounter(TIM1); + LL_DMA_DisableIT_TC(INFRARED_DMA_CH1_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH2_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH1_DEF); + LL_TIM_DisableCounter(INFRARED_DMA_TIMER); FuriStatus status = furi_semaphore_release(infrared_tim_tx.stop_semaphore); furi_check(status == FuriStatusOk); furi_hal_infrared_state = InfraredStateAsyncTxStopped; @@ -240,7 +251,7 @@ static void furi_hal_infrared_tx_dma_terminate(void) { static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { uint8_t buf_num = 0; - uint32_t buffer_adr = LL_DMA_GetMemoryAddress(IR_DMA_CH2_DEF); + uint32_t buffer_adr = LL_DMA_GetMemoryAddress(INFRARED_DMA_CH2_DEF); if(buffer_adr == (uint32_t)infrared_tim_tx.buffer[0].data) { buf_num = 0; } else if(buffer_adr == (uint32_t)infrared_tim_tx.buffer[1].data) { @@ -252,13 +263,13 @@ static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { } static void furi_hal_infrared_tx_dma_polarity_isr() { -#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 - if(LL_DMA_IsActiveFlag_TE1(IR_DMA)) { - LL_DMA_ClearFlag_TE1(IR_DMA); +#if INFRARED_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + if(LL_DMA_IsActiveFlag_TE1(INFRARED_DMA)) { + LL_DMA_ClearFlag_TE1(INFRARED_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_TC1(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH1_DEF)) { - LL_DMA_ClearFlag_TC1(IR_DMA); + if(LL_DMA_IsActiveFlag_TC1(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH1_DEF)) { + LL_DMA_ClearFlag_TC1(INFRARED_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTx) || @@ -274,23 +285,23 @@ static void furi_hal_infrared_tx_dma_polarity_isr() { } static void furi_hal_infrared_tx_dma_isr() { -#if IR_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 - if(LL_DMA_IsActiveFlag_TE2(IR_DMA)) { - LL_DMA_ClearFlag_TE2(IR_DMA); +#if INFRARED_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 + if(LL_DMA_IsActiveFlag_TE2(INFRARED_DMA)) { + LL_DMA_ClearFlag_TE2(INFRARED_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_HT2(IR_DMA) && LL_DMA_IsEnabledIT_HT(IR_DMA_CH2_DEF)) { - LL_DMA_ClearFlag_HT2(IR_DMA); + if(LL_DMA_IsActiveFlag_HT2(INFRARED_DMA) && LL_DMA_IsEnabledIT_HT(INFRARED_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_HT2(INFRARED_DMA); uint8_t buf_num = furi_hal_infrared_get_current_dma_tx_buffer(); uint8_t next_buf_num = !buf_num; if(infrared_tim_tx.buffer[buf_num].last_packet_end) { - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); } else if( !infrared_tim_tx.buffer[buf_num].packet_end || (furi_hal_infrared_state == InfraredStateAsyncTx)) { furi_hal_infrared_tx_fill_buffer(next_buf_num, 0); if(infrared_tim_tx.buffer[next_buf_num].last_packet_end) { - LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_HT(INFRARED_DMA_CH2_DEF); } } else if(furi_hal_infrared_state == InfraredStateAsyncTxStopReq) { /* fallthrough */ @@ -298,8 +309,8 @@ static void furi_hal_infrared_tx_dma_isr() { furi_crash(NULL); } } - if(LL_DMA_IsActiveFlag_TC2(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH2_DEF)) { - LL_DMA_ClearFlag_TC2(IR_DMA); + if(LL_DMA_IsActiveFlag_TC2(INFRARED_DMA) && LL_DMA_IsEnabledIT_TC(INFRARED_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_TC2(INFRARED_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress) || (furi_hal_infrared_state == InfraredStateAsyncTxStopReq) || @@ -331,37 +342,42 @@ static void furi_hal_infrared_tx_dma_isr() { } static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cycle) { - LL_TIM_DisableCounter(TIM1); - LL_TIM_SetRepetitionCounter(TIM1, 0); - LL_TIM_SetCounter(TIM1, 0); - LL_TIM_SetPrescaler(TIM1, 0); - LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); - LL_TIM_EnableARRPreload(TIM1); + LL_TIM_DisableCounter(INFRARED_DMA_TIMER); + LL_TIM_SetRepetitionCounter(INFRARED_DMA_TIMER, 0); + LL_TIM_SetCounter(INFRARED_DMA_TIMER, 0); + LL_TIM_SetPrescaler(INFRARED_DMA_TIMER, 0); + LL_TIM_SetCounterMode(INFRARED_DMA_TIMER, LL_TIM_COUNTERMODE_UP); + LL_TIM_EnableARRPreload(INFRARED_DMA_TIMER); LL_TIM_SetAutoReload( - TIM1, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM1), freq)); + INFRARED_DMA_TIMER, + __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(INFRARED_DMA_TIMER), freq)); if(infrared_external_output) { - LL_TIM_OC_SetCompareCH1(TIM1, ((LL_TIM_GetAutoReload(TIM1) + 1) * (1 - duty_cycle))); - LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH1); + LL_TIM_OC_SetCompareCH1( + INFRARED_DMA_TIMER, + ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1); /* LL_TIM_OCMODE_PWM2 set by DMA */ - LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE); - LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH); - LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH1); - LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH1N); - LL_TIM_DisableIT_CC1(TIM1); + LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1); + LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N); + LL_TIM_DisableIT_CC1(INFRARED_DMA_TIMER); } else { - LL_TIM_OC_SetCompareCH3(TIM1, ((LL_TIM_GetAutoReload(TIM1) + 1) * (1 - duty_cycle))); - LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH3); + LL_TIM_OC_SetCompareCH3( + INFRARED_DMA_TIMER, + ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle))); + LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3); /* LL_TIM_OCMODE_PWM2 set by DMA */ - LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE); - LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH); - LL_TIM_OC_DisableFast(TIM1, LL_TIM_CHANNEL_CH3); - LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH3N); - LL_TIM_DisableIT_CC3(TIM1); + LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE); + LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH); + LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3); + LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N); + LL_TIM_DisableIT_CC3(INFRARED_DMA_TIMER); } - LL_TIM_DisableMasterSlaveMode(TIM1); - LL_TIM_EnableAllOutputs(TIM1); - LL_TIM_DisableIT_UPDATE(TIM1); - LL_TIM_EnableDMAReq_UPDATE(TIM1); + LL_TIM_DisableMasterSlaveMode(INFRARED_DMA_TIMER); + LL_TIM_EnableAllOutputs(INFRARED_DMA_TIMER); + LL_TIM_DisableIT_UPDATE(INFRARED_DMA_TIMER); + LL_TIM_EnableDMAReq_UPDATE(INFRARED_DMA_TIMER); NVIC_SetPriority(TIM1_UP_TIM16_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); @@ -370,9 +386,9 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) { LL_DMA_InitTypeDef dma_config = {0}; if(infrared_external_output) { - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR1); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1); } else { - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR2); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR2); } dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; @@ -385,24 +401,25 @@ static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) { dma_config.NbData = 0; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH; - LL_DMA_Init(IR_DMA_CH1_DEF, &dma_config); + LL_DMA_Init(INFRARED_DMA_CH1_DEF, &dma_config); -#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 - LL_DMA_ClearFlag_TE1(IR_DMA); - LL_DMA_ClearFlag_TC1(IR_DMA); +#if INFRARED_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + LL_DMA_ClearFlag_TE1(INFRARED_DMA); + LL_DMA_ClearFlag_TC1(INFRARED_DMA); #else #error Update this code. Would you kindly? #endif - LL_DMA_EnableIT_TE(IR_DMA_CH1_DEF); - LL_DMA_EnableIT_TC(IR_DMA_CH1_DEF); + LL_DMA_EnableIT_TE(INFRARED_DMA_CH1_DEF); + LL_DMA_EnableIT_TC(INFRARED_DMA_CH1_DEF); - furi_hal_interrupt_set_isr_ex(IR_DMA_CH1_IRQ, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); + furi_hal_interrupt_set_isr_ex( + INFRARED_DMA_CH1_IRQ, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); } static void furi_hal_infrared_configure_tim_rcr_dma_tx(void) { LL_DMA_InitTypeDef dma_config = {0}; - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->RCR); + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->RCR); dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_NORMAL; @@ -413,21 +430,21 @@ static void furi_hal_infrared_configure_tim_rcr_dma_tx(void) { dma_config.NbData = 0; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM1_UP; dma_config.Priority = LL_DMA_PRIORITY_MEDIUM; - LL_DMA_Init(IR_DMA_CH2_DEF, &dma_config); + LL_DMA_Init(INFRARED_DMA_CH2_DEF, &dma_config); -#if IR_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 - LL_DMA_ClearFlag_TC2(IR_DMA); - LL_DMA_ClearFlag_HT2(IR_DMA); - LL_DMA_ClearFlag_TE2(IR_DMA); +#if INFRARED_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 + LL_DMA_ClearFlag_TC2(INFRARED_DMA); + LL_DMA_ClearFlag_HT2(INFRARED_DMA); + LL_DMA_ClearFlag_TE2(INFRARED_DMA); #else #error Update this code. Would you kindly? #endif - LL_DMA_EnableIT_TC(IR_DMA_CH2_DEF); - LL_DMA_EnableIT_HT(IR_DMA_CH2_DEF); - LL_DMA_EnableIT_TE(IR_DMA_CH2_DEF); + LL_DMA_EnableIT_TC(INFRARED_DMA_CH2_DEF); + LL_DMA_EnableIT_HT(INFRARED_DMA_CH2_DEF); + LL_DMA_EnableIT_TE(INFRARED_DMA_CH2_DEF); - furi_hal_interrupt_set_isr_ex(IR_DMA_CH2_IRQ, 5, furi_hal_infrared_tx_dma_isr, NULL); + furi_hal_interrupt_set_isr_ex(INFRARED_DMA_CH2_IRQ, 5, furi_hal_infrared_tx_dma_isr, NULL); } static void furi_hal_infrared_tx_fill_buffer_last(uint8_t buf_num) { @@ -529,14 +546,14 @@ static void furi_hal_infrared_tx_dma_set_polarity(uint8_t buf_num, uint8_t polar furi_assert(buffer->polarity != NULL); FURI_CRITICAL_ENTER(); - bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH1_DEF); + bool channel_enabled = LL_DMA_IsEnabledChannel(INFRARED_DMA_CH1_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(IR_DMA_CH1_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH1_DEF); } - LL_DMA_SetMemoryAddress(IR_DMA_CH1_DEF, (uint32_t)buffer->polarity); - LL_DMA_SetDataLength(IR_DMA_CH1_DEF, buffer->size + polarity_shift); + LL_DMA_SetMemoryAddress(INFRARED_DMA_CH1_DEF, (uint32_t)buffer->polarity); + LL_DMA_SetDataLength(INFRARED_DMA_CH1_DEF, buffer->size + polarity_shift); if(channel_enabled) { - LL_DMA_EnableChannel(IR_DMA_CH1_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH1_DEF); } FURI_CRITICAL_EXIT(); } @@ -549,14 +566,14 @@ static void furi_hal_infrared_tx_dma_set_buffer(uint8_t buf_num) { /* non-circular mode requires disabled channel before setup */ FURI_CRITICAL_ENTER(); - bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH2_DEF); + bool channel_enabled = LL_DMA_IsEnabledChannel(INFRARED_DMA_CH2_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(IR_DMA_CH2_DEF); + LL_DMA_DisableChannel(INFRARED_DMA_CH2_DEF); } - LL_DMA_SetMemoryAddress(IR_DMA_CH2_DEF, (uint32_t)buffer->data); - LL_DMA_SetDataLength(IR_DMA_CH2_DEF, buffer->size); + LL_DMA_SetMemoryAddress(INFRARED_DMA_CH2_DEF, (uint32_t)buffer->data); + LL_DMA_SetDataLength(INFRARED_DMA_CH2_DEF, buffer->size); if(channel_enabled) { - LL_DMA_EnableChannel(IR_DMA_CH2_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH2_DEF); } FURI_CRITICAL_EXIT(); } @@ -571,9 +588,10 @@ static void furi_hal_infrared_async_tx_free_resources(void) { } else { furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow); } - furi_hal_interrupt_set_isr(IR_DMA_CH1_IRQ, NULL, NULL); - furi_hal_interrupt_set_isr(IR_DMA_CH2_IRQ, NULL, NULL); - LL_TIM_DeInit(TIM1); + furi_hal_interrupt_set_isr(INFRARED_DMA_CH1_IRQ, NULL, NULL); + furi_hal_interrupt_set_isr(INFRARED_DMA_CH2_IRQ, NULL, NULL); + + furi_hal_bus_disable(INFRARED_DMA_TIMER_BUS); furi_semaphore_free(infrared_tim_tx.stop_semaphore); free(infrared_tim_tx.buffer[0].data); @@ -614,6 +632,8 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { furi_hal_infrared_tx_fill_buffer(0, INFRARED_POLARITY_SHIFT); + furi_hal_bus_enable(INFRARED_DMA_TIMER_BUS); + furi_hal_infrared_configure_tim_pwm_tx(freq, duty_cycle); furi_hal_infrared_configure_tim_cmgr2_dma_tx(); furi_hal_infrared_configure_tim_rcr_dma_tx(); @@ -622,11 +642,11 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { furi_hal_infrared_state = InfraredStateAsyncTx; - LL_TIM_ClearFlag_UPDATE(TIM1); - LL_DMA_EnableChannel(IR_DMA_CH1_DEF); - LL_DMA_EnableChannel(IR_DMA_CH2_DEF); + LL_TIM_ClearFlag_UPDATE(INFRARED_DMA_TIMER); + LL_DMA_EnableChannel(INFRARED_DMA_CH1_DEF); + LL_DMA_EnableChannel(INFRARED_DMA_CH2_DEF); furi_delay_us(5); - LL_TIM_GenerateEvent_UPDATE(TIM1); /* DMA -> TIMx_RCR */ + LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* DMA -> TIMx_RCR */ furi_delay_us(5); if(infrared_external_output) { LL_GPIO_ResetOutputPin( @@ -646,8 +666,8 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { } FURI_CRITICAL_ENTER(); - LL_TIM_GenerateEvent_UPDATE(TIM1); /* TIMx_RCR -> Repetition counter */ - LL_TIM_EnableCounter(TIM1); + LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */ + LL_TIM_EnableCounter(INFRARED_DMA_TIMER); FURI_CRITICAL_EXIT(); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_pwm.c b/firmware/targets/f7/furi_hal/furi_hal_pwm.c index 8f84b5fd8..7e985cbb1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_pwm.c +++ b/firmware/targets/f7/furi_hal/furi_hal_pwm.c @@ -1,8 +1,7 @@ #include -#include #include +#include -#include #include #include #include @@ -29,9 +28,7 @@ void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) GpioSpeedVeryHigh, GpioAltFn1TIM1); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusTIM1); LL_TIM_SetCounterMode(TIM1, LL_TIM_COUNTERMODE_UP); LL_TIM_SetRepetitionCounter(TIM1, 0); @@ -58,9 +55,7 @@ void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) GpioSpeedVeryHigh, GpioAltFn14LPTIM2); - FURI_CRITICAL_ENTER(); - LL_LPTIM_DeInit(LPTIM2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusLPTIM2); LL_LPTIM_SetUpdateMode(LPTIM2, LL_LPTIM_UPDATE_MODE_ENDOFPERIOD); LL_RCC_SetLPTIMClockSource(LL_RCC_LPTIM2_CLKSOURCE_PCLK1); @@ -80,14 +75,10 @@ void furi_hal_pwm_start(FuriHalPwmOutputId channel, uint32_t freq, uint8_t duty) void furi_hal_pwm_stop(FuriHalPwmOutputId channel) { if(channel == FuriHalPwmOutputIdTim1PA7) { furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusTIM1); } else if(channel == FuriHalPwmOutputIdLptim2PA4) { furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeAnalog); - FURI_CRITICAL_ENTER(); - LL_LPTIM_DeInit(LPTIM2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusLPTIM2); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_random.c b/firmware/targets/f7/furi_hal/furi_hal_random.c index d3461c4d1..cf4b552f6 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_random.c +++ b/firmware/targets/f7/furi_hal/furi_hal_random.c @@ -1,8 +1,9 @@ #include +#include #include -#include #include +#include #include #include @@ -32,6 +33,11 @@ static uint32_t furi_hal_random_read_rng() { return LL_RNG_ReadRandData32(RNG); } +void furi_hal_random_init() { + furi_hal_bus_enable(FuriHalBusRNG); + LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_CLK48); +} + uint32_t furi_hal_random_get() { while(LL_HSEM_1StepLock(HSEM, CFG_HW_RNG_SEMID)) ; @@ -40,6 +46,7 @@ uint32_t furi_hal_random_get() { const uint32_t random_val = furi_hal_random_read_rng(); LL_RNG_Disable(RNG); + ; LL_HSEM_ReleaseLock(HSEM, CFG_HW_RNG_SEMID, 0); return random_val; diff --git a/firmware/targets/f7/furi_hal/furi_hal_resources.c b/firmware/targets/f7/furi_hal/furi_hal_resources.c index f87f2a31a..9d6cd7caf 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f7/furi_hal/furi_hal_resources.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -111,6 +112,13 @@ static void furi_hal_resources_init_input_pins(GpioMode mode) { } void furi_hal_resources_init_early() { + furi_hal_bus_enable(FuriHalBusGPIOA); + furi_hal_bus_enable(FuriHalBusGPIOB); + furi_hal_bus_enable(FuriHalBusGPIOC); + furi_hal_bus_enable(FuriHalBusGPIOD); + furi_hal_bus_enable(FuriHalBusGPIOE); + furi_hal_bus_enable(FuriHalBusGPIOH); + furi_hal_resources_init_input_pins(GpioModeInput); // SD Card stepdown control @@ -155,6 +163,12 @@ void furi_hal_resources_init_early() { void furi_hal_resources_deinit_early() { furi_hal_resources_init_input_pins(GpioModeAnalog); + furi_hal_bus_disable(FuriHalBusGPIOA); + furi_hal_bus_disable(FuriHalBusGPIOB); + furi_hal_bus_disable(FuriHalBusGPIOC); + furi_hal_bus_disable(FuriHalBusGPIOD); + furi_hal_bus_disable(FuriHalBusGPIOE); + furi_hal_bus_disable(FuriHalBusGPIOH); } void furi_hal_resources_init() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index 145e49df2..fa0c19b09 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,15 +10,18 @@ #include #define FURI_HAL_RFID_READ_TIMER TIM1 +#define FURI_HAL_RFID_READ_TIMER_BUS FuriHalBusTIM1 #define FURI_HAL_RFID_READ_TIMER_CHANNEL LL_TIM_CHANNEL_CH1N // We can't use N channel for LL_TIM_OC_Init, so... #define FURI_HAL_RFID_READ_TIMER_CHANNEL_CONFIG LL_TIM_CHANNEL_CH1 #define FURI_HAL_RFID_EMULATE_TIMER TIM2 +#define FURI_HAL_RFID_EMULATE_TIMER_BUS FuriHalBusTIM2 #define FURI_HAL_RFID_EMULATE_TIMER_IRQ FuriHalInterruptIdTIM2 #define FURI_HAL_RFID_EMULATE_TIMER_CHANNEL LL_TIM_CHANNEL_CH3 #define RFID_CAPTURE_TIM TIM2 +#define RFID_CAPTURE_TIM_BUS FuriHalBusTIM2 #define RFID_CAPTURE_IND_CH LL_TIM_CHANNEL_CH3 #define RFID_CAPTURE_DIR_CH LL_TIM_CHANNEL_CH4 @@ -30,7 +34,6 @@ #define RFID_DMA_CH2_DEF RFID_DMA, RFID_DMA_CH2_CHANNEL typedef struct { - FuriHalRfidEmulateCallback callback; FuriHalRfidDMACallback dma_callback; FuriHalRfidReadCaptureCallback read_capture_callback; void* context; @@ -56,11 +59,7 @@ void furi_hal_rfid_init() { COMP_InitStruct.InputPlus = LL_COMP_INPUT_PLUS_IO1; COMP_InitStruct.InputMinus = LL_COMP_INPUT_MINUS_1_2VREFINT; COMP_InitStruct.InputHysteresis = LL_COMP_HYSTERESIS_HIGH; -#ifdef INVERT_RFID_IN - COMP_InitStruct.OutputPolarity = LL_COMP_OUTPUTPOL_INVERTED; -#else COMP_InitStruct.OutputPolarity = LL_COMP_OUTPUTPOL_NONINVERTED; -#endif COMP_InitStruct.OutputBlankingSource = LL_COMP_BLANKINGSRC_NONE; LL_COMP_Init(COMP1, &COMP_InitStruct); LL_COMP_SetCommonWindowMode(__LL_COMP_COMMON_INSTANCE(COMP1), LL_COMP_WINDOWMODE_DISABLE); @@ -92,7 +91,7 @@ void furi_hal_rfid_pins_reset() { furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } -void furi_hal_rfid_pins_emulate() { +static void furi_hal_rfid_pins_emulate() { // ibutton low furi_hal_ibutton_pin_configure(); furi_hal_ibutton_pin_write(false); @@ -113,7 +112,7 @@ void furi_hal_rfid_pins_emulate() { &gpio_rfid_carrier, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn2TIM2); } -void furi_hal_rfid_pins_read() { +static void furi_hal_rfid_pins_read() { // ibutton low furi_hal_ibutton_pin_configure(); furi_hal_ibutton_pin_write(false); @@ -142,10 +141,10 @@ void furi_hal_rfid_pin_pull_pulldown() { furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false); } -void furi_hal_rfid_tim_read(float freq, float duty_cycle) { - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_RFID_READ_TIMER); - FURI_CRITICAL_EXIT(); +void furi_hal_rfid_tim_read_start(float freq, float duty_cycle) { + furi_hal_bus_enable(FURI_HAL_RFID_READ_TIMER_BUS); + + furi_hal_rfid_pins_read(); LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Autoreload = (SystemCoreClock / freq) - 1; @@ -160,23 +159,23 @@ void furi_hal_rfid_tim_read(float freq, float duty_cycle) { FURI_HAL_RFID_READ_TIMER, FURI_HAL_RFID_READ_TIMER_CHANNEL_CONFIG, &TIM_OC_InitStruct); LL_TIM_EnableCounter(FURI_HAL_RFID_READ_TIMER); + + furi_hal_rfid_tim_read_continue(); } -void furi_hal_rfid_tim_read_start() { +void furi_hal_rfid_tim_read_continue() { LL_TIM_EnableAllOutputs(FURI_HAL_RFID_READ_TIMER); } -void furi_hal_rfid_tim_read_stop() { +void furi_hal_rfid_tim_read_pause() { LL_TIM_DisableAllOutputs(FURI_HAL_RFID_READ_TIMER); } -void furi_hal_rfid_tim_emulate(float freq) { - UNUSED(freq); // FIXME - // basic PWM setup with needed freq and internal clock - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); - FURI_CRITICAL_EXIT(); +void furi_hal_rfid_tim_read_stop() { + furi_hal_bus_disable(FURI_HAL_RFID_READ_TIMER_BUS); +} +static void furi_hal_rfid_tim_emulate() { LL_TIM_SetPrescaler(FURI_HAL_RFID_EMULATE_TIMER, 0); LL_TIM_SetCounterMode(FURI_HAL_RFID_EMULATE_TIMER, LL_TIM_COUNTERMODE_UP); LL_TIM_SetAutoReload(FURI_HAL_RFID_EMULATE_TIMER, 1); @@ -201,32 +200,6 @@ void furi_hal_rfid_tim_emulate(float freq) { LL_TIM_GenerateEvent_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); } -static void furi_hal_rfid_emulate_isr() { - if(LL_TIM_IsActiveFlag_UPDATE(FURI_HAL_RFID_EMULATE_TIMER)) { - LL_TIM_ClearFlag_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); - furi_hal_rfid->callback(furi_hal_rfid->context); - } -} - -void furi_hal_rfid_tim_emulate_start(FuriHalRfidEmulateCallback callback, void* context) { - furi_assert(furi_hal_rfid); - - furi_hal_rfid->callback = callback; - furi_hal_rfid->context = context; - - furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, furi_hal_rfid_emulate_isr, NULL); - - LL_TIM_EnableIT_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); - LL_TIM_EnableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); - LL_TIM_EnableCounter(FURI_HAL_RFID_EMULATE_TIMER); -} - -void furi_hal_rfid_tim_emulate_stop() { - LL_TIM_DisableCounter(FURI_HAL_RFID_EMULATE_TIMER); - LL_TIM_DisableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); - furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); -} - static void furi_hal_capture_dma_isr(void* context) { UNUSED(context); @@ -247,15 +220,13 @@ static void furi_hal_capture_dma_isr(void* context) { } void furi_hal_rfid_tim_read_capture_start(FuriHalRfidReadCaptureCallback callback, void* context) { - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(RFID_CAPTURE_TIM); - FURI_CRITICAL_EXIT(); - furi_assert(furi_hal_rfid); furi_hal_rfid->read_capture_callback = callback; furi_hal_rfid->context = context; + furi_hal_bus_enable(RFID_CAPTURE_TIM_BUS); + // Timer: base LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -303,10 +274,7 @@ void furi_hal_rfid_tim_read_capture_stop() { furi_hal_rfid_comp_stop(); furi_hal_interrupt_set_isr(FURI_HAL_RFID_EMULATE_TIMER_IRQ, NULL, NULL); - - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(RFID_CAPTURE_TIM); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(RFID_CAPTURE_TIM_BUS); } static void furi_hal_rfid_dma_isr() { @@ -341,7 +309,8 @@ void furi_hal_rfid_tim_emulate_dma_start( furi_hal_rfid_pins_emulate(); // configure timer - furi_hal_rfid_tim_emulate(125000); + furi_hal_bus_enable(FURI_HAL_RFID_EMULATE_TIMER_BUS); + furi_hal_rfid_tim_emulate(); LL_TIM_OC_SetPolarity( FURI_HAL_RFID_EMULATE_TIMER, FURI_HAL_RFID_EMULATE_TIMER_CHANNEL, LL_TIM_OCPOLARITY_HIGH); LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_EMULATE_TIMER); @@ -405,32 +374,12 @@ void furi_hal_rfid_tim_emulate_dma_stop() { LL_DMA_DeInit(RFID_DMA_CH1_DEF); LL_DMA_DeInit(RFID_DMA_CH2_DEF); - LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); + + furi_hal_bus_disable(FURI_HAL_RFID_EMULATE_TIMER_BUS); FURI_CRITICAL_EXIT(); } -void furi_hal_rfid_tim_reset() { - FURI_CRITICAL_ENTER(); - - LL_TIM_DeInit(FURI_HAL_RFID_READ_TIMER); - LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); - - FURI_CRITICAL_EXIT(); -} - -void furi_hal_rfid_set_emulate_period(uint32_t period) { - LL_TIM_SetAutoReload(FURI_HAL_RFID_EMULATE_TIMER, period); -} - -void furi_hal_rfid_set_emulate_pulse(uint32_t pulse) { -#if FURI_HAL_RFID_EMULATE_TIMER_CHANNEL == LL_TIM_CHANNEL_CH3 - LL_TIM_OC_SetCompareCH3(FURI_HAL_RFID_EMULATE_TIMER, pulse); -#else -#error Update this code. Would you kindly? -#endif -} - void furi_hal_rfid_set_read_period(uint32_t period) { LL_TIM_SetAutoReload(FURI_HAL_RFID_READ_TIMER, period); } @@ -443,12 +392,6 @@ void furi_hal_rfid_set_read_pulse(uint32_t pulse) { #endif } -void furi_hal_rfid_change_read_config(float freq, float duty_cycle) { - uint32_t period = (uint32_t)((SystemCoreClock) / freq) - 1; - furi_hal_rfid_set_read_period(period); - furi_hal_rfid_set_read_pulse(period * duty_cycle); -} - void furi_hal_rfid_comp_start() { LL_COMP_Enable(COMP1); // Magic @@ -483,4 +426,4 @@ void COMP_IRQHandler() { (LL_COMP_ReadOutputLevel(COMP1) == LL_COMP_OUTPUT_LEVEL_LOW), furi_hal_rfid_comp_callback_context); } -} \ 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 36563c1d1..78d9b6658 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.h +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.h @@ -21,14 +21,6 @@ void furi_hal_rfid_init(); */ void furi_hal_rfid_pins_reset(); -/** Config rfid pins to emulate state - */ -void furi_hal_rfid_pins_emulate(); - -/** Config rfid pins to read state - */ -void furi_hal_rfid_pins_read(); - /** Release rfid pull pin */ void furi_hal_rfid_pin_pull_release(); @@ -37,33 +29,24 @@ void furi_hal_rfid_pin_pull_release(); */ void furi_hal_rfid_pin_pull_pulldown(); -/** Config rfid timer to read state - * +/** Start read timer * @param freq timer frequency * @param duty_cycle timer duty cycle, 0.0-1.0 */ -void furi_hal_rfid_tim_read(float freq, float duty_cycle); +void furi_hal_rfid_tim_read_start(float freq, float duty_cycle); -/** Start read timer +/** Pause read timer, to be able to continue later */ -void furi_hal_rfid_tim_read_start(); +void furi_hal_rfid_tim_read_pause(); + +/** Continue read timer + */ +void furi_hal_rfid_tim_read_continue(); /** Stop read timer */ void furi_hal_rfid_tim_read_stop(); -/** Config rfid timer to emulate state - * - * @param freq timer frequency - */ -void furi_hal_rfid_tim_emulate(float freq); - -typedef void (*FuriHalRfidEmulateCallback)(void* context); - -/** Start emulation timer - */ -void furi_hal_rfid_tim_emulate_start(FuriHalRfidEmulateCallback callback, void* context); - typedef void (*FuriHalRfidReadCaptureCallback)(bool level, uint32_t duration, void* context); void furi_hal_rfid_tim_read_capture_start(FuriHalRfidReadCaptureCallback callback, void* context); @@ -81,26 +64,6 @@ void furi_hal_rfid_tim_emulate_dma_start( void furi_hal_rfid_tim_emulate_dma_stop(); -/** Stop emulation timer - */ -void furi_hal_rfid_tim_emulate_stop(); - -/** Config rfid timers to reset state - */ -void furi_hal_rfid_tim_reset(); - -/** Set emulation timer period - * - * @param period overall duration - */ -void furi_hal_rfid_set_emulate_period(uint32_t period); - -/** Set emulation timer pulse - * - * @param pulse duration of high level - */ -void furi_hal_rfid_set_emulate_pulse(uint32_t pulse); - /** Set read timer period * * @param period overall duration @@ -113,13 +76,6 @@ void furi_hal_rfid_set_read_period(uint32_t period); */ void furi_hal_rfid_set_read_pulse(uint32_t pulse); -/** Сhanges the configuration of the RFID timer "on a fly" - * - * @param freq new frequency - * @param duty_cycle new duty cycle - */ -void furi_hal_rfid_change_read_config(float freq, float duty_cycle); - /** Start/Enable comparator */ void furi_hal_rfid_comp_start(); diff --git a/firmware/targets/f7/furi_hal/furi_hal_rtc.c b/firmware/targets/f7/furi_hal/furi_hal_rtc.c index 8dfe1a13e..a8e25faad 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rtc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rtc.c @@ -2,8 +2,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_speaker.c b/firmware/targets/f7/furi_hal/furi_hal_speaker.c index 5421509cc..ad7ed994a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_speaker.c +++ b/firmware/targets/f7/furi_hal/furi_hal_speaker.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -20,16 +21,11 @@ static FuriMutex* furi_hal_speaker_mutex = NULL; void furi_hal_speaker_init() { furi_assert(furi_hal_speaker_mutex == NULL); furi_hal_speaker_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER); - FURI_CRITICAL_EXIT(); FURI_LOG_I(TAG, "Init OK"); } void furi_hal_speaker_deinit() { furi_check(furi_hal_speaker_mutex != NULL); - LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER); - furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow); furi_mutex_free(furi_hal_speaker_mutex); furi_hal_speaker_mutex = NULL; } @@ -39,6 +35,7 @@ bool furi_hal_speaker_acquire(uint32_t timeout) { if(furi_mutex_acquire(furi_hal_speaker_mutex, timeout) == FuriStatusOk) { furi_hal_power_insomnia_enter(); + furi_hal_bus_enable(FuriHalBusTIM16); furi_hal_gpio_init_ex( &gpio_speaker, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn14TIM16); return true; @@ -53,6 +50,8 @@ void furi_hal_speaker_release() { furi_hal_speaker_stop(); furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullDown, GpioSpeedLow); + + furi_hal_bus_disable(FuriHalBusTIM16); furi_hal_power_insomnia_exit(); furi_check(furi_mutex_release(furi_hal_speaker_mutex) == FuriStatusOk); diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c index 695418af1..c73c71a4f 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi_config.c +++ b/firmware/targets/f7/furi_hal/furi_hal_spi_config.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -101,28 +102,17 @@ void furi_hal_spi_config_init() { static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_r_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_r_mutex); - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_r_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_r_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI1); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI1); } } @@ -136,28 +126,17 @@ FuriMutex* furi_hal_spi_bus_d_mutex = NULL; static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { if(event == FuriHalSpiBusEventInit) { furi_hal_spi_bus_d_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); bus->current_handle = NULL; } else if(event == FuriHalSpiBusEventDeinit) { furi_mutex_free(furi_hal_spi_bus_d_mutex); - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); } else if(event == FuriHalSpiBusEventLock) { furi_check(furi_mutex_acquire(furi_hal_spi_bus_d_mutex, FuriWaitForever) == FuriStatusOk); } else if(event == FuriHalSpiBusEventUnlock) { furi_check(furi_mutex_release(furi_hal_spi_bus_d_mutex) == FuriStatusOk); } else if(event == FuriHalSpiBusEventActivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_enable(FuriHalBusSPI2); } else if(event == FuriHalSpiBusEventDeactivate) { - FURI_CRITICAL_ENTER(); - LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); - FURI_CRITICAL_EXIT(); + furi_hal_bus_disable(FuriHalBusSPI2); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_spi_types.h b/firmware/targets/f7/furi_hal/furi_hal_spi_types.h index d2273f38b..ecc18d50d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_spi_types.h +++ b/firmware/targets/f7/furi_hal/furi_hal_spi_types.h @@ -6,8 +6,6 @@ #include #include -#include -#include #ifdef __cplusplus extern "C" { diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index 6c5f37aa1..7008f387a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -597,6 +598,8 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void* furi_hal_subghz_capture_callback = callback; furi_hal_subghz_capture_callback_context = context; + furi_hal_bus_enable(FuriHalBusTIM2); + // Timer: base LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -681,7 +684,7 @@ void furi_hal_subghz_stop_async_rx() { furi_hal_subghz_idle(); FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); // Stop debug furi_hal_subghz_stop_debug(); @@ -860,6 +863,8 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void* LL_DMA_EnableIT_HT(SUBGHZ_DMA_CH1_DEF); LL_DMA_EnableChannel(SUBGHZ_DMA_CH1_DEF); + furi_hal_bus_enable(FuriHalBusTIM2); + // Configure TIM2 LL_TIM_InitTypeDef TIM_InitStruct = {0}; TIM_InitStruct.Prescaler = 64 - 1; @@ -959,7 +964,7 @@ void furi_hal_subghz_stop_async_tx() { // Deinitialize Timer FURI_CRITICAL_ENTER(); - LL_TIM_DeInit(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); // Deinitialize DMA diff --git a/firmware/targets/f7/furi_hal/furi_hal_uart.c b/firmware/targets/f7/furi_hal/furi_hal_uart.c index 71b5c7ba0..209c6be6a 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_uart.c +++ b/firmware/targets/f7/furi_hal/furi_hal_uart.c @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -13,6 +14,9 @@ static void (*irq_cb[2])(uint8_t ev, uint8_t data, void* context); static void* irq_ctx[2]; static void furi_hal_usart_init(uint32_t baud) { + furi_hal_bus_enable(FuriHalBusUSART1); + LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2); + furi_hal_gpio_init_ex( &gpio_usart_tx, GpioModeAltFunctionPushPull, @@ -50,6 +54,9 @@ static void furi_hal_usart_init(uint32_t baud) { } static void furi_hal_lpuart_init(uint32_t baud) { + furi_hal_bus_enable(FuriHalBusLPUART1); + LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1); + furi_hal_gpio_init_ex( &gpio_ext_pc0, GpioModeAltFunctionPushPull, @@ -86,10 +93,11 @@ static void furi_hal_lpuart_init(uint32_t baud) { } void furi_hal_uart_init(FuriHalUartId ch, uint32_t baud) { - if(ch == FuriHalUartIdLPUART1) + if(ch == FuriHalUartIdLPUART1) { furi_hal_lpuart_init(baud); - else if(ch == FuriHalUartIdUSART1) + } else if(ch == FuriHalUartIdUSART1) { furi_hal_usart_init(baud); + } } void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { @@ -126,11 +134,15 @@ void furi_hal_uart_set_br(FuriHalUartId ch, uint32_t baud) { void furi_hal_uart_deinit(FuriHalUartId ch) { furi_hal_uart_set_irq_cb(ch, NULL, NULL); if(ch == FuriHalUartIdUSART1) { - LL_USART_Disable(USART1); + if(furi_hal_bus_is_enabled(FuriHalBusUSART1)) { + furi_hal_bus_disable(FuriHalBusUSART1); + } furi_hal_gpio_init(&gpio_usart_tx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); furi_hal_gpio_init(&gpio_usart_rx, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } else if(ch == FuriHalUartIdLPUART1) { - LL_LPUART_Disable(LPUART1); + if(furi_hal_bus_is_enabled(FuriHalBusLPUART1)) { + furi_hal_bus_disable(FuriHalBusLPUART1); + } furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow); furi_hal_gpio_init(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 011add953..b88168d5d 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -2,7 +2,9 @@ #include #include #include + #include +#include #include #include @@ -86,6 +88,8 @@ static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep); /* Low-level init */ void furi_hal_usb_init(void) { + LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLLSAI1); + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; LL_PWR_EnableVddUSB(); @@ -98,7 +102,10 @@ void furi_hal_usb_init(void) { LL_GPIO_Init(GPIOA, &GPIO_InitStruct); usbd_init(&udev, &usbd_hw, USB_EP0_SIZE, ubuf, sizeof(ubuf)); + + FURI_CRITICAL_ENTER(); usbd_enable(&udev, true); + FURI_CRITICAL_EXIT(); usbd_reg_descr(&udev, usb_descriptor_get); usbd_reg_event(&udev, usbd_evt_susp, susp_evt); @@ -359,8 +366,10 @@ static void usb_process_mode_reinit() { usbd_connect(&udev, false); usb.enabled = false; + FURI_CRITICAL_ENTER(); usbd_enable(&udev, false); usbd_enable(&udev, true); + FURI_CRITICAL_EXIT(); furi_delay_ms(USB_RECONNECT_DELAY); usb_process_mode_start(usb.interface, usb.interface_context); diff --git a/firmware/targets/f7/src/update.c b/firmware/targets/f7/src/update.c index c1e1084c2..c6235a150 100644 --- a/firmware/targets/f7/src/update.c +++ b/firmware/targets/f7/src/update.c @@ -38,6 +38,12 @@ static bool flipper_update_mount_sd() { } static bool flipper_update_init() { + // TODO: Configure missing peripherals properly + furi_hal_bus_enable(FuriHalBusHSEM); + furi_hal_bus_enable(FuriHalBusIPCC); + furi_hal_bus_enable(FuriHalBusRNG); + furi_hal_bus_enable(FuriHalBusUSART1); + furi_hal_clock_init(); furi_hal_rtc_init(); furi_hal_interrupt_init(); diff --git a/firmware/targets/furi_hal_include/furi_hal.h b/firmware/targets/furi_hal_include/furi_hal.h index 3b1e8dc2d..285dbea76 100644 --- a/firmware/targets/furi_hal_include/furi_hal.h +++ b/firmware/targets/furi_hal_include/furi_hal.h @@ -12,9 +12,11 @@ struct STOP_EXTERNING_ME {}; #include #include +#include #include #include #include +#include #include #include #include diff --git a/firmware/targets/furi_hal_include/furi_hal_random.h b/firmware/targets/furi_hal_include/furi_hal_random.h index ee69326f4..5ca9cb723 100644 --- a/firmware/targets/furi_hal_include/furi_hal_random.h +++ b/firmware/targets/furi_hal_include/furi_hal_random.h @@ -6,6 +6,9 @@ extern "C" { #endif +/** Initialize random subsystem */ +void furi_hal_random_init(); + /** Get random value * * @return random value diff --git a/furi/core/core_defines.h b/furi/core/core_defines.h index 830bb191c..4309c20c5 100644 --- a/furi/core/core_defines.h +++ b/furi/core/core_defines.h @@ -78,6 +78,11 @@ extern "C" { #define TOSTRING(x) STRINGIFY(x) #endif +#ifndef CONCATENATE +#define CONCATENATE(a, b) CONCATENATE_(a, b) +#define CONCATENATE_(a, b) a##b +#endif + #ifndef REVERSE_BYTES_U32 #define REVERSE_BYTES_U32(x) \ ((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | (((x)&0x00FF0000) >> 8) | \ diff --git a/lib/digital_signal/digital_signal.c b/lib/digital_signal/digital_signal.c index ae110ed97..c442b37dc 100644 --- a/lib/digital_signal/digital_signal.c +++ b/lib/digital_signal/digital_signal.c @@ -243,10 +243,12 @@ static void digital_signal_stop_timer() { LL_TIM_DisableCounter(TIM2); LL_TIM_DisableUpdateEvent(TIM2); LL_TIM_DisableDMAReq_UPDATE(TIM2); + + furi_hal_bus_disable(FuriHalBusTIM2); } static void digital_signal_setup_timer() { - digital_signal_stop_timer(); + furi_hal_bus_enable(FuriHalBusTIM2); LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); diff --git a/lib/lfrfid/lfrfid_raw_worker.c b/lib/lfrfid/lfrfid_raw_worker.c index 22c0bbd02..aa962a47d 100644 --- a/lib/lfrfid/lfrfid_raw_worker.c +++ b/lib/lfrfid/lfrfid_raw_worker.c @@ -151,9 +151,7 @@ static int32_t lfrfid_raw_read_worker_thread(void* thread_context) { if(file_valid) { // setup carrier - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read(worker->frequency, worker->duty_cycle); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(worker->frequency, worker->duty_cycle); // stabilize detector furi_delay_ms(1500); diff --git a/lib/lfrfid/lfrfid_worker_modes.c b/lib/lfrfid/lfrfid_worker_modes.c index 9b6f16eb1..8a2667774 100644 --- a/lib/lfrfid/lfrfid_worker_modes.c +++ b/lib/lfrfid/lfrfid_worker_modes.c @@ -100,24 +100,21 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( uint32_t timeout, ProtocolId* result_protocol) { LFRFIDWorkerReadState state = LFRFIDWorkerReadTimeout; - furi_hal_rfid_pins_read(); if(feature & LFRFIDFeatureASK) { - furi_hal_rfid_tim_read(125000, 0.5); + furi_hal_rfid_tim_read_start(125000, 0.5); FURI_LOG_D(TAG, "Start ASK"); if(worker->read_cb) { worker->read_cb(LFRFIDWorkerReadStartASK, PROTOCOL_NO, worker->cb_ctx); } } else { - furi_hal_rfid_tim_read(62500, 0.25); + furi_hal_rfid_tim_read_start(62500, 0.25); FURI_LOG_D(TAG, "Start PSK"); if(worker->read_cb) { worker->read_cb(LFRFIDWorkerReadStartPSK, PROTOCOL_NO, worker->cb_ctx); } } - furi_hal_rfid_tim_read_start(); - // stabilize detector lfrfid_worker_delay(worker, LFRFID_WORKER_READ_STABILIZE_TIME_MS); @@ -205,7 +202,7 @@ static LFRFIDWorkerReadState lfrfid_worker_read_internal( average_index = 0; if(worker->read_cb) { - if(average > 0.2 && average < 0.8) { + if(average > 0.2f && average < 0.8f) { if(!card_detected) { card_detected = true; worker->read_cb( diff --git a/lib/lfrfid/tools/t5577.c b/lib/lfrfid/tools/t5577.c index 3444afea3..a931f02cf 100644 --- a/lib/lfrfid/tools/t5577.c +++ b/lib/lfrfid/tools/t5577.c @@ -14,9 +14,7 @@ #define T5577_OPCODE_RESET 0b00 static void t5577_start() { - furi_hal_rfid_tim_read(125000, 0.5); - furi_hal_rfid_pins_read(); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_start(125000, 0.5); // do not ground the antenna furi_hal_rfid_pin_pull_release(); @@ -24,14 +22,13 @@ static void t5577_start() { static void t5577_stop() { furi_hal_rfid_tim_read_stop(); - furi_hal_rfid_tim_reset(); furi_hal_rfid_pins_reset(); } static void t5577_write_gap(uint32_t gap_time) { - furi_hal_rfid_tim_read_stop(); + furi_hal_rfid_tim_read_pause(); furi_delay_us(gap_time * 8); - furi_hal_rfid_tim_read_start(); + furi_hal_rfid_tim_read_continue(); } static void t5577_write_bit(bool value) { @@ -54,7 +51,12 @@ static void t5577_write_reset() { t5577_write_bit(0); } -static void t5577_write_block(uint8_t block, bool lock_bit, uint32_t data) { +static void t5577_write_block_pass( + uint8_t block, + bool lock_bit, + uint32_t data, + bool with_pass, + uint32_t password) { furi_delay_us(T5577_TIMING_WAIT_TIME * 8); // start gap @@ -63,6 +65,13 @@ static void t5577_write_block(uint8_t block, bool lock_bit, uint32_t data) { // opcode for page 0 t5577_write_opcode(T5577_OPCODE_PAGE_0); + // password + if(with_pass) { + for(uint8_t i = 0; i < 32; i++) { + t5577_write_bit((password >> (31 - i)) & 1); + } + } + // lock bit t5577_write_bit(lock_bit); @@ -82,11 +91,26 @@ static void t5577_write_block(uint8_t block, bool lock_bit, uint32_t data) { t5577_write_reset(); } +static void t5577_write_block_simple(uint8_t block, bool lock_bit, uint32_t data) { + t5577_write_block_pass(block, lock_bit, data, false, 0); +} + void t5577_write(LFRFIDT5577* data) { t5577_start(); FURI_CRITICAL_ENTER(); for(size_t i = 0; i < data->blocks_to_write; i++) { - t5577_write_block(i, false, data->block[i]); + t5577_write_block_simple(i, false, data->block[i]); + } + t5577_write_reset(); + FURI_CRITICAL_EXIT(); + t5577_stop(); +} + +void t5577_write_with_pass(LFRFIDT5577* data, uint32_t password) { + t5577_start(); + FURI_CRITICAL_ENTER(); + for(size_t i = 0; i < data->blocks_to_write; i++) { + t5577_write_block_pass(0, false, data->block[i], true, password); } t5577_write_reset(); FURI_CRITICAL_EXIT(); diff --git a/lib/lfrfid/tools/t5577.h b/lib/lfrfid/tools/t5577.h index 6d53b5dc7..c77984476 100644 --- a/lib/lfrfid/tools/t5577.h +++ b/lib/lfrfid/tools/t5577.h @@ -51,6 +51,8 @@ typedef struct { */ void t5577_write(LFRFIDT5577* data); +void t5577_write_with_pass(LFRFIDT5577* data, uint32_t password); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/lib/nfc/parsers/opal.c b/lib/nfc/parsers/opal.c index b5ca37eb6..2a6b5d122 100644 --- a/lib/nfc/parsers/opal.c +++ b/lib/nfc/parsers/opal.c @@ -143,7 +143,7 @@ bool opal_parser_parse(NfcDeviceData* dev_data) { // sign separately, because then we can handle balances of -99..-1 // cents, as the "dollars" division below would result in a positive // zero value. - o->balance = abs(o->balance); + o->balance = abs(o->balance); //-V1081 sign = "-"; } uint8_t cents = o->balance % 100; @@ -164,7 +164,7 @@ bool opal_parser_parse(NfcDeviceData* dev_data) { o->mode = 4; } - const char* mode_str = (o->mode <= 4 ? opal_modes[o->mode] : opal_modes[3]); + const char* mode_str = (o->mode <= 4 ? opal_modes[o->mode] : opal_modes[3]); //-V547 const char* usage_str = (o->usage <= 12 ? opal_usages[o->usage] : opal_usages[13]); furi_string_printf( diff --git a/lib/pulse_reader/pulse_reader.c b/lib/pulse_reader/pulse_reader.c index 74d99fe80..1c3cb4a58 100644 --- a/lib/pulse_reader/pulse_reader.c +++ b/lib/pulse_reader/pulse_reader.c @@ -135,6 +135,7 @@ void pulse_reader_stop(PulseReader* signal) { LL_DMA_DisableChannel(DMA1, signal->dma_channel + 1); LL_DMAMUX_DisableRequestGen(NULL, LL_DMAMUX_REQ_GEN_0); LL_TIM_DisableCounter(TIM2); + furi_hal_bus_disable(FuriHalBusTIM2); furi_hal_gpio_init_simple(signal->gpio, GpioModeAnalog); } @@ -146,6 +147,8 @@ void pulse_reader_start(PulseReader* signal) { signal->dma_config_gpio.MemoryOrM2MDstAddress = (uint32_t)signal->gpio_buffer; signal->dma_config_gpio.NbData = signal->size; + furi_hal_bus_enable(FuriHalBusTIM2); + /* start counter */ LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP); LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1); diff --git a/lib/subghz/blocks/custom_btn.c b/lib/subghz/blocks/custom_btn.c index 275a4c930..1919fc5e4 100644 --- a/lib/subghz/blocks/custom_btn.c +++ b/lib/subghz/blocks/custom_btn.c @@ -1,8 +1,9 @@ -#include "custom_btn.h" +#include "custom_btn_i.h" static uint8_t custom_btn_id = SUBGHZ_CUSTOM_BTN_OK; static uint8_t custom_btn_original = 0; static uint8_t custom_btn_max_btns = 0; +static uint8_t controller_programming_mode = PROG_MODE_OFF; bool subghz_custom_btn_set(uint8_t btn_id) { if(btn_id > custom_btn_max_btns) { @@ -33,8 +34,18 @@ void subghz_custom_btn_set_max(uint8_t b) { void subghz_custom_btns_reset() { custom_btn_original = 0; custom_btn_max_btns = 0; + controller_programming_mode = PROG_MODE_OFF; + custom_btn_id = SUBGHZ_CUSTOM_BTN_OK; } bool subghz_custom_btn_is_allowed() { return custom_btn_max_btns != 0; +} + +void subghz_custom_btn_set_prog_mode(ProgMode prog_mode) { + controller_programming_mode = prog_mode; +} + +ProgMode subghz_custom_btn_get_prog_mode() { + return controller_programming_mode; } \ No newline at end of file diff --git a/lib/subghz/blocks/custom_btn.h b/lib/subghz/blocks/custom_btn.h index af1493740..bae811120 100644 --- a/lib/subghz/blocks/custom_btn.h +++ b/lib/subghz/blocks/custom_btn.h @@ -19,12 +19,8 @@ bool subghz_custom_btn_set(uint8_t btn_id); uint8_t subghz_custom_btn_get(); -void subghz_custom_btn_set_original(uint8_t btn_code); - uint8_t subghz_custom_btn_get_original(); -void subghz_custom_btn_set_max(uint8_t b); - void subghz_custom_btns_reset(); bool subghz_custom_btn_is_allowed(); diff --git a/lib/subghz/blocks/custom_btn_i.h b/lib/subghz/blocks/custom_btn_i.h new file mode 100644 index 000000000..f75ba4068 --- /dev/null +++ b/lib/subghz/blocks/custom_btn_i.h @@ -0,0 +1,17 @@ +#pragma once + +#include "custom_btn.h" + +#define PROG_MODE_OFF (0U) +#define PROG_MODE_KEELOQ_BFT (1U) +#define PROG_MODE_KEELOQ_APRIMATIC (2U) + +typedef uint8_t ProgMode; + +void subghz_custom_btn_set_original(uint8_t btn_code); + +void subghz_custom_btn_set_max(uint8_t b); + +void subghz_custom_btn_set_prog_mode(ProgMode prog_mode); + +ProgMode subghz_custom_btn_get_prog_mode(); \ No newline at end of file diff --git a/lib/subghz/environment.c b/lib/subghz/environment.c index 5ded243c4..bcada8752 100644 --- a/lib/subghz/environment.c +++ b/lib/subghz/environment.c @@ -7,6 +7,8 @@ struct SubGhzEnvironment { const char* came_atomo_rainbow_table_file_name; const char* nice_flor_s_rainbow_table_file_name; const char* alutech_at_4n_rainbow_table_file_name; + const char* mfname; + uint8_t kl_type; }; SubGhzEnvironment* subghz_environment_alloc() { @@ -17,6 +19,8 @@ SubGhzEnvironment* subghz_environment_alloc() { instance->came_atomo_rainbow_table_file_name = NULL; instance->nice_flor_s_rainbow_table_file_name = NULL; instance->alutech_at_4n_rainbow_table_file_name = NULL; + instance->mfname = ""; + instance->kl_type = 0; return instance; } @@ -115,4 +119,10 @@ const char* } else { return NULL; } -} \ No newline at end of file +} + +void subghz_environment_reset_keeloq(SubGhzEnvironment* instance) { + furi_assert(instance); + + subghz_keystore_reset_kl(instance->keystore); +} diff --git a/lib/subghz/environment.h b/lib/subghz/environment.h index 7bd38ba2f..67de48df9 100644 --- a/lib/subghz/environment.h +++ b/lib/subghz/environment.h @@ -110,6 +110,12 @@ void* subghz_environment_get_protocol_registry(SubGhzEnvironment* instance); */ const char* subghz_environment_get_protocol_name_registry(SubGhzEnvironment* instance, size_t idx); +/** + * Resetting the parameters used in the keeloq protocol. + * @param instance Pointer to a SubGhzEnvironment instance + */ +void subghz_environment_reset_keeloq(SubGhzEnvironment* instance); + #ifdef __cplusplus } #endif diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index 281e820f0..1a35550c6 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -5,7 +5,7 @@ #include "../blocks/generic.h" #include "../blocks/math.h" -#include "../blocks/custom_btn.h" +#include "../blocks/custom_btn_i.h" #define TAG "SubGhzProtocoAlutech_at_4n" diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 4723ec99f..cea7ebf6f 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -7,7 +7,7 @@ #include "../blocks/generic.h" #include "../blocks/math.h" -#include "../blocks/custom_btn.h" +#include "../blocks/custom_btn_i.h" #define TAG "SubGhzProtocoCameAtomo" diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index 26b5a20a9..2163c0500 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -10,14 +10,11 @@ #include "../blocks/generic.h" #include "../blocks/math.h" -#include "../blocks/custom_btn.h" +#include "../blocks/custom_btn_i.h" +#include "../subghz_keystore_i.h" #define TAG "SubGhzProtocolKeeloq" -#define KEELOQ_PROG_MODE_OFF (0U) -#define KEELOQ_PROG_MODE_BFT (1U) -#define KEELOQ_PROG_MODE_APRIMATIC (2U) - static const SubGhzBlockConst subghz_protocol_keeloq_const = { .te_short = 400, .te_long = 800, @@ -90,25 +87,6 @@ const SubGhzProtocol subghz_protocol_keeloq = { .encoder = &subghz_protocol_keeloq_encoder, }; -static const char* mfname; -static uint8_t kl_type; -static uint8_t klq_prog_mode; -static uint16_t temp_counter; - -void keeloq_reset_original_btn() { - subghz_custom_btns_reset(); - temp_counter = 0; - klq_prog_mode = KEELOQ_PROG_MODE_OFF; -} - -void keeloq_reset_mfname() { - mfname = ""; -} - -void keeloq_reset_kl_type() { - kl_type = 0; -} - /** * Analysis of received data * @param instance Pointer to a SubGhzBlockGeneric* instance @@ -165,29 +143,32 @@ static bool subghz_protocol_keeloq_gen_data( } // programming mode on / off conditions + ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); if(strcmp(instance->manufacture_name, "BFT") == 0) { // BFT programming mode on / off conditions if(btn == 0xF) { - klq_prog_mode = KEELOQ_PROG_MODE_BFT; - } else if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) { - klq_prog_mode = KEELOQ_PROG_MODE_OFF; + prog_mode = PROG_MODE_KEELOQ_BFT; + } else if(prog_mode == PROG_MODE_KEELOQ_BFT) { + prog_mode = PROG_MODE_OFF; } } else if(strcmp(instance->manufacture_name, "Aprimatic") == 0) { // Aprimatic programming mode on / off conditions if(btn == 0xF) { - klq_prog_mode = KEELOQ_PROG_MODE_APRIMATIC; - } else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) { - klq_prog_mode = KEELOQ_PROG_MODE_OFF; + prog_mode = PROG_MODE_KEELOQ_APRIMATIC; + } else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) { + prog_mode = PROG_MODE_OFF; } } + subghz_custom_btn_set_prog_mode(prog_mode); + // If we using BFT programming mode we will trasmit its seed in hop part like original remote - if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) { + if(prog_mode == PROG_MODE_KEELOQ_BFT) { hop = instance->generic.seed; - } else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) { + } else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) { // If we using Aprimatic programming mode we will trasmit some strange looking hop value, why? cuz manufacturer did it this way :) hop = 0x1A2B3C4D; } - if(counter_up && klq_prog_mode == KEELOQ_PROG_MODE_OFF) { + if(counter_up && prog_mode == PROG_MODE_OFF) { if(instance->generic.cnt < 0xFFFF) { if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { instance->generic.cnt = 0; @@ -198,7 +179,7 @@ static bool subghz_protocol_keeloq_gen_data( instance->generic.cnt = 0; } } - if(klq_prog_mode == KEELOQ_PROG_MODE_OFF) { + if(prog_mode == PROG_MODE_OFF) { // Protocols that do not use encryption if(strcmp(instance->manufacture_name, "Unknown") == 0) { code_found_reverse = subghz_protocol_blocks_reverse_key( @@ -252,7 +233,7 @@ static bool subghz_protocol_keeloq_gen_data( decrypt = btn << 28 | (0x000) << 16 | instance->generic.cnt; // Beninca / Allmatic -> no serial - simple XOR } - + uint8_t kl_type_en = instance->keystore->kl_type; for M_EACH( manufacture_code, @@ -292,21 +273,21 @@ static bool subghz_protocol_keeloq_gen_data( hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); break; case KEELOQ_LEARNING_UNKNOWN: - if(kl_type == 1) { + if(kl_type_en == 1) { hop = subghz_protocol_keeloq_common_encrypt( decrypt, manufacture_code->key); } - if(kl_type == 2) { + if(kl_type_en == 2) { man = subghz_protocol_keeloq_common_normal_learning( fix, manufacture_code->key); hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); } - if(kl_type == 3) { + if(kl_type_en == 3) { man = subghz_protocol_keeloq_common_secure_learning( fix, instance->generic.seed, manufacture_code->key); hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); } - if(kl_type == 4) { + if(kl_type_en == 4) { man = subghz_protocol_keeloq_common_magic_xor_type1_learning( instance->generic.serial, manufacture_code->key); hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); @@ -399,9 +380,10 @@ static bool if(instance->manufacture_name == 0x0) { instance->manufacture_name = ""; } - if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) { + ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); + if(prog_mode == PROG_MODE_KEELOQ_BFT) { instance->manufacture_name = "BFT"; - } else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) { + } else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) { instance->manufacture_name = "Aprimatic"; } uint8_t klq_last_custom_btn = 0xA; @@ -507,7 +489,7 @@ SubGhzProtocolStatus if(flipper_format_read_string( flipper_format, "Manufacture", instance->manufacture_from_file)) { instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file); - mfname = furi_string_get_cstr(instance->manufacture_from_file); + instance->keystore->mfname = instance->manufacture_name; } else { FURI_LOG_D(TAG, "ENCODER: Missing Manufacture"); } @@ -579,7 +561,7 @@ void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) { instance->keystore = subghz_environment_get_keystore(environment); instance->manufacture_from_file = furi_string_alloc(); - klq_prog_mode = KEELOQ_PROG_MODE_OFF; + subghz_custom_btn_set_prog_mode(PROG_MODE_OFF); return instance; } @@ -596,8 +578,9 @@ void subghz_protocol_decoder_keeloq_reset(void* context) { furi_assert(context); SubGhzProtocolDecoderKeeloq* instance = context; instance->decoder.parser_step = KeeloqDecoderStepReset; - mfname = ""; - kl_type = 0; + // TODO + instance->keystore->mfname = ""; + instance->keystore->kl_type = 0; } void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t duration) { @@ -740,9 +723,12 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( uint32_t decrypt = 0; uint64_t man; bool mf_not_set = false; - if(mfname == 0x0) { - mfname = ""; - } + // TODO: + // if(mfname == 0x0) { + // mfname = ""; + // } + + const char* mfname = keystore->mfname; if(strcmp(mfname, "Unknown") == 0) { return 1; @@ -758,7 +744,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; return 1; } break; @@ -770,7 +756,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; return 1; } break; @@ -780,7 +766,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; return 1; } break; @@ -790,7 +776,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; return 1; } break; @@ -800,7 +786,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; return 1; } break; @@ -810,7 +796,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; return 1; } break; @@ -820,7 +806,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; return 1; } break; @@ -829,8 +815,8 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 1; + keystore->mfname = *manufacture_name; + keystore->kl_type = 1; return 1; } @@ -845,8 +831,8 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 1; + keystore->mfname = *manufacture_name; + keystore->kl_type = 1; return 1; } @@ -858,8 +844,8 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 2; + keystore->mfname = *manufacture_name; + keystore->kl_type = 2; return 1; } @@ -868,8 +854,8 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 2; + keystore->mfname = *manufacture_name; + keystore->kl_type = 2; return 1; } @@ -879,8 +865,8 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 3; + keystore->mfname = *manufacture_name; + keystore->kl_type = 3; return 1; } @@ -890,8 +876,8 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 3; + keystore->mfname = *manufacture_name; + keystore->kl_type = 3; return 1; } @@ -901,8 +887,8 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 4; + keystore->mfname = *manufacture_name; + keystore->kl_type = 4; return 1; } @@ -911,8 +897,8 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( decrypt = subghz_protocol_keeloq_common_decrypt(hop, man); if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 4; + keystore->mfname = *manufacture_name; + keystore->kl_type = 4; return 1; } @@ -922,7 +908,7 @@ static uint8_t subghz_protocol_keeloq_check_remote_controller_selector( } *manufacture_name = "Unknown"; - mfname = "Unknown"; + keystore->mfname = "Unknown"; instance->cnt = 0; return 0; @@ -935,18 +921,20 @@ static void subghz_protocol_keeloq_check_remote_controller( uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit); uint32_t key_fix = key >> 32; uint32_t key_hop = key & 0x00000000ffffffff; + static uint16_t temp_counter = 0; // Be careful with prog_mode // If we are in BFT / Aprimatic programming mode we will set previous remembered counter and skip mf keys check - if(klq_prog_mode == KEELOQ_PROG_MODE_OFF) { + ProgMode prog_mode = subghz_custom_btn_get_prog_mode(); + if(prog_mode == PROG_MODE_OFF) { // Check key AN-Motors if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) { *manufacture_name = "AN-Motors"; - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; instance->cnt = key_hop >> 16; } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { *manufacture_name = "HCS101"; - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; instance->cnt = key_hop >> 16; } else { subghz_protocol_keeloq_check_remote_controller_selector( @@ -954,14 +942,17 @@ static void subghz_protocol_keeloq_check_remote_controller( } temp_counter = instance->cnt; - } else if(klq_prog_mode == KEELOQ_PROG_MODE_BFT) { + } else if(prog_mode == PROG_MODE_KEELOQ_BFT) { *manufacture_name = "BFT"; - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; instance->cnt = temp_counter; - } else if(klq_prog_mode == KEELOQ_PROG_MODE_APRIMATIC) { + } else if(prog_mode == PROG_MODE_KEELOQ_APRIMATIC) { *manufacture_name = "Aprimatic"; - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; instance->cnt = temp_counter; + } else { + // Counter protection + furi_crash("Unsuported Prog Mode"); } instance->serial = key_fix & 0x0FFFFFFF; @@ -1052,7 +1043,7 @@ SubGhzProtocolStatus if(flipper_format_read_string( flipper_format, "Manufacture", instance->manufacture_from_file)) { instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file); - mfname = furi_string_get_cstr(instance->manufacture_from_file); + instance->keystore->mfname = instance->manufacture_name; } else { FURI_LOG_D(TAG, "DECODER: Missing Manufacture"); } diff --git a/lib/subghz/protocols/keeloq.h b/lib/subghz/protocols/keeloq.h index 31fdb2198..988b37c24 100644 --- a/lib/subghz/protocols/keeloq.h +++ b/lib/subghz/protocols/keeloq.h @@ -2,8 +2,6 @@ #include "base.h" -#include "../blocks/custom_btn.h" - #ifdef __cplusplus extern "C" { #endif @@ -17,12 +15,6 @@ extern const SubGhzProtocolDecoder subghz_protocol_keeloq_decoder; extern const SubGhzProtocolEncoder subghz_protocol_keeloq_encoder; extern const SubGhzProtocol subghz_protocol_keeloq; -void keeloq_reset_mfname(); - -void keeloq_reset_kl_type(); - -void keeloq_reset_original_btn(); - /** * Allocate SubGhzProtocolEncoderKeeloq. * @param environment Pointer to a SubGhzEnvironment instance diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 5eaa21274..eca9c4e95 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -6,7 +6,7 @@ #include "../blocks/generic.h" #include "../blocks/math.h" -#include "../blocks/custom_btn.h" +#include "../blocks/custom_btn_i.h" /* * https://phreakerclub.com/1615 diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index 7acfb74ac..bf2246292 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -7,7 +7,7 @@ #include "../blocks/generic.h" #include "../blocks/math.h" -#include "../blocks/custom_btn.h" +#include "../blocks/custom_btn_i.h" /* * Help diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 6a159a7ea..5fbd90275 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -7,7 +7,7 @@ #include "../blocks/generic.h" #include "../blocks/math.h" -#include "../blocks/custom_btn.h" +#include "../blocks/custom_btn_i.h" #define TAG "SubGhzProtocolSomfyTelis" diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index 362e34f3c..05afd80a6 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -10,6 +10,8 @@ #include "../blocks/generic.h" #include "../blocks/math.h" +#include "../subghz_keystore_i.h" + #define TAG "SubGhzProtocolStarLine" static const SubGhzBlockConst subghz_protocol_star_line_const = { @@ -83,18 +85,6 @@ const SubGhzProtocol subghz_protocol_star_line = { .encoder = &subghz_protocol_star_line_encoder, }; -static const char* mfname; - -static int kl_type; - -void star_line_reset_mfname() { - mfname = ""; -} - -void star_line_reset_kl_type() { - kl_type = 0; -} - /** * Analysis of received data * @param instance Pointer to a SubGhzBlockGeneric* instance @@ -163,6 +153,7 @@ static bool instance->generic.data, instance->generic.data_count_bit); hop = code_found_reverse & 0x00000000ffffffff; } else { + uint8_t kl_type_en = instance->keystore->kl_type; for M_EACH( manufacture_code, @@ -184,11 +175,11 @@ static bool hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); break; case KEELOQ_LEARNING_UNKNOWN: - if(kl_type == 1) { + if(kl_type_en == 1) { hop = subghz_protocol_keeloq_common_encrypt( decrypt, manufacture_code->key); } - if(kl_type == 2) { + if(kl_type_en == 2) { man = subghz_protocol_keeloq_common_normal_learning( fix, manufacture_code->key); hop = subghz_protocol_keeloq_common_encrypt(decrypt, man); @@ -300,7 +291,7 @@ SubGhzProtocolStatus if(flipper_format_read_string( flipper_format, "Manufacture", instance->manufacture_from_file)) { instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file); - mfname = furi_string_get_cstr(instance->manufacture_from_file); + instance->keystore->mfname = instance->manufacture_name; } else { FURI_LOG_D(TAG, "ENCODER: Missing Manufacture"); } @@ -382,8 +373,9 @@ void subghz_protocol_decoder_star_line_reset(void* context) { furi_assert(context); SubGhzProtocolDecoderStarLine* instance = context; instance->decoder.parser_step = StarLineDecoderStepReset; - mfname = ""; - kl_type = 0; + // TODO + instance->keystore->mfname = ""; + instance->keystore->kl_type = 0; } void subghz_protocol_decoder_star_line_feed(void* context, bool level, uint32_t duration) { @@ -523,9 +515,12 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector( uint32_t decrypt = 0; uint64_t man_normal_learning; bool mf_not_set = false; - if(mfname == 0x0) { - mfname = ""; - } + // TODO: + // if(mfname == 0x0) { + // mfname = ""; + // } + + const char* mfname = keystore->mfname; if(strcmp(mfname, "Unknown") == 0) { return 1; @@ -542,7 +537,7 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector( if(subghz_protocol_star_line_check_decrypt( instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; return 1; } break; @@ -555,7 +550,7 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector( if(subghz_protocol_star_line_check_decrypt( instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; + keystore->mfname = *manufacture_name; return 1; } break; @@ -565,8 +560,8 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector( if(subghz_protocol_star_line_check_decrypt( instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 1; + keystore->mfname = *manufacture_name; + keystore->kl_type = 1; return 1; } // Check for mirrored man @@ -580,8 +575,8 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector( if(subghz_protocol_star_line_check_decrypt( instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 1; + keystore->mfname = *manufacture_name; + keystore->kl_type = 1; return 1; } //########################### @@ -593,8 +588,8 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector( if(subghz_protocol_star_line_check_decrypt( instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 2; + keystore->mfname = *manufacture_name; + keystore->kl_type = 2; return 1; } // Check for mirrored man @@ -604,8 +599,8 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector( if(subghz_protocol_star_line_check_decrypt( instance, decrypt, btn, end_serial)) { *manufacture_name = furi_string_get_cstr(manufacture_code->name); - mfname = *manufacture_name; - kl_type = 2; + keystore->mfname = *manufacture_name; + keystore->kl_type = 2; return 1; } break; @@ -614,7 +609,7 @@ static uint8_t subghz_protocol_star_line_check_remote_controller_selector( } *manufacture_name = "Unknown"; - mfname = "Unknown"; + keystore->mfname = "Unknown"; instance->cnt = 0; return 0; @@ -690,7 +685,7 @@ SubGhzProtocolStatus if(flipper_format_read_string( flipper_format, "Manufacture", instance->manufacture_from_file)) { instance->manufacture_name = furi_string_get_cstr(instance->manufacture_from_file); - mfname = furi_string_get_cstr(instance->manufacture_from_file); + instance->keystore->mfname = instance->manufacture_name; } else { FURI_LOG_D(TAG, "DECODER: Missing Manufacture"); } diff --git a/lib/subghz/protocols/star_line.h b/lib/subghz/protocols/star_line.h index b142a4032..7400e1e01 100644 --- a/lib/subghz/protocols/star_line.h +++ b/lib/subghz/protocols/star_line.h @@ -15,10 +15,6 @@ extern const SubGhzProtocolDecoder subghz_protocol_star_line_decoder; extern const SubGhzProtocolEncoder subghz_protocol_star_line_encoder; extern const SubGhzProtocol subghz_protocol_star_line; -void star_line_reset_mfname(); - -void star_line_reset_kl_type(); - /** * Allocate SubGhzProtocolEncoderStarLine. * @param environment Pointer to a SubGhzEnvironment instance diff --git a/lib/subghz/subghz_keystore.c b/lib/subghz/subghz_keystore.c index e0b1cf6ca..54ed15a99 100644 --- a/lib/subghz/subghz_keystore.c +++ b/lib/subghz/subghz_keystore.c @@ -1,4 +1,5 @@ #include "subghz_keystore.h" +#include "subghz_keystore_i.h" #include #include @@ -26,18 +27,23 @@ typedef enum { SubGhzKeystoreEncryptionAES256, } SubGhzKeystoreEncryption; -struct SubGhzKeystore { - SubGhzKeyArray_t data; -}; - SubGhzKeystore* subghz_keystore_alloc() { SubGhzKeystore* instance = malloc(sizeof(SubGhzKeystore)); SubGhzKeyArray_init(instance->data); + subghz_keystore_reset_kl(instance); + return instance; } +void subghz_keystore_reset_kl(SubGhzKeystore* instance) { + furi_assert(instance); + + instance->mfname = ""; + instance->kl_type = 0; +} + void subghz_keystore_free(SubGhzKeystore* instance) { furi_assert(instance); diff --git a/lib/subghz/subghz_keystore.h b/lib/subghz/subghz_keystore.h index 06ae8adae..dfb5c7373 100644 --- a/lib/subghz/subghz_keystore.h +++ b/lib/subghz/subghz_keystore.h @@ -75,6 +75,8 @@ bool subghz_keystore_raw_encrypted_save( */ bool subghz_keystore_raw_get_data(const char* file_name, size_t offset, uint8_t* data, size_t len); +void subghz_keystore_reset_kl(SubGhzKeystore* instance); + #ifdef __cplusplus } #endif diff --git a/lib/subghz/subghz_keystore_i.h b/lib/subghz/subghz_keystore_i.h new file mode 100644 index 000000000..8bf2f1e51 --- /dev/null +++ b/lib/subghz/subghz_keystore_i.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +struct SubGhzKeystore { + SubGhzKeyArray_t data; + const char* mfname; + uint8_t kl_type; +}; diff --git a/lib/toolbox/version.c b/lib/toolbox/version.c index 70386d96d..41e22ce09 100644 --- a/lib/toolbox/version.c +++ b/lib/toolbox/version.c @@ -5,7 +5,7 @@ #define VERSION_MAGIC (0xBE40u) #define VERSION_MAJOR (0x1u) -#define VERSION_MINOR (0x0u) +#define VERSION_MINOR (0x1u) struct Version { // Header @@ -20,6 +20,9 @@ struct Version { // Payload bits and pieces const uint8_t target; const bool build_is_dirty; + // v 1.1 + const char* firmware_origin; + const char* git_origin; const char* custom_flipper_name; }; @@ -38,6 +41,8 @@ static Version version = { , .target = TARGET, .build_is_dirty = BUILD_DIRTY, + .firmware_origin = FIRMWARE_ORIGIN, + .git_origin = GIT_ORIGIN, .custom_flipper_name = NULL, }; @@ -83,3 +88,11 @@ uint8_t version_get_target(const Version* v) { bool version_get_dirty_flag(const Version* v) { return v ? v->build_is_dirty : version.build_is_dirty; } + +const char* version_get_firmware_origin(const Version* v) { + return v ? v->firmware_origin : version.firmware_origin; +} + +const char* version_get_git_origin(const Version* v) { + return v ? v->git_origin : version.git_origin; +} diff --git a/lib/toolbox/version.h b/lib/toolbox/version.h index 2aa72bc28..568260077 100644 --- a/lib/toolbox/version.h +++ b/lib/toolbox/version.h @@ -100,6 +100,17 @@ uint8_t version_get_target(const Version* v); */ bool version_get_dirty_flag(const Version* v); +/** + * Get firmware origin. "Official" for mainline firmware, fork name for forks. + * Set by FIRMWARE_ORIGIN fbt argument. +*/ +const char* version_get_firmware_origin(const Version* v); + +/** + * Get git repo origin +*/ +const char* version_get_git_origin(const Version* v); + #ifdef __cplusplus } #endif diff --git a/scripts/debug/flipperversion.py b/scripts/debug/flipperversion.py index 4ac3bd200..56915c0f2 100644 --- a/scripts/debug/flipperversion.py +++ b/scripts/debug/flipperversion.py @@ -23,6 +23,10 @@ class VersionData: version: str target: int build_is_dirty: bool + # Since version 1.1 + firmware_origin: str = "" + git_origin: str = "" + # More fields may be added in the future extra: Optional[Dict[str, str]] = field(default_factory=dict) @@ -52,7 +56,7 @@ class VersionLoader: # Struct version 1.0 extra_data = int(self.version_ptr[5].cast(self._uint_type)) - return VersionData( + version_data = VersionData( git_hash=self.version_ptr[1].cast(self._cstr_type).string(), git_branch=self.version_ptr[2].cast(self._cstr_type).string(), build_date=self.version_ptr[3].cast(self._cstr_type).string(), @@ -60,6 +64,12 @@ class VersionLoader: target=extra_data & 0xF, build_is_dirty=bool((extra_data >> 8) & 0xF), ) + if minor >= 1: + version_data.firmware_origin = ( + self.version_ptr[6].cast(self._cstr_type).string() + ) + version_data.git_origin = self.version_ptr[7].cast(self._cstr_type).string() + return version_data def load_unversioned(self): """Parse an early version of the version struct.""" @@ -104,6 +114,10 @@ class FlipperFwVersion(gdb.Command): print(f"\tGit commit: {v.version.git_hash}") print(f"\tDirty: {v.version.build_is_dirty}") print(f"\tHW Target: {v.version.target}") + if v.version.firmware_origin: + print(f"\tOrigin: {v.version.firmware_origin}") + if v.version.git_origin: + print(f"\tGit origin: {v.version.git_origin}") FlipperFwVersion() diff --git a/scripts/fbt_tools/fbt_envhooks.py b/scripts/fbt_tools/fbt_envhooks.py new file mode 100644 index 000000000..0538e173c --- /dev/null +++ b/scripts/fbt_tools/fbt_envhooks.py @@ -0,0 +1,67 @@ +""" + +To introduce changes to firmware build environment that are specific to your fork: + + create a file "scripts/fbt/fbt_hooks.py" + +With it, you can define functions that will be called at specific points of +firmware build configuration, with environment as an argument. + +For example, you can define a function `PreConfigureFwEnvionment(env)` that +defines that will be a part of SDK build, so applications can +use them for conditional compilation. + +Here is a list of all available hooks: + + PreConfigureFwEnvionment(env): + This function is called on firmware environment (incl. updater) + before any major configuration is done. + + PostConfigureFwEnvionment(env): + This function is called on firmware environment (incl. updater) + after all configuration is done. + + PreConfigureUfbtEnvionment(env): + This function is called on ufbt environment at the beginning of + its configuration, before dist environment is created. + + PostConfigureUfbtEnvionment(env): + This function is called on ufbt dist_env environment after all + configuration and target creation is done. +""" + + +class DefaultFbtHooks: + pass + + +try: + from fbt import fbt_hooks +except ImportError: + fbt_hooks = DefaultFbtHooks() + + +def generate(env): + stub_hook = lambda env: None + control_hooks = [ + "PreConfigureFwEnvionment", + "PostConfigureFwEnvionment", + "PreConfigureUfbtEnvionment", + "PostConfigureUfbtEnvionment", + ] + + if ( + isinstance(fbt_hooks, DefaultFbtHooks) + and env.subst("${FIRMWARE_ORIGIN}") != "Official" + ): + # If fbt_hooks.py is not present, but we are not building official firmware, + # create "scripts/fbt/fbt_hooks.py" to implement changes to firmware build environment. + pass + + for hook_name in control_hooks: + hook_fn = getattr(fbt_hooks, hook_name, stub_hook) + env.AddMethod(hook_fn, hook_name) + + +def exists(): + return True diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index 8469e181a..aead13b29 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -19,7 +19,9 @@ def generate(env): BUILDERS={ "VersionBuilder": Builder( action=Action( - '${PYTHON3} "${VERSION_SCRIPT}" generate -t ${TARGET_HW} -o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', + '${PYTHON3} "${VERSION_SCRIPT}" generate ' + "-t ${TARGET_HW} -fw-origin ${FIRMWARE_ORIGIN} " + '-o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', "${VERSIONCOMSTR}", ), emitter=version_emitter, diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 4dd1fb5b9..d72de380c 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -98,6 +98,7 @@ env = core_env.Clone( "fbt_apps", "fbt_extapps", "fbt_assets", + "fbt_envhooks", ("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}), ], FBT_FAP_DEBUG_ELF_ROOT=ufbt_build_dir, @@ -117,6 +118,8 @@ env = core_env.Clone( wrap_tempfile(env, "LINKCOM") wrap_tempfile(env, "ARCOM") +env.PreConfigureUfbtEnvionment() + # print(env.Dump()) # Dist env @@ -474,3 +477,5 @@ dist_env.PhonyTarget( "env", "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", ) + +dist_env.PostConfigureUfbtEnvionment() diff --git a/scripts/version.py b/scripts/version.py index 4b581c2fa..6f58da152 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -50,8 +50,23 @@ class GitVersion: "GIT_BRANCH": branch, "VERSION": version, "BUILD_DIRTY": dirty and 1 or 0, + "GIT_ORIGIN": ",".join(self._get_git_origins()), } + def _get_git_origins(self): + try: + remotes = self._exec_git("remote -v") + except subprocess.CalledProcessError: + return set() + origins = set() + for line in remotes.split("\n"): + if not line: + continue + _, destination = line.split("\t") + url, _ = destination.split(" ") + origins.add(url) + return origins + def _exec_git(self, args): cmd = ["git"] cmd.extend(args.split(" ")) @@ -79,6 +94,13 @@ class Main(App): help="hardware target", required=True, ) + self.parser_generate.add_argument( + "-fw-origin", + dest="firmware_origin", + type=str, + help="firmware origin", + required=True, + ) self.parser_generate.add_argument("--dir", dest="sourcedir", required=True) self.parser_generate.set_defaults(func=self.generate) @@ -94,6 +116,7 @@ class Main(App): { "BUILD_DATE": build_date.strftime("%d-%m-%Y"), "TARGET": self.args.target, + "FIRMWARE_ORIGIN": self.args.firmware_origin, } ) diff --git a/site_scons/commandline.scons b/site_scons/commandline.scons index 54bcbc568..f6deeb420 100644 --- a/site_scons/commandline.scons +++ b/site_scons/commandline.scons @@ -241,6 +241,13 @@ vars.AddVariables( help="Don't open browser after generating error repots", default=False, ), + ( + "FIRMWARE_ORIGIN", + "Firmware origin. 'Official' if follows upstream's API structure, otherwise fork name. " + " This will also create a C define FW_ORIGIN_ so that " + " app can check what version it is being built for.", + "Official", + ), ) Return("vars")