diff --git a/.gitignore b/.gitignore index 025246faa..f816372fa 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,10 @@ Brewfile.lock.json # Visual Studio .vs/ +# Kate +.kateproject +.kateconfig + # legendary cmake's build CMakeLists.txt @@ -68,9 +72,8 @@ PVS-Studio.log # Automate files, etc automate.py deployments/ -fbt_options.py commitnotes.md -lib/STM32CubeWB +fbt_options.py # Asset packs assets/dolphin/custom/* diff --git a/applications/ReadMe.md b/applications/ReadMe.md index efc9afd86..ddbe5d65b 100644 --- a/applications/ReadMe.md +++ b/applications/ReadMe.md @@ -86,4 +86,4 @@ Small applications providing configuration for basic firmware and its services. Utility apps not visible in other menus. - `storage_move_to_sd` - Data migration tool for internal storage -- `updater` - updater service & application +- `updater` - Update service & application diff --git a/applications/debug/accessor/accessor_app.cpp b/applications/debug/accessor/accessor_app.cpp index 9d3708ebe..337437d0e 100644 --- a/applications/debug/accessor/accessor_app.cpp +++ b/applications/debug/accessor/accessor_app.cpp @@ -34,7 +34,7 @@ void AccessorApp::run(void) { AccessorApp::AccessorApp() : text_store{0} { notification = static_cast(furi_record_open(RECORD_NOTIFICATION)); - onewire_host = onewire_host_alloc(); + onewire_host = onewire_host_alloc(&ibutton_gpio); furi_hal_power_enable_otg(); } diff --git a/applications/debug/locale_test/locale_test.c b/applications/debug/locale_test/locale_test.c index 46248cf3c..003df55dc 100644 --- a/applications/debug/locale_test/locale_test.c +++ b/applications/debug/locale_test/locale_test.c @@ -99,4 +99,4 @@ int32_t locale_test_app(void* p) { view_dispatcher_run(app->view_dispatcher); locale_test_free(app); return 0; -} \ No newline at end of file +} diff --git a/applications/debug/unit_tests/power/power_test.c b/applications/debug/unit_tests/power/power_test.c index ce2c7aad7..a9b66b221 100644 --- a/applications/debug/unit_tests/power/power_test.c +++ b/applications/debug/unit_tests/power/power_test.c @@ -3,56 +3,63 @@ #include "../minunit.h" static void power_test_deinit(void) { - // Try to reset to default charging voltage - furi_hal_power_set_battery_charging_voltage(4.208f); + // Try to reset to default charge voltage limit + furi_hal_power_set_battery_charge_voltage_limit(4.208f); } -MU_TEST(test_power_charge_voltage_exact) { - // Power of 16mV charge voltages get applied exactly +MU_TEST(test_power_charge_voltage_limit_exact) { + // Power of 16mV charge voltage limits get applied exactly // (bq25896 charge controller works in 16mV increments) // // This test may need adapted if other charge controllers are used in the future. for(uint16_t charge_mv = 3840; charge_mv <= 4208; charge_mv += 16) { float charge_volt = (float)charge_mv / 1000.0f; - furi_hal_power_set_battery_charging_voltage(charge_volt); - mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(charge_volt); + mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charge_voltage_limit()); } } -MU_TEST(test_power_charge_voltage_floating_imprecision) { +MU_TEST(test_power_charge_voltage_limit_floating_imprecision) { // 4.016f should act as 4.016 V, even with floating point imprecision - furi_hal_power_set_battery_charging_voltage(4.016f); - mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(4.016f); + mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charge_voltage_limit()); } -MU_TEST(test_power_charge_voltage_inexact) { - // Charge voltages that are not power of 16mV get truncated down - furi_hal_power_set_battery_charging_voltage(3.841f); - mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage()); +MU_TEST(test_power_charge_voltage_limit_inexact) { + // Charge voltage limits that are not power of 16mV get truncated down + furi_hal_power_set_battery_charge_voltage_limit(3.841f); + mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit()); - furi_hal_power_set_battery_charging_voltage(3.900f); - mu_assert_double_eq(3.888, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(3.900f); + mu_assert_double_eq(3.888, furi_hal_power_get_battery_charge_voltage_limit()); - furi_hal_power_set_battery_charging_voltage(4.200f); - mu_assert_double_eq(4.192, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(4.200f); + mu_assert_double_eq(4.192, furi_hal_power_get_battery_charge_voltage_limit()); } -MU_TEST(test_power_charge_voltage_invalid_clamped) { - // Out-of-range charge voltages get clamped to 3.840 V and 4.208 V - furi_hal_power_set_battery_charging_voltage(3.808f); - mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage()); +MU_TEST(test_power_charge_voltage_limit_invalid_clamped) { + // Out-of-range charge voltage limits get clamped to 3.840 V and 4.208 V + furi_hal_power_set_battery_charge_voltage_limit(3.808f); + mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit()); + furi_hal_power_set_battery_charge_voltage_limit(1.0f); + mu_assert_double_eq(3.840, furi_hal_power_get_battery_charge_voltage_limit()); // NOTE: Intentionally picking a small increment above 4.208 V to reduce the risk of an // unhappy battery if this fails. - furi_hal_power_set_battery_charging_voltage(4.240f); - mu_assert_double_eq(4.208, furi_hal_power_get_battery_charging_voltage()); + furi_hal_power_set_battery_charge_voltage_limit(4.240f); + mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit()); + // Likewise, picking a number that the uint8_t wraparound in the driver would result in a + // VREG value under 23 if this test fails. + // E.g. (uint8_t)((8105-3840)/16) -> 10 + furi_hal_power_set_battery_charge_voltage_limit(8.105f); + mu_assert_double_eq(4.208, furi_hal_power_get_battery_charge_voltage_limit()); } MU_TEST_SUITE(test_power_suite) { - MU_RUN_TEST(test_power_charge_voltage_exact); - MU_RUN_TEST(test_power_charge_voltage_floating_imprecision); - MU_RUN_TEST(test_power_charge_voltage_inexact); - MU_RUN_TEST(test_power_charge_voltage_invalid_clamped); + MU_RUN_TEST(test_power_charge_voltage_limit_exact); + MU_RUN_TEST(test_power_charge_voltage_limit_floating_imprecision); + MU_RUN_TEST(test_power_charge_voltage_limit_inexact); + MU_RUN_TEST(test_power_charge_voltage_limit_invalid_clamped); power_test_deinit(); } diff --git a/applications/debug/unit_tests/rpc/rpc_test.c b/applications/debug/unit_tests/rpc/rpc_test.c index 5b52df2fa..76acf6be9 100644 --- a/applications/debug/unit_tests/rpc/rpc_test.c +++ b/applications/debug/unit_tests/rpc/rpc_test.c @@ -89,7 +89,7 @@ static void test_rpc_setup(void) { } furi_check(rpc_session[0].session); - rpc_session[0].output_stream = furi_stream_buffer_alloc(1000, 1); + rpc_session[0].output_stream = furi_stream_buffer_alloc(4096, 1); rpc_session_set_send_bytes_callback(rpc_session[0].session, output_bytes_callback); rpc_session[0].close_session_semaphore = xSemaphoreCreateBinary(); rpc_session[0].terminate_semaphore = xSemaphoreCreateBinary(); diff --git a/applications/debug/unit_tests/subghz/subghz_test.c b/applications/debug/unit_tests/subghz/subghz_test.c index fcd3dbded..c7e9c96f1 100644 --- a/applications/debug/unit_tests/subghz/subghz_test.c +++ b/applications/debug/unit_tests/subghz/subghz_test.c @@ -12,8 +12,9 @@ #define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes") #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") +#define ALUTECH_AT_4N_DIR_NAME EXT_PATH("subghz/assets/alutech_at_4n") #define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") -#define TEST_RANDOM_COUNT_PARSE 273 +#define TEST_RANDOM_COUNT_PARSE 329 #define TEST_TIMEOUT 10000 static SubGhzEnvironment* environment_handler; @@ -43,6 +44,8 @@ static void subghz_test_init(void) { environment_handler, CAME_ATOMO_DIR_NAME); subghz_environment_set_nice_flor_s_rainbow_table_file_name( environment_handler, NICE_FLOR_S_DIR_NAME); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + environment_handler, ALUTECH_AT_4N_DIR_NAME); subghz_environment_set_protocol_registry( environment_handler, (void*)&subghz_protocol_registry); @@ -489,6 +492,14 @@ MU_TEST(subghz_decoder_linear_test) { "Test decoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n"); } +MU_TEST(subghz_decoder_linear_delta3_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/linear_delta3_raw.sub"), + SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME), + "Test decoder " SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME " error\r\n"); +} + MU_TEST(subghz_decoder_megacode_test) { mu_assert( subghz_decoder_test( @@ -590,12 +601,6 @@ MU_TEST(subghz_decoder_ansonic_test) { "Test decoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n"); } -MU_TEST(subghz_decoder_pocsag_test) { - mu_assert( - subghz_decoder_test(EXT_PATH("unit_tests/subghz/pocsag.sub"), SUBGHZ_PROTOCOL_POCSAG_NAME), - "Test decoder " SUBGHZ_PROTOCOL_POCSAG_NAME " error\r\n"); -} - MU_TEST(subghz_decoder_smc5326_test) { mu_assert( subghz_decoder_test( @@ -610,6 +615,36 @@ MU_TEST(subghz_decoder_holtek_ht12x_test) { "Test decoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n"); } +MU_TEST(subghz_decoder_dooya_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/dooya_raw.sub"), SUBGHZ_PROTOCOL_DOOYA_NAME), + "Test decoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n"); +} + +MU_TEST(subghz_decoder_alutech_at_4n_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/alutech_at_4n_raw.sub"), + SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME), + "Test decoder " SUBGHZ_PROTOCOL_ALUTECH_AT_4N_NAME " error\r\n"); +} + +MU_TEST(subghz_decoder_nice_one_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/nice_one_raw.sub"), SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME), + "Test decoder " SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME " error\r\n"); +} + +MU_TEST(subghz_decoder_kinggates_stylo4k_test) { + mu_assert( + subghz_decoder_test( + EXT_PATH("unit_tests/subghz/kinggates_stylo4k_raw.sub"), + SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME), + "Test decoder " SUBGHZ_PROTOCOL_KINGGATES_STYLO_4K_NAME " error\r\n"); +} + //test encoders MU_TEST(subghz_encoder_princeton_test) { mu_assert( @@ -653,6 +688,12 @@ MU_TEST(subghz_encoder_linear_test) { "Test encoder " SUBGHZ_PROTOCOL_LINEAR_NAME " error\r\n"); } +MU_TEST(subghz_encoder_linear_delta3_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/linear_delta3.sub")), + "Test encoder " SUBGHZ_PROTOCOL_LINEAR_DELTA3_NAME " error\r\n"); +} + MU_TEST(subghz_encoder_megacode_test) { mu_assert( subghz_encoder_test(EXT_PATH("unit_tests/subghz/megacode.sub")), @@ -749,6 +790,12 @@ MU_TEST(subghz_encoder_holtek_ht12x_test) { "Test encoder " SUBGHZ_PROTOCOL_HOLTEK_HT12X_NAME " error\r\n"); } +MU_TEST(subghz_encoder_dooya_test) { + mu_assert( + subghz_encoder_test(EXT_PATH("unit_tests/subghz/dooya.sub")), + "Test encoder " SUBGHZ_PROTOCOL_DOOYA_NAME " error\r\n"); +} + MU_TEST(subghz_random_test) { mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n"); } @@ -778,6 +825,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_somfy_telis_test); MU_RUN_TEST(subghz_decoder_star_line_test); MU_RUN_TEST(subghz_decoder_linear_test); + MU_RUN_TEST(subghz_decoder_linear_delta3_test); MU_RUN_TEST(subghz_decoder_megacode_test); MU_RUN_TEST(subghz_decoder_secplus_v1_test); MU_RUN_TEST(subghz_decoder_secplus_v2_test); @@ -792,9 +840,12 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_decoder_intertechno_v3_test); MU_RUN_TEST(subghz_decoder_clemsa_test); MU_RUN_TEST(subghz_decoder_ansonic_test); - MU_RUN_TEST(subghz_decoder_pocsag_test); MU_RUN_TEST(subghz_decoder_smc5326_test); MU_RUN_TEST(subghz_decoder_holtek_ht12x_test); + MU_RUN_TEST(subghz_decoder_dooya_test); + MU_RUN_TEST(subghz_decoder_alutech_at_4n_test); + MU_RUN_TEST(subghz_decoder_nice_one_test); + MU_RUN_TEST(subghz_decoder_kinggates_stylo4k_test); MU_RUN_TEST(subghz_encoder_princeton_test); MU_RUN_TEST(subghz_encoder_came_test); @@ -803,6 +854,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_nice_flo_test); MU_RUN_TEST(subghz_encoder_keelog_test); MU_RUN_TEST(subghz_encoder_linear_test); + MU_RUN_TEST(subghz_encoder_linear_delta3_test); MU_RUN_TEST(subghz_encoder_megacode_test); MU_RUN_TEST(subghz_encoder_holtek_test); MU_RUN_TEST(subghz_encoder_secplus_v1_test); @@ -819,6 +871,7 @@ MU_TEST_SUITE(subghz) { MU_RUN_TEST(subghz_encoder_ansonic_test); MU_RUN_TEST(subghz_encoder_smc5326_test); MU_RUN_TEST(subghz_encoder_holtek_ht12x_test); + MU_RUN_TEST(subghz_encoder_dooya_test); MU_RUN_TEST(subghz_random_test); subghz_test_deinit(); diff --git a/applications/debug/unit_tests/test_index.c b/applications/debug/unit_tests/test_index.c index 2bb9c423f..ac71ca397 100644 --- a/applications/debug/unit_tests/test_index.c +++ b/applications/debug/unit_tests/test_index.c @@ -70,7 +70,7 @@ void minunit_print_progress() { } void minunit_print_fail(const char* str) { - printf(FURI_LOG_CLR_E "%s\r\n" FURI_LOG_CLR_RESET, str); + printf(_FURI_LOG_CLR_E "%s\r\n" _FURI_LOG_CLR_RESET, str); } void unit_tests_cli(Cli* cli, FuriString* args, void* context) { diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index 78b010a78..c72220c6a 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -8,6 +8,7 @@ #include #include #include +#include static void archive_folder_open_cb(void* context, uint32_t item_cnt, int32_t file_idx, bool is_root) { @@ -464,14 +465,17 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { browser->last_tab_switch_dir = key; - for(int i = 0; i < 2; i++) { + if(key == InputKeyLeft) { + tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal; + } else { + tab = (tab + 1) % ArchiveTabTotal; + } + if(tab == ArchiveTabInternal && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { if(key == InputKeyLeft) { tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal; } else { tab = (tab + 1) % ArchiveTabTotal; } - if(tab == ArchiveTabInternal && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) continue; - break; } browser->is_root = true; diff --git a/applications/main/gpio/scenes/gpio_scene_start.c b/applications/main/gpio/scenes/gpio_scene_start.c index 1c1a665c7..2d8f7adbc 100644 --- a/applications/main/gpio/scenes/gpio_scene_start.c +++ b/applications/main/gpio/scenes/gpio_scene_start.c @@ -107,6 +107,7 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) { } else if(event.event == GpioStartEventUsbUart) { scene_manager_set_scene_state(app->scene_manager, GpioSceneStart, GpioItemUsbUart); if(!furi_hal_usb_is_locked()) { + DOLPHIN_DEED(DolphinDeedGpioUartBridge); scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart); } else { scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCloseRpc); diff --git a/applications/main/ibutton/ibutton_cli.c b/applications/main/ibutton/ibutton_cli.c index fab1ccf05..9ddb079dc 100644 --- a/applications/main/ibutton/ibutton_cli.c +++ b/applications/main/ibutton/ibutton_cli.c @@ -271,7 +271,7 @@ void onewire_cli_print_usage() { static void onewire_cli_search(Cli* cli) { UNUSED(cli); - OneWireHost* onewire = onewire_host_alloc(); + OneWireHost* onewire = onewire_host_alloc(&ibutton_gpio); uint8_t address[8]; bool done = false; diff --git a/applications/main/ibutton/scenes/ibutton_scene_start.c b/applications/main/ibutton/scenes/ibutton_scene_start.c index 28807faa8..b8f6b07d6 100644 --- a/applications/main/ibutton/scenes/ibutton_scene_start.c +++ b/applications/main/ibutton/scenes/ibutton_scene_start.c @@ -39,7 +39,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) { consumed = true; if(event.event == SubmenuIndexRead) { scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead); - //DOLPHIN_DEED(DolphinDeedIbuttonRead); + DOLPHIN_DEED(DolphinDeedIbuttonRead); } else if(event.event == SubmenuIndexSaved) { furi_string_set(ibutton->file_path, IBUTTON_APP_FOLDER); scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSelectKey); diff --git a/applications/main/infrared/infrared.c b/applications/main/infrared/infrared.c index 9d78a09b6..14729e0d8 100644 --- a/applications/main/infrared/infrared.c +++ b/applications/main/infrared/infrared.c @@ -148,6 +148,12 @@ static Infrared* infrared_alloc() { view_dispatcher_add_view( view_dispatcher, InfraredViewTextInput, text_input_get_view(infrared->text_input)); + infrared->variable_item_list = variable_item_list_alloc(); + view_dispatcher_add_view( + infrared->view_dispatcher, + InfraredViewVariableItemList, + variable_item_list_get_view(infrared->variable_item_list)); + infrared->dialog_ex = dialog_ex_alloc(); view_dispatcher_add_view( view_dispatcher, InfraredViewDialogEx, dialog_ex_get_view(infrared->dialog_ex)); @@ -195,6 +201,9 @@ static void infrared_free(Infrared* infrared) { view_dispatcher_remove_view(view_dispatcher, InfraredViewTextInput); text_input_free(infrared->text_input); + view_dispatcher_remove_view(infrared->view_dispatcher, InfraredViewVariableItemList); + variable_item_list_free(infrared->variable_item_list); + view_dispatcher_remove_view(view_dispatcher, InfraredViewDialogEx); dialog_ex_free(infrared->dialog_ex); diff --git a/applications/main/infrared/infrared_cli.c b/applications/main/infrared/infrared_cli.c index 5f5e2d4bb..3fa99cb02 100644 --- a/applications/main/infrared/infrared_cli.c +++ b/applications/main/infrared/infrared_cli.c @@ -86,7 +86,7 @@ static void infrared_cli_print_usage(void) { printf("\tir universal \r\n"); printf("\tir universal list \r\n"); // TODO: Do not hardcode universal remote names - printf("\tAvailable universal remotes: tv audio ac\r\n"); + printf("\tAvailable universal remotes: tv audio ac projector\r\n"); } static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) { diff --git a/applications/main/infrared/infrared_i.h b/applications/main/infrared/infrared_i.h index 6972d53b4..72800d994 100644 --- a/applications/main/infrared/infrared_i.h +++ b/applications/main/infrared/infrared_i.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -32,8 +34,6 @@ #include "rpc/rpc_app.h" -#include - #define INFRARED_FILE_NAME_SIZE 100 #define INFRARED_TEXT_STORE_NUM 2 #define INFRARED_TEXT_STORE_SIZE 128 @@ -87,6 +87,7 @@ struct Infrared { Submenu* submenu; TextInput* text_input; + VariableItemList* variable_item_list; DialogEx* dialog_ex; ButtonMenu* button_menu; Popup* popup; @@ -108,6 +109,7 @@ struct Infrared { typedef enum { InfraredViewSubmenu, InfraredViewTextInput, + InfraredViewVariableItemList, InfraredViewDialogEx, InfraredViewButtonMenu, InfraredViewPopup, diff --git a/applications/main/infrared/scenes/infrared_scene_config.h b/applications/main/infrared/scenes/infrared_scene_config.h index 551485295..b15974941 100644 --- a/applications/main/infrared/scenes/infrared_scene_config.h +++ b/applications/main/infrared/scenes/infrared_scene_config.h @@ -21,4 +21,5 @@ ADD_SCENE(infrared, universal_audio, UniversalAudio) ADD_SCENE(infrared, universal_projector, UniversalProjector) ADD_SCENE(infrared, debug, Debug) ADD_SCENE(infrared, error_databases, ErrorDatabases) +ADD_SCENE(infrared, debug_settings, DebugSettings) ADD_SCENE(infrared, rpc, Rpc) diff --git a/applications/main/infrared/scenes/infrared_scene_debug_settings.c b/applications/main/infrared/scenes/infrared_scene_debug_settings.c new file mode 100644 index 000000000..0bc830788 --- /dev/null +++ b/applications/main/infrared/scenes/infrared_scene_debug_settings.c @@ -0,0 +1,59 @@ +#include "../infrared_i.h" +#include + +uint8_t value_index_ir; + +#define DEB_PINS_COUNT (sizeof(infrared_debug_cfg_variables_text) / sizeof(char* const)) +const char* const infrared_debug_cfg_variables_text[] = { + "Internal", + "2 (A7)", +}; + +static void infrared_scene_debug_settings_changed(VariableItem* item) { + Infrared* infrared = variable_item_get_context(item); + value_index_ir = variable_item_get_current_value_index(item); + UNUSED(infrared); + + variable_item_set_current_value_text(item, infrared_debug_cfg_variables_text[value_index_ir]); + + furi_hal_infrared_set_debug_out(value_index_ir); +} +static void infrared_debug_settings_start_var_list_enter_callback(void* context, uint32_t index) { + Infrared* infrared = context; + view_dispatcher_send_custom_event(infrared->view_dispatcher, index); +} + +void infrared_scene_debug_settings_on_enter(void* context) { + Infrared* infrared = context; + + VariableItemList* variable_item_list = infrared->variable_item_list; + + value_index_ir = furi_hal_infrared_get_debug_out_status(); + VariableItem* item = variable_item_list_add( + variable_item_list, + "Send signal to", + DEB_PINS_COUNT, + infrared_scene_debug_settings_changed, + infrared); + + variable_item_list_set_enter_callback( + variable_item_list, infrared_debug_settings_start_var_list_enter_callback, infrared); + + variable_item_set_current_value_index(item, value_index_ir); + variable_item_set_current_value_text(item, infrared_debug_cfg_variables_text[value_index_ir]); + + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewVariableItemList); +} + +bool infrared_scene_debug_settings_on_event(void* context, SceneManagerEvent event) { + Infrared* infrared = context; + UNUSED(infrared); + UNUSED(event); + + return false; +} + +void infrared_scene_debug_settings_on_exit(void* context) { + Infrared* infrared = context; + variable_item_list_reset(infrared->variable_item_list); +} diff --git a/applications/main/infrared/scenes/infrared_scene_start.c b/applications/main/infrared/scenes/infrared_scene_start.c index 4d13d6e0e..0403e40f8 100644 --- a/applications/main/infrared/scenes/infrared_scene_start.c +++ b/applications/main/infrared/scenes/infrared_scene_start.c @@ -5,7 +5,8 @@ enum SubmenuIndex { SubmenuIndexLearnNewRemote, SubmenuIndexLearnNewRemoteRaw, SubmenuIndexSavedRemotes, - SubmenuIndexDebug + SubmenuIndexDebug, + SubmenuIndexDebugSettings }; static void infrared_scene_start_submenu_callback(void* context, uint32_t index) { @@ -45,7 +46,17 @@ void infrared_scene_start_on_enter(void* context) { infrared_scene_start_submenu_callback, infrared); submenu_add_item( - submenu, "Debug", SubmenuIndexDebug, infrared_scene_start_submenu_callback, infrared); + submenu, + "Debug RX", + SubmenuIndexDebug, + infrared_scene_start_submenu_callback, + infrared); + submenu_add_item( + submenu, + "Debug Settings", + SubmenuIndexDebugSettings, + infrared_scene_start_submenu_callback, + infrared); } const uint32_t submenu_index = @@ -85,6 +96,9 @@ bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) { } else if(submenu_index == SubmenuIndexDebug) { scene_manager_next_scene(scene_manager, InfraredSceneDebug); consumed = true; + } else if(submenu_index == SubmenuIndexDebugSettings) { + scene_manager_next_scene(scene_manager, InfraredSceneDebugSettings); + consumed = true; } } diff --git a/applications/main/infrared/scenes/infrared_scene_universal.c b/applications/main/infrared/scenes/infrared_scene_universal.c index 1d6021171..b6c1ac983 100644 --- a/applications/main/infrared/scenes/infrared_scene_universal.c +++ b/applications/main/infrared/scenes/infrared_scene_universal.c @@ -80,6 +80,7 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC); consumed = true; } + scene_manager_set_scene_state(scene_manager, InfraredSceneUniversal, event.event); } return consumed; diff --git a/applications/main/lfrfid/lfrfid_i.h b/applications/main/lfrfid/lfrfid_i.h index 201caa4f6..72b061930 100644 --- a/applications/main/lfrfid/lfrfid_i.h +++ b/applications/main/lfrfid/lfrfid_i.h @@ -5,8 +5,10 @@ #include #include +#include #include #include +#include #include #include @@ -32,8 +34,6 @@ #include #include -#include -// #include #define LFRFID_KEY_NAME_SIZE 22 #define LFRFID_TEXT_STORE_SIZE 40 diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c b/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c index b1130d191..efa319c1e 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_extra_actions.c @@ -20,7 +20,7 @@ void lfrfid_scene_extra_actions_on_enter(void* context) { submenu_add_item( submenu, - "Read ASK (Animal, FDX)", + "Read ASK (FDX,Regular)", SubmenuIndexASK, lfrfid_scene_extra_actions_submenu_callback, app); diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_start.c b/applications/main/lfrfid/scenes/lfrfid_scene_start.c index 8e1c92dbb..2d83ba53b 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_start.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_start.c @@ -47,21 +47,28 @@ bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexRead); scene_manager_next_scene(app->scene_manager, LfRfidSceneRead); DOLPHIN_DEED(DolphinDeedRfidRead); consumed = true; } else if(event.event == SubmenuIndexSaved) { + // Like in the other apps, explicitly save the scene state + // in each branch in case the user cancels loading a file. + scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, SubmenuIndexSaved); furi_string_set(app->file_path, LFRFID_APP_FOLDER); scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey); consumed = true; } else if(event.event == SubmenuIndexAddManually) { + scene_manager_set_scene_state( + app->scene_manager, LfRfidSceneStart, SubmenuIndexAddManually); scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType); consumed = true; } else if(event.event == SubmenuIndexExtraActions) { + scene_manager_set_scene_state( + app->scene_manager, LfRfidSceneStart, SubmenuIndexExtraActions); scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions); consumed = true; } - scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, event.event); } return consumed; diff --git a/applications/main/subghz/helpers/subghz_custom_event.h b/applications/main/subghz/helpers/subghz_custom_event.h index 350e68ee6..4475045ee 100644 --- a/applications/main/subghz/helpers/subghz_custom_event.h +++ b/applications/main/subghz/helpers/subghz_custom_event.h @@ -8,11 +8,14 @@ typedef enum { //SubmenuIndex SubmenuIndexFaacSLH_433, SubmenuIndexFaacSLH_868, - SubmenuIndexBFT, + SubmenuIndexBFTClone, + SubmenuIndexBFTMitto, + SubmenuIndexSomfyTelis, SubmenuIndexPricenton, SubmenuIndexNiceFlo12bit, SubmenuIndexNiceFlo24bit, SubmenuIndexNiceFlorS_433_92, + SubmenuIndexNiceOne_433_92, SubmenuIndexNiceSmilo_433_92, SubmenuIndexCAME12bit, SubmenuIndexCAME24bit, @@ -64,6 +67,7 @@ typedef enum { SubGhzCustomEventViewReceiverBack, SubGhzCustomEventViewReceiverOffDisplay, SubGhzCustomEventViewReceiverUnlock, + SubGhzCustomEventViewReceiverDeleteItem, SubGhzCustomEventViewReadRAWBack, SubGhzCustomEventViewReadRAWIDLE, diff --git a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c index 4627c57be..df81eae29 100644 --- a/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c +++ b/applications/main/subghz/scenes/subghz_scene_ext_module_settings.c @@ -1,8 +1,9 @@ #include "../subghz_i.h" #include "../helpers/subghz_custom_event.h" -uint8_t value_index; -uint8_t value_index2; +uint8_t value_index_exm; +uint8_t value_index_dpin; +uint8_t value_index_cnt; #define EXT_MODULES_COUNT (sizeof(radio_modules_variables_text) / sizeof(char* const)) const char* const radio_modules_variables_text[] = { @@ -16,12 +17,22 @@ const char* const debug_pin_text[DEBUG_P_COUNT] = { "17(1W)", }; +#define DEBUG_COUNTER_COUNT 6 +const char* const debug_counter_text[DEBUG_COUNTER_COUNT] = { + "+1", + "+2", + "+3", + "+4", + "+5", + "+10", +}; + static void subghz_scene_ext_module_changed(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); - value_index = variable_item_get_current_value_index(item); + value_index_exm = variable_item_get_current_value_index(item); UNUSED(subghz); - variable_item_set_current_value_text(item, radio_modules_variables_text[value_index]); + variable_item_set_current_value_text(item, radio_modules_variables_text[value_index_exm]); } static void subghz_ext_module_start_var_list_enter_callback(void* context, uint32_t index) { SubGhz* subghz = context; @@ -37,20 +48,49 @@ static void subghz_scene_receiver_config_set_debug_pin(VariableItem* item) { subghz->txrx->debug_pin_state = index == 1; } +static void subghz_scene_receiver_config_set_debug_counter(VariableItem* item) { + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, debug_counter_text[index]); + + switch(index) { + case 0: + furi_hal_subghz_set_rolling_counter_mult(1); + break; + case 1: + furi_hal_subghz_set_rolling_counter_mult(2); + break; + case 2: + furi_hal_subghz_set_rolling_counter_mult(3); + break; + case 3: + furi_hal_subghz_set_rolling_counter_mult(4); + break; + case 4: + furi_hal_subghz_set_rolling_counter_mult(5); + break; + case 5: + furi_hal_subghz_set_rolling_counter_mult(10); + break; + default: + break; + } +} + void subghz_scene_ext_module_settings_on_enter(void* context) { SubGhz* subghz = context; VariableItemList* variable_item_list = subghz->variable_item_list; - value_index = furi_hal_subghz.radio_type; + value_index_exm = furi_hal_subghz.radio_type; VariableItem* item = variable_item_list_add( variable_item_list, "Module", EXT_MODULES_COUNT, subghz_scene_ext_module_changed, subghz); variable_item_list_set_enter_callback( variable_item_list, subghz_ext_module_start_var_list_enter_callback, subghz); - variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, radio_modules_variables_text[value_index]); + variable_item_set_current_value_index(item, value_index_exm); + variable_item_set_current_value_text(item, radio_modules_variables_text[value_index_exm]); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { item = variable_item_list_add( @@ -59,9 +99,40 @@ void subghz_scene_ext_module_settings_on_enter(void* context) { DEBUG_P_COUNT, subghz_scene_receiver_config_set_debug_pin, subghz); - value_index2 = subghz->txrx->debug_pin_state; - variable_item_set_current_value_index(item, value_index2); - variable_item_set_current_value_text(item, debug_pin_text[value_index2]); + value_index_dpin = subghz->txrx->debug_pin_state; + variable_item_set_current_value_index(item, value_index_dpin); + variable_item_set_current_value_text(item, debug_pin_text[value_index_dpin]); + + item = variable_item_list_add( + subghz->variable_item_list, + "Counter Mult:", + DEBUG_COUNTER_COUNT, + subghz_scene_receiver_config_set_debug_counter, + subghz); + switch(furi_hal_subghz_get_rolling_counter_mult()) { + case 1: + value_index_cnt = 0; + break; + case 2: + value_index_cnt = 1; + break; + case 3: + value_index_cnt = 2; + break; + case 4: + value_index_cnt = 3; + break; + case 5: + value_index_cnt = 4; + break; + case 10: + value_index_cnt = 5; + break; + default: + break; + } + variable_item_set_current_value_index(item, value_index_cnt); + variable_item_set_current_value_text(item, debug_counter_text[value_index_cnt]); } view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); @@ -73,12 +144,12 @@ bool subghz_scene_ext_module_settings_on_event(void* context, SceneManagerEvent UNUSED(event); // Set selected radio module - furi_hal_subghz_set_radio_type(value_index); + furi_hal_subghz_set_radio_type(value_index_exm); // Check if module is present, if no -> show error if(!furi_hal_subghz_check_radio()) { - value_index = 0; - furi_hal_subghz_set_radio_type(value_index); + value_index_exm = 0; + furi_hal_subghz_set_radio_type(value_index_exm); furi_string_set(subghz->error_str, "Please connect\nexternal radio"); scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index e1ea08497..c0112199c 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -204,6 +204,16 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo); consumed = true; break; + case SubGhzCustomEventViewReceiverDeleteItem: + subghz->txrx->idx_menu_chosen = + subghz_view_receiver_get_idx_menu(subghz->subghz_receiver); + + subghz_history_delete_item(subghz->txrx->history, subghz->txrx->idx_menu_chosen); + subghz_view_receiver_delete_element_callback(subghz->subghz_receiver); + + subghz_scene_receiver_update_statusbar(subghz); + consumed = true; + break; case SubGhzCustomEventViewReceiverConfig: subghz->state_notifications = SubGhzNotificationStateIDLE; subghz->txrx->idx_menu_chosen = diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index e5b037f2e..fd28421a8 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -2,6 +2,9 @@ #include "../helpers/subghz_custom_event.h" #include #include +#include +#include +#include void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); @@ -233,6 +236,10 @@ void subghz_scene_receiver_info_on_exit(void* context) { widget_reset(subghz->widget); keeloq_reset_mfname(); keeloq_reset_kl_type(); + keeloq_reset_original_btn(); + alutech_reset_original_btn(); + nice_flors_reset_original_btn(); + somfy_telis_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/subghz/scenes/subghz_scene_rpc.c b/applications/main/subghz/scenes/subghz_scene_rpc.c index 609b4a71d..b9585ec36 100644 --- a/applications/main/subghz/scenes/subghz_scene_rpc.c +++ b/applications/main/subghz/scenes/subghz_scene_rpc.c @@ -1,6 +1,10 @@ #include "../subghz_i.h" #include #include +#include +#include +#include + #include "xtreme/assets.h" typedef enum { @@ -110,6 +114,10 @@ void subghz_scene_rpc_on_exit(void* context) { keeloq_reset_mfname(); keeloq_reset_kl_type(); + keeloq_reset_original_btn(); + alutech_reset_original_btn(); + nice_flors_reset_original_btn(); + somfy_telis_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/subghz/scenes/subghz_scene_set_type.c b/applications/main/subghz/scenes/subghz_scene_set_type.c index 95cb1ec03..5c5d5db3b 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_type.c +++ b/applications/main/subghz/scenes/subghz_scene_set_type.c @@ -79,10 +79,22 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexFaacSLH_433, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "BFT [Manual] 433MHz", + SubmenuIndexBFTClone, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "BFT Mitto 433MHz", - SubmenuIndexBFT, + SubmenuIndexBFTMitto, + subghz_scene_set_type_submenu_callback, + subghz); + submenu_add_item( + subghz->submenu, + "Somfy Telis 433MHz", + SubmenuIndexSomfyTelis, subghz_scene_set_type_submenu_callback, subghz); submenu_add_item( @@ -115,6 +127,12 @@ void subghz_scene_set_type_on_enter(void* context) { SubmenuIndexNiceFlorS_433_92, subghz_scene_set_type_submenu_callback, subghz); + submenu_add_item( + subghz->submenu, + "Nice One 433MHz", + SubmenuIndexNiceOne_433_92, + subghz_scene_set_type_submenu_callback, + subghz); submenu_add_item( subghz->submenu, "CAME 12bit 433MHz", @@ -230,7 +248,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { case SubmenuIndexFaacSLH_433: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixFaac); break; - case SubmenuIndexBFT: + case SubmenuIndexBFTClone: scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSetFixBft); break; case SubmenuIndexPricenton: @@ -306,6 +324,66 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { generated_protocol = true; } break; + case SubmenuIndexBFTMitto: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); + subghz_preset_init(subghz, "AM650", 433920000, NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_keeloq_bft_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + key & 0x000FFFFF, + 0x2, + 0x0002, + key & 0x000FFFFF, + "BFT", + subghz->txrx->preset); + + uint8_t seed_data[sizeof(uint32_t)] = {0}; + for(size_t i = 0; i < sizeof(uint32_t); i++) { + seed_data[sizeof(uint32_t) - i - 1] = ((key & 0x000FFFFF) >> i * 8) & 0xFF; + } + + flipper_format_write_hex( + subghz->txrx->fff_data, "Seed", seed_data, sizeof(uint32_t)); + + flipper_format_write_string_cstr(subghz->txrx->fff_data, "Manufacture", "BFT"); + + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; + case SubmenuIndexSomfyTelis: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_SOMFY_TELIS_NAME); + subghz_preset_init( + subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_somfy_telis_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + key & 0x00FFFFFF, + 0x2, + 0x0003, + subghz->txrx->preset); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; case SubmenuIndexDoorHan_433_92: subghz->txrx->transmitter = subghz_transmitter_alloc_init( subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME); @@ -367,7 +445,33 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) { key & 0x0FFFFFFF, 0x1, 0x0003, - subghz->txrx->preset); + subghz->txrx->preset, + false); + generated_protocol = true; + } else { + generated_protocol = false; + } + subghz_transmitter_free(subghz->txrx->transmitter); + if(!generated_protocol) { + furi_string_set( + subghz->error_str, "Function requires\nan SD card with\nfresh databases."); + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError); + } + break; + case SubmenuIndexNiceOne_433_92: + subghz->txrx->transmitter = subghz_transmitter_alloc_init( + subghz->txrx->environment, SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME); + subghz_preset_init( + subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0); + if(subghz->txrx->transmitter) { + subghz_protocol_nice_flor_s_create_data( + subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter), + subghz->txrx->fff_data, + key & 0x0FFFFFFF, + 0x1, + 0x0003, + subghz->txrx->preset, + true); generated_protocol = true; } else { generated_protocol = false; diff --git a/applications/main/subghz/scenes/subghz_scene_transmitter.c b/applications/main/subghz/scenes/subghz_scene_transmitter.c index dff4f8384..00839170c 100644 --- a/applications/main/subghz/scenes/subghz_scene_transmitter.c +++ b/applications/main/subghz/scenes/subghz_scene_transmitter.c @@ -2,7 +2,10 @@ #include "../views/transmitter.h" #include #include +#include #include +#include +#include void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) { furi_assert(context); @@ -89,6 +92,27 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) { subghz_tx_stop(subghz); subghz_sleep(subghz); } + if(keeloq_get_custom_btn() != 0) { + keeloq_set_btn(0); + alutech_set_btn(0); + nice_flors_set_btn(0); + somfy_telis_set_btn(0); + uint8_t tmp_counter = furi_hal_subghz_get_rolling_counter_mult(); + furi_hal_subghz_set_rolling_counter_mult(0); + // Calling restore! + if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) { + subghz_rx_end(subghz); + } + if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) || + (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) { + if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) { + scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx); + } + } + subghz_tx_stop(subghz); + subghz_sleep(subghz); + furi_hal_subghz_set_rolling_counter_mult(tmp_counter); + } return true; } else if(event.event == SubGhzCustomEventViewTransmitterBack) { subghz->state_notifications = SubGhzNotificationStateIDLE; @@ -113,6 +137,10 @@ void subghz_scene_transmitter_on_exit(void* context) { subghz->state_notifications = SubGhzNotificationStateIDLE; keeloq_reset_mfname(); keeloq_reset_kl_type(); + keeloq_reset_original_btn(); + alutech_reset_original_btn(); + nice_flors_reset_original_btn(); + somfy_telis_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index 184146698..f6530238e 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -88,6 +88,28 @@ void subghz_history_reset(SubGhzHistory* instance) { instance->code_last_hash_data = 0; } +void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id) { + furi_assert(instance); + + SubGhzHistoryItemArray_it_t it; + //SubGhzHistoryItem* target_item = SubGhzHistoryItemArray_get(instance->history->data, item_id); + SubGhzHistoryItemArray_it_last(it, instance->history->data); + while(!SubGhzHistoryItemArray_end_p(it)) { + SubGhzHistoryItem* item = SubGhzHistoryItemArray_ref(it); + + if(it->index == (size_t)(item_id)) { + furi_string_free(item->item_str); + furi_string_free(item->preset->name); + free(item->preset); + flipper_format_free(item->flipper_string); + item->type = 0; + SubGhzHistoryItemArray_remove(instance->history->data, it); + } + SubGhzHistoryItemArray_previous(it); + } + instance->last_index_write--; +} + uint16_t subghz_history_get_item(SubGhzHistory* instance) { furi_assert(instance); return instance->last_index_write; diff --git a/applications/main/subghz/subghz_history.h b/applications/main/subghz/subghz_history.h index 4b01f5aef..1f2f8d246 100644 --- a/applications/main/subghz/subghz_history.h +++ b/applications/main/subghz/subghz_history.h @@ -27,6 +27,8 @@ void subghz_history_free(SubGhzHistory* instance); */ void subghz_history_reset(SubGhzHistory* instance); +void subghz_history_delete_item(SubGhzHistory* instance, uint16_t item_id); + /** Get frequency to history[idx] * * @param instance - SubGhzHistory instance diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index be683be28..2a432deb5 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -431,6 +431,34 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { true); } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { subghz_receiver->callback(SubGhzCustomEventViewReceiverConfig, subghz_receiver->context); + } else if(event->key == InputKeyRight && event->type == InputTypeLong) { + with_view_model( + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { + if(model->history_item != 0) { + SubGhzReceiverMenuItemArray_it_t it; + // SubGhzReceiverMenuItem* target_item = + // SubGhzReceiverMenuItemArray_get(model->history->data, model->idx); + SubGhzReceiverMenuItemArray_it_last(it, model->history->data); + while(!SubGhzReceiverMenuItemArray_end_p(it)) { + SubGhzReceiverMenuItem* item = SubGhzReceiverMenuItemArray_ref(it); + + if(it->index == (size_t)(model->idx)) { + furi_string_free(item->item_str); + item->type = 0; + SubGhzReceiverMenuItemArray_remove(model->history->data, it); + } + + SubGhzReceiverMenuItemArray_previous(it); + } + + // Callback + subghz_receiver->callback( + SubGhzCustomEventViewReceiverDeleteItem, subghz_receiver->context); + } + }, + true); } else if(event->key == InputKeyOk && event->type == InputTypeShort) { with_view_model( subghz_receiver->view, @@ -544,12 +572,34 @@ View* subghz_view_receiver_get_view(SubGhzViewReceiver* subghz_receiver) { uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver) { furi_assert(subghz_receiver); - uint32_t idx = 0; + uint16_t idx = 0; with_view_model( subghz_receiver->view, SubGhzViewReceiverModel * model, { idx = model->idx; }, false); return idx; } +void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver) { + furi_assert(subghz_receiver); + + with_view_model( + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { + if(model->history_item == 5) { + if(model->idx >= 2) { + model->idx = model->history_item - 1; + } + } + model->history_item--; + + if(model->idx != 0) { + model->idx--; + } + }, + true); + furi_delay_ms(200); +} + void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) { furi_assert(subghz_receiver); with_view_model( diff --git a/applications/main/subghz/views/receiver.h b/applications/main/subghz/views/receiver.h index 37eb473de..ad8c31eda 100644 --- a/applications/main/subghz/views/receiver.h +++ b/applications/main/subghz/views/receiver.h @@ -46,4 +46,6 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver); void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx); +void subghz_view_receiver_delete_element_callback(SubGhzViewReceiver* subghz_receiver); + void subghz_view_receiver_exit(void* context); diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 102639924..e6ed16d81 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -4,6 +4,11 @@ #include #include +#include +#include +#include +#include + struct SubGhzViewTransmitter { View* view; SubGhzViewTransmitterCallback callback; @@ -15,6 +20,8 @@ typedef struct { FuriString* preset_str; FuriString* key_str; uint8_t show_button; + FuriString* temp_button_id; + bool draw_temp_button; } SubGhzViewTransmitterModel; void subghz_view_transmitter_set_callback( @@ -89,6 +96,12 @@ void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* mo canvas_draw_str(canvas, 78, 7, furi_string_get_cstr(model->frequency_str)); canvas_draw_str(canvas, 113, 7, furi_string_get_cstr(model->preset_str)); + if(model->draw_temp_button) { + canvas_set_font(canvas, FontBatteryPercent); + canvas_draw_str(canvas, 117, 40, furi_string_get_cstr(model->temp_button_id)); + canvas_set_font(canvas, FontSecondary); + } + if(model->show_button) { canvas_draw_str(canvas, 58, 62, furi_hal_subghz_get_radio_type() ? "R: Ext" : "R: Int"); subghz_view_transmitter_button_right(canvas, "Send"); @@ -108,7 +121,9 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { furi_string_reset(model->frequency_str); furi_string_reset(model->preset_str); furi_string_reset(model->key_str); + furi_string_reset(model->temp_button_id); model->show_button = 0; + model->draw_temp_button = false; }, false); return false; @@ -125,6 +140,14 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { true); if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { + with_view_model( + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { + furi_string_reset(model->temp_button_id); + model->draw_temp_button = false; + }, + true); subghz_transmitter->callback( SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); return true; @@ -134,6 +157,141 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { return true; } + // Temp Buttons (UP) + if(can_be_sent && event->key == InputKeyUp && event->type == InputTypePress) { + keeloq_set_btn(1); + alutech_set_btn(1); + nice_flors_set_btn(1); + somfy_telis_set_btn(1); + with_view_model( + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { + furi_string_reset(model->temp_button_id); + if(keeloq_get_original_btn() != 0) { + furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn()); + model->draw_temp_button = true; + } else if(alutech_get_original_btn() != 0) { + furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn()); + model->draw_temp_button = true; + } else if(nice_flors_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", nice_flors_get_original_btn()); + model->draw_temp_button = true; + } else if(somfy_telis_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", somfy_telis_get_original_btn()); + model->draw_temp_button = true; + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyUp && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + // Down + if(can_be_sent && event->key == InputKeyDown && event->type == InputTypePress) { + keeloq_set_btn(2); + alutech_set_btn(2); + nice_flors_set_btn(2); + somfy_telis_set_btn(2); + with_view_model( + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { + furi_string_reset(model->temp_button_id); + if(keeloq_get_original_btn() != 0) { + furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn()); + model->draw_temp_button = true; + } else if(alutech_get_original_btn() != 0) { + furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn()); + model->draw_temp_button = true; + } else if(nice_flors_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", nice_flors_get_original_btn()); + model->draw_temp_button = true; + } else if(somfy_telis_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", somfy_telis_get_original_btn()); + model->draw_temp_button = true; + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyDown && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + // Left + if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypePress) { + keeloq_set_btn(3); + alutech_set_btn(3); + nice_flors_set_btn(3); + somfy_telis_set_btn(3); + with_view_model( + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { + furi_string_reset(model->temp_button_id); + if(keeloq_get_original_btn() != 0) { + furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn()); + model->draw_temp_button = true; + } else if(alutech_get_original_btn() != 0) { + furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn()); + model->draw_temp_button = true; + } else if(nice_flors_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", nice_flors_get_original_btn()); + model->draw_temp_button = true; + } else if(somfy_telis_get_original_btn() != 0) { + furi_string_printf( + model->temp_button_id, "%01X", somfy_telis_get_original_btn()); + model->draw_temp_button = true; + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyLeft && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + // Right + if(can_be_sent && event->key == InputKeyRight && event->type == InputTypePress) { + keeloq_set_btn(4); + alutech_set_btn(4); + with_view_model( + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { + furi_string_reset(model->temp_button_id); + if(keeloq_get_original_btn() != 0) { + furi_string_printf(model->temp_button_id, "%01X", keeloq_get_original_btn()); + model->draw_temp_button = true; + } else if(alutech_get_original_btn() != 0) { + furi_string_printf(model->temp_button_id, "%01X", alutech_get_original_btn()); + model->draw_temp_button = true; + } + }, + true); + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context); + return true; + } else if(can_be_sent && event->key == InputKeyRight && event->type == InputTypeRelease) { + subghz_transmitter->callback( + SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context); + return true; + } + return true; } @@ -166,6 +324,7 @@ SubGhzViewTransmitter* subghz_view_transmitter_alloc() { model->frequency_str = furi_string_alloc(); model->preset_str = furi_string_alloc(); model->key_str = furi_string_alloc(); + model->temp_button_id = furi_string_alloc(); }, true); return subghz_transmitter; @@ -181,6 +340,7 @@ void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter) { furi_string_free(model->frequency_str); furi_string_free(model->preset_str); furi_string_free(model->key_str); + furi_string_free(model->temp_button_id); }, true); view_free(subghz_transmitter->view); diff --git a/applications/main/unirfremix/unirfremix_app.c b/applications/main/unirfremix/unirfremix_app.c index a4e5249fa..7cf1c2a00 100644 --- a/applications/main/unirfremix/unirfremix_app.c +++ b/applications/main/unirfremix/unirfremix_app.c @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #define UNIRFMAP_FOLDER "/ext/subghz/unirf" #define UNIRFMAP_EXTENSION ".txt" @@ -481,6 +484,10 @@ void unirfremix_tx_stop(UniRFRemix* app) { keeloq_reset_mfname(); keeloq_reset_kl_type(); + keeloq_reset_original_btn(); + alutech_reset_original_btn(); + nice_flors_reset_original_btn(); + somfy_telis_reset_original_btn(); star_line_reset_mfname(); star_line_reset_kl_type(); } diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_misc.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc.c index 54ad0371e..22b5fb1b0 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_misc.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_misc.c @@ -39,7 +39,7 @@ void xtreme_app_scene_misc_on_enter(void* context) { variable_item_set_current_value_text(item, xtreme_settings->sort_dirs_first ? "ON" : "OFF"); item = variable_item_list_add( - var_item_list, "Dark Mode (Exp.)", 2, xtreme_app_scene_misc_dark_mode_changed, app); + var_item_list, "Exp. Dark Mode", 2, xtreme_app_scene_misc_dark_mode_changed, app); variable_item_set_current_value_index(item, xtreme_settings->dark_mode); variable_item_set_current_value_text(item, xtreme_settings->dark_mode ? "ON" : "OFF"); diff --git a/applications/main/xtreme_app/xtreme_app.c b/applications/main/xtreme_app/xtreme_app.c index 0309c4cae..6804dd0c3 100644 --- a/applications/main/xtreme_app/xtreme_app.c +++ b/applications/main/xtreme_app/xtreme_app.c @@ -177,7 +177,7 @@ XtremeApp* xtreme_app_alloc() { furi_record_close(RECORD_STORAGE); app->version_tag = furi_string_alloc_printf( - "%s %s", version_get_gitbranchnum(NULL), version_get_builddate(NULL)); + "%s %s", version_get_version(NULL), version_get_builddate(NULL)); return app; } diff --git a/applications/plugins/dice/dice.c b/applications/plugins/dice/dice.c index dc748b68f..0bf90a1c8 100644 --- a/applications/plugins/dice/dice.c +++ b/applications/plugins/dice/dice.c @@ -290,10 +290,10 @@ static void dice_render_callback(Canvas* const canvas, void* ctx) { state->diceQty, state->diceType[0], state->rollTime[0]); - if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect) - DOLPHIN_DEED(getRandomDeed()); - if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect - 1) - DOLPHIN_DEED(getRandomDeed()); + // if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect) + // DOLPHIN_DEED(getRandomDeed()); + // if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect - 1) + // DOLPHIN_DEED(getRandomDeed()); if(state->diceQty == 1) { snprintf(state->strings[1], sizeof(state->strings[1]), "%d", state->diceRoll); } else if(state->diceQty == 2) { diff --git a/applications/plugins/hc_sr04/README.md b/applications/plugins/hc_sr04/README.md deleted file mode 100644 index 2fb3b8ce4..000000000 --- a/applications/plugins/hc_sr04/README.md +++ /dev/null @@ -1 +0,0 @@ -## (5V -> VCC) / (GND -> GND) / (13|TX -> Trig) / (14|RX -> Echo) \ No newline at end of file diff --git a/applications/plugins/hc_sr04/hc_sr04.c b/applications/plugins/hc_sr04/hc_sr04.c index dbbf4f3ec..db075247a 100644 --- a/applications/plugins/hc_sr04/hc_sr04.c +++ b/applications/plugins/hc_sr04/hc_sr04.c @@ -3,6 +3,7 @@ // Ported and modified by @xMasterX #include +#include #include #include #include @@ -26,7 +27,7 @@ typedef struct { NotificationApp* notification; bool have_5v; bool measurement_made; - uint32_t echo; // ms + uint32_t echo; // us float distance; // meters } PluginState; @@ -72,7 +73,7 @@ static void render_callback(Canvas* const canvas, void* ctx) { FuriString* str_buf; str_buf = furi_string_alloc(); - furi_string_printf(str_buf, "Echo: %ld ms", plugin_state->echo); + furi_string_printf(str_buf, "Echo: %ld us", plugin_state->echo); canvas_draw_str_aligned( canvas, 8, 38, AlignLeft, AlignTop, furi_string_get_cstr(str_buf)); @@ -110,9 +111,11 @@ static void hc_sr04_state_init(PluginState* const plugin_state) { } } -float hc_sr04_ms_to_m(uint32_t ms) { - const float speed_sound_m_per_s = 343.0f; - const float time_s = ms / 1e3f; +float hc_sr04_us_to_m(uint32_t us) { + //speed of sound for 20°C, 50% relative humidity + //331.3 + 20 * 0.606 + 50 * 0.0124 = 0.034404 + const float speed_sound_m_per_s = 344.04f; + const float time_s = us / 1e6f; const float total_dist = time_s * speed_sound_m_per_s; return total_dist / 2.0f; } @@ -147,10 +150,6 @@ static void hc_sr04_measure(PluginState* const plugin_state) { furi_delay_ms(10); furi_hal_gpio_write(&gpio_usart_tx, false); - // TODO change from furi_get_tick(), which returns ms, - // to DWT->CYCCNT, which is a more precise counter with - // us precision (see furi_hal_cortex_delay_us) - const uint32_t start = furi_get_tick(); while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx)) @@ -158,16 +157,17 @@ static void hc_sr04_measure(PluginState* const plugin_state) { while(furi_get_tick() - start < timeout_ms && !furi_hal_gpio_read(&gpio_usart_rx)) ; - const uint32_t pulse_start = furi_get_tick(); + const uint32_t pulse_start = DWT->CYCCNT; while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx)) ; + const uint32_t pulse_end = DWT->CYCCNT; - const uint32_t pulse_end = furi_get_tick(); //FURI_CRITICAL_EXIT(); - plugin_state->echo = pulse_end - pulse_start; - plugin_state->distance = hc_sr04_ms_to_m(pulse_end - pulse_start); + plugin_state->echo = + (pulse_end - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); + plugin_state->distance = hc_sr04_us_to_m(plugin_state->echo); plugin_state->measurement_made = true; //furi_hal_light_set(LightRed, 0x00); @@ -270,4 +270,4 @@ int32_t hc_sr04_app() { delete_mutex(&state_mutex); return 0; -} \ No newline at end of file +} diff --git a/applications/plugins/lightmeter/.clang-format b/applications/plugins/lightmeter/.clang-format deleted file mode 100644 index 4b76f7fa4..000000000 --- a/applications/plugins/lightmeter/.clang-format +++ /dev/null @@ -1,191 +0,0 @@ ---- -Language: Cpp -AccessModifierOffset: -4 -AlignAfterOpenBracket: AlwaysBreak -AlignArrayOfStructures: None -AlignConsecutiveMacros: None -AlignConsecutiveAssignments: None -AlignConsecutiveBitFields: None -AlignConsecutiveDeclarations: None -AlignEscapedNewlines: Left -AlignOperands: Align -AlignTrailingComments: false -AllowAllArgumentsOnNextLine: true -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortEnumsOnASingleLine: true -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: None -AllowShortLambdasOnASingleLine: All -AllowShortIfStatementsOnASingleLine: WithoutElse -AllowShortLoopsOnASingleLine: true -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes -AttributeMacros: - - __capability -BinPackArguments: false -BinPackParameters: false -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: Never - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - AfterExternBlock: false - BeforeCatch: false - BeforeElse: false - BeforeLambdaBody: false - BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: true - SplitEmptyRecord: true - SplitEmptyNamespace: true -BreakBeforeBinaryOperators: None -BreakBeforeConceptDeclarations: true -BreakBeforeBraces: Attach -BreakBeforeInheritanceComma: false -BreakInheritanceList: BeforeColon -BreakBeforeTernaryOperators: false -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeComma -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: false -ColumnLimit: 99 -CommentPragmas: '^ IWYU pragma:' -QualifierAlignment: Leave -CompactNamespaces: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DeriveLineEnding: true -DerivePointerAlignment: false -DisableFormat: false -EmptyLineAfterAccessModifier: Never -EmptyLineBeforeAccessModifier: LogicalBlock -ExperimentalAutoDetectBinPacking: false -PackConstructorInitializers: BinPack -BasedOnStyle: '' -ConstructorInitializerAllOnOneLineOrOnePerLine: false -AllowAllConstructorInitializersOnNextLine: true -FixNamespaceComments: false -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IfMacros: - - KJ_IF_MAYBE -IncludeBlocks: Preserve -IncludeCategories: - - Regex: '.*' - Priority: 1 - SortPriority: 0 - CaseSensitive: false - - Regex: '^(<|"(gtest|gmock|isl|json)/)' - Priority: 3 - SortPriority: 0 - CaseSensitive: false - - Regex: '.*' - Priority: 1 - SortPriority: 0 - CaseSensitive: false -IncludeIsMainRegex: '(Test)?$' -IncludeIsMainSourceRegex: '' -IndentAccessModifiers: false -IndentCaseLabels: false -IndentCaseBlocks: false -IndentGotoLabels: true -IndentPPDirectives: None -IndentExternBlock: AfterExternBlock -IndentRequires: false -IndentWidth: 4 -IndentWrappedFunctionNames: true -InsertTrailingCommas: None -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: false -LambdaBodyIndentation: Signature -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 4 -ObjCBreakBeforeNestedBlockParam: true -ObjCSpaceAfterProperty: true -ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 10 -PenaltyBreakBeforeFirstCallParameter: 30 -PenaltyBreakComment: 10 -PenaltyBreakFirstLessLess: 0 -PenaltyBreakOpenParenthesis: 0 -PenaltyBreakString: 10 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 100 -PenaltyReturnTypeOnItsOwnLine: 60 -PenaltyIndentedWhitespace: 0 -PointerAlignment: Left -PPIndentWidth: -1 -ReferenceAlignment: Pointer -ReflowComments: false -RemoveBracesLLVM: false -SeparateDefinitionBlocks: Leave -ShortNamespaceLines: 1 -SortIncludes: Never -SortJavaStaticImport: Before -SortUsingDeclarations: false -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true -SpaceBeforeCaseColon: false -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: Never -SpaceBeforeParensOptions: - AfterControlStatements: false - AfterForeachMacros: false - AfterFunctionDefinitionName: false - AfterFunctionDeclarationName: false - AfterIfMacros: false - AfterOverloadedOperator: false - BeforeNonEmptyParentheses: false -SpaceAroundPointerQualifiers: Default -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: false -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: Never -SpacesInConditionalStatement: false -SpacesInContainerLiterals: false -SpacesInCStyleCastParentheses: false -SpacesInLineCommentPrefix: - Minimum: 1 - Maximum: -1 -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpaceBeforeSquareBrackets: false -BitFieldColonSpacing: Both -Standard: c++03 -StatementAttributeLikeMacros: - - Q_EMIT -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION -TabWidth: 4 -UseCRLF: false -UseTab: Never -WhitespaceSensitiveMacros: - - STRINGIZE - - PP_STRINGIZE - - BOOST_PP_STRINGIZE - - NS_SWIFT_NAME - - CF_SWIFT_NAME -... - diff --git a/applications/plugins/lightmeter/README.md b/applications/plugins/lightmeter/README.md index dc6c6ffd5..d9c071e67 100644 --- a/applications/plugins/lightmeter/README.md +++ b/applications/plugins/lightmeter/README.md @@ -1,10 +1,9 @@ -# flipperzero-lightmeter +# flipperzero-lightmeter -[![Build FAP](https://github.com/oleksiikutuzov/flipperzero-lightmeter/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/oleksiikutuzov/flipperzero-lightmeter/actions/workflows/build.yml) +[Original link](https://github.com/oleksiikutuzov/flipperzero-lightmeter) - - + ## Wiring @@ -15,19 +14,6 @@ SCL -> C0 SDA -> C1 ``` -## Sensor module - - - -### If you want to build this module, you'll need (it's quite over-engineered, sorry :D) -1. [Module PCB](https://github.com/oleksiikutuzov/flipperzero-lightmeter/blob/main/module/module_v2_gerber.zip) -2. [Enclosure](https://github.com/oleksiikutuzov/flipperzero-lightmeter/blob/main/module/module_v2_enclosure.stl) -3. 4-pin female header -4. 10-pin male header -5. 2x M3 threaded inserts (max diameter 5.3 mm, max height 4 mm) -6. 2x M3x5 screws - - ## TODO - [ ] Save settings to sd card diff --git a/applications/plugins/lightmeter/application.fam b/applications/plugins/lightmeter/application.fam index b1de62641..b1ae6c6b2 100644 --- a/applications/plugins/lightmeter/application.fam +++ b/applications/plugins/lightmeter/application.fam @@ -9,7 +9,6 @@ App( ], stack_size=1 * 1024, order=90, - fap_version=(0, 7), fap_icon="lightmeter.png", fap_category="GPIO", fap_private_libs=[ @@ -22,7 +21,4 @@ App( ), ], fap_icon_assets="icons", - fap_description="Lightmeter app for photography based on BH1750 sensor", - fap_author="Oleksii Kutuzov", - fap_weburl="https://github.com/oleksiikutuzov/flipperzero-lightmeter", ) diff --git a/applications/plugins/lightmeter/gui/views/main_view.c b/applications/plugins/lightmeter/gui/views/main_view.c index fcbafbff4..8b3e2989f 100644 --- a/applications/plugins/lightmeter/gui/views/main_view.c +++ b/applications/plugins/lightmeter/gui/views/main_view.c @@ -62,11 +62,11 @@ const float aperture_numbers[] = { const float speed_numbers[] = { [SPEED_8000] = 1.0 / 8000, [SPEED_4000] = 1.0 / 4000, [SPEED_2000] = 1.0 / 2000, [SPEED_1000] = 1.0 / 1000, [SPEED_500] = 1.0 / 500, [SPEED_250] = 1.0 / 250, - [SPEED_125] = 1.0 / 125, [SPEED_60] = 1.0 / 60, [SPEED_30] = 1.0 / 30, - [SPEED_15] = 1.0 / 15, [SPEED_8] = 1.0 / 8, [SPEED_4] = 1.0 / 4, - [SPEED_2] = 1.0 / 2, [SPEED_1S] = 1.0, [SPEED_2S] = 2.0, - [SPEED_4S] = 4.0, [SPEED_8S] = 8.0, [SPEED_15S] = 15.0, - [SPEED_30S] = 30.0, + [SPEED_125] = 1.0 / 125, [SPEED_60] = 1.0 / 60, [SPEED_48] = 1.0 / 48, + [SPEED_30] = 1.0 / 30, [SPEED_15] = 1.0 / 15, [SPEED_8] = 1.0 / 8, + [SPEED_4] = 1.0 / 4, [SPEED_2] = 1.0 / 2, [SPEED_1S] = 1.0, + [SPEED_2S] = 2.0, [SPEED_4S] = 4.0, [SPEED_8S] = 8.0, + [SPEED_15S] = 15.0, [SPEED_30S] = 30.0, }; struct MainView { diff --git a/applications/plugins/lightmeter/images/framed_gui_config.png b/applications/plugins/lightmeter/images/framed_gui_config.png deleted file mode 100644 index b87c3bd5c..000000000 Binary files a/applications/plugins/lightmeter/images/framed_gui_config.png and /dev/null differ diff --git a/applications/plugins/lightmeter/images/framed_gui_lux_meter.png b/applications/plugins/lightmeter/images/framed_gui_lux_meter.png deleted file mode 100644 index 6ab0cf191..000000000 Binary files a/applications/plugins/lightmeter/images/framed_gui_lux_meter.png and /dev/null differ diff --git a/applications/plugins/lightmeter/images/framed_gui_main.png b/applications/plugins/lightmeter/images/framed_gui_main.png deleted file mode 100644 index 23dc4a2cc..000000000 Binary files a/applications/plugins/lightmeter/images/framed_gui_main.png and /dev/null differ diff --git a/applications/plugins/lightmeter/images/gui_config.png b/applications/plugins/lightmeter/images/gui_config.png deleted file mode 100644 index 95fdcb167..000000000 Binary files a/applications/plugins/lightmeter/images/gui_config.png and /dev/null differ diff --git a/applications/plugins/lightmeter/images/gui_lux_meter.png b/applications/plugins/lightmeter/images/gui_lux_meter.png deleted file mode 100644 index f7159e671..000000000 Binary files a/applications/plugins/lightmeter/images/gui_lux_meter.png and /dev/null differ diff --git a/applications/plugins/lightmeter/images/gui_main.png b/applications/plugins/lightmeter/images/gui_main.png deleted file mode 100644 index ba4c3f75f..000000000 Binary files a/applications/plugins/lightmeter/images/gui_main.png and /dev/null differ diff --git a/applications/plugins/lightmeter/lib/BH1750/BH1750.c b/applications/plugins/lightmeter/lib/BH1750/BH1750.c index 28616e040..9e6a50758 100644 --- a/applications/plugins/lightmeter/lib/BH1750/BH1750.c +++ b/applications/plugins/lightmeter/lib/BH1750/BH1750.c @@ -15,6 +15,7 @@ BH1750_mode bh1750_mode = BH1750_DEFAULT_MODE; // Current sensor mode uint8_t bh1750_mt_reg = BH1750_DEFAULT_MTREG; // Current MT register value +uint8_t bh1750_addr = BH1750_ADDRESS; BH1750_STATUS bh1750_init() { if(BH1750_OK == bh1750_reset()) { @@ -25,12 +26,17 @@ BH1750_STATUS bh1750_init() { return BH1750_ERROR; } +BH1750_STATUS bh1750_init_with_addr(uint8_t addr) { + bh1750_addr = (addr << 1); + return bh1750_init(); +} + BH1750_STATUS bh1750_reset() { uint8_t command = 0x07; bool status; furi_hal_i2c_acquire(I2C_BUS); - status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &command, 1, I2C_TIMEOUT); + status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &command, 1, I2C_TIMEOUT); furi_hal_i2c_release(I2C_BUS); if(status) { @@ -45,7 +51,7 @@ BH1750_STATUS bh1750_set_power_state(uint8_t PowerOn) { bool status; furi_hal_i2c_acquire(I2C_BUS); - status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &PowerOn, 1, I2C_TIMEOUT); + status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &PowerOn, 1, I2C_TIMEOUT); furi_hal_i2c_release(I2C_BUS); if(status) { @@ -69,7 +75,7 @@ BH1750_STATUS bh1750_set_mode(BH1750_mode mode) { bh1750_mode = mode; furi_hal_i2c_acquire(I2C_BUS); - status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &mode, 1, I2C_TIMEOUT); + status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &mode, 1, I2C_TIMEOUT); furi_hal_i2c_release(I2C_BUS); if(status) { @@ -93,14 +99,14 @@ BH1750_STATUS bh1750_set_mt_reg(uint8_t mt_reg) { tmp[1] = (0x60 | (mt_reg & 0x1F)); furi_hal_i2c_acquire(I2C_BUS); - status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &tmp[0], 1, I2C_TIMEOUT); + status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &tmp[0], 1, I2C_TIMEOUT); furi_hal_i2c_release(I2C_BUS); if(!status) { return BH1750_ERROR; } furi_hal_i2c_acquire(I2C_BUS); - status = furi_hal_i2c_tx(I2C_BUS, BH1750_ADDRESS, &tmp[1], 1, I2C_TIMEOUT); + status = furi_hal_i2c_tx(I2C_BUS, bh1750_addr, &tmp[1], 1, I2C_TIMEOUT); furi_hal_i2c_release(I2C_BUS); if(status) { return BH1750_OK; @@ -122,7 +128,7 @@ BH1750_STATUS bh1750_read_light(float* result) { bool status; furi_hal_i2c_acquire(I2C_BUS); - status = furi_hal_i2c_rx(I2C_BUS, BH1750_ADDRESS, rcv, 2, I2C_TIMEOUT); + status = furi_hal_i2c_rx(I2C_BUS, bh1750_addr, rcv, 2, I2C_TIMEOUT); furi_hal_i2c_release(I2C_BUS); if(status) { diff --git a/applications/plugins/lightmeter/lib/BH1750/BH1750.h b/applications/plugins/lightmeter/lib/BH1750/BH1750.h index 991350f7f..46649c33e 100644 --- a/applications/plugins/lightmeter/lib/BH1750/BH1750.h +++ b/applications/plugins/lightmeter/lib/BH1750/BH1750.h @@ -49,6 +49,13 @@ typedef enum { */ BH1750_STATUS bh1750_init(); +/** + * @brief Change the I2C device address and then initialize the sensor. + * + * @return BH1750_STATUS + */ +BH1750_STATUS bh1750_init_with_addr(uint8_t addr); + /** * @brief Reset all registers to the default value. * diff --git a/applications/plugins/lightmeter/lightmeter_config.h b/applications/plugins/lightmeter/lightmeter_config.h index 4f7e11e0d..5edbdce0a 100644 --- a/applications/plugins/lightmeter/lightmeter_config.h +++ b/applications/plugins/lightmeter/lightmeter_config.h @@ -79,6 +79,7 @@ typedef enum { SPEED_250, SPEED_125, SPEED_60, + SPEED_48, SPEED_30, SPEED_15, SPEED_8, diff --git a/applications/plugins/lightmeter/module/back.jpg b/applications/plugins/lightmeter/module/back.jpg deleted file mode 100644 index 366d7a852..000000000 Binary files a/applications/plugins/lightmeter/module/back.jpg and /dev/null differ diff --git a/applications/plugins/lightmeter/module/front.jpg b/applications/plugins/lightmeter/module/front.jpg deleted file mode 100644 index b38fd4150..000000000 Binary files a/applications/plugins/lightmeter/module/front.jpg and /dev/null differ diff --git a/applications/plugins/lightmeter/module/module.jpg b/applications/plugins/lightmeter/module/module.jpg deleted file mode 100644 index 53f481338..000000000 Binary files a/applications/plugins/lightmeter/module/module.jpg and /dev/null differ diff --git a/applications/plugins/lightmeter/module/module_v2_enclosure.stl b/applications/plugins/lightmeter/module/module_v2_enclosure.stl deleted file mode 100644 index ee2be93fd..000000000 Binary files a/applications/plugins/lightmeter/module/module_v2_enclosure.stl and /dev/null differ diff --git a/applications/plugins/lightmeter/module/module_v2_gerber.zip b/applications/plugins/lightmeter/module/module_v2_gerber.zip deleted file mode 100644 index 02887f4bf..000000000 Binary files a/applications/plugins/lightmeter/module/module_v2_gerber.zip and /dev/null differ diff --git a/applications/plugins/metronome/README.md b/applications/plugins/metronome/README.md index 79134c350..4b6cd3122 100644 --- a/applications/plugins/metronome/README.md +++ b/applications/plugins/metronome/README.md @@ -1,5 +1,7 @@ # Metronome +[Original link](https://github.com/panki27/Metronome) + A metronome for the [Flipper Zero](https://flipperzero.one/) device. Goes along perfectly with my [BPM tapper](https://github.com/panki27/bpm-tapper). ![screenshot](img/screenshot.png) @@ -17,5 +19,5 @@ A metronome for the [Flipper Zero](https://flipperzero.one/) device. Goes along ## Compiling ``` -./fbt fap_metronome +./fbt firmware_metronome ``` diff --git a/applications/plugins/metronome/application.fam b/applications/plugins/metronome/application.fam index b40809638..32588d06e 100644 --- a/applications/plugins/metronome/application.fam +++ b/applications/plugins/metronome/application.fam @@ -8,8 +8,8 @@ App( "gui", ], fap_icon="metronome_icon.png", - fap_icon_assets="icons", fap_category="Music", + fap_icon_assets="images", stack_size=2 * 1024, order=20, ) diff --git a/applications/plugins/metronome/gui_extensions.c b/applications/plugins/metronome/gui_extensions.c index a7661ec28..458eb137b 100644 --- a/applications/plugins/metronome/gui_extensions.c +++ b/applications/plugins/metronome/gui_extensions.c @@ -1,6 +1,6 @@ #include #include -#include "Metronome_icons.h" +#include //lib can only do bottom left/right void elements_button_top_left(Canvas* canvas, const char* str) { diff --git a/applications/plugins/metronome/icons/ButtonUp_7x4.png b/applications/plugins/metronome/images/ButtonUp_7x4.png similarity index 100% rename from applications/plugins/metronome/icons/ButtonUp_7x4.png rename to applications/plugins/metronome/images/ButtonUp_7x4.png diff --git a/applications/plugins/metronome/metronome.c b/applications/plugins/metronome/metronome.c index 4c374aa75..06bce1bff 100644 --- a/applications/plugins/metronome/metronome.c +++ b/applications/plugins/metronome/metronome.c @@ -287,7 +287,6 @@ int32_t metronome_app() { metronome_state->timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, &state_mutex); // Open GUI and register view_port - // Gui* gui = furi_record_open("gui"); gui_add_view_port(gui, view_port, GuiLayerFullscreen); @@ -326,7 +325,7 @@ int32_t metronome_app() { case InputKeyBack: processing = false; break; - case InputKeyMAX: + default: break; } } else if(event.input.type == InputTypeLong) { @@ -348,7 +347,7 @@ int32_t metronome_app() { case InputKeyBack: processing = false; break; - case InputKeyMAX: + default: break; } } else if(event.input.type == InputTypeRepeat) { @@ -369,7 +368,7 @@ int32_t metronome_app() { case InputKeyBack: processing = false; break; - case InputKeyMAX: + default: break; } } diff --git a/applications/plugins/mousejacker/README.md b/applications/plugins/mousejacker/README.md deleted file mode 100644 index ad5fdecdc..000000000 --- a/applications/plugins/mousejacker/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# flipperzero-nrf24 - -An [NRF24](https://www.sparkfun.com/datasheets/Components/SMD/nRF24L01Pluss_Preliminary_Product_Specification_v1_0.pdf) driver for the [Flipper Zero](https://flipperzero.one/) device. The NRF24 is a popular line of 2.4GHz radio transceivers from Nordic Semiconductors. This library is not currently complete, but functional. - -## Warning -This repo contains two Flipper Zero apps that utilize the NRF24 driver to sniff for NRF24 addresses and perform mousejack attacks. These apps are for **educational purposes** only. Please use this code responsibly and only use these apps on your own equipment. - -## Acknowledgments -The NRF24 sniffing technique was discovered and shared by Travis Goodspeed in [his blog](http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html). - -The mousejack vulnerabilities were discovered and reported by Marc Newlin, see [the blog](https://www.bastille.net/research/vulnerabilities/mousejack/technical-details) for technical details. - -Much of the driver code was inspired by [RadioHead's Arduino library](https://www.airspayce.com/mikem/arduino/RadioHead/classRH__NRF24.html). -Much of the mousejack code was inspired by the [Jackit project](https://github.com/insecurityofthings/jackit). - - -## PinOut from from NoComp/Frog - - -# Mousejack / NRF24 pinout by UberGuidoZ -2/A7 on FZ goes to MOSI/6 on nrf24l01
-3/A6 on FZ goes to MISO/7 on nrf24l01
-4/A4 on FZ goes to CSN/4 on nrf24l01
-5/B3 on FZ goes to SCK/5 on nrf24l01
-6/B2 on FZ goes to CE/3 on nrf24l01
-8/GND on FZ goes to GND/1 on nrf24l01
-9/3V3 on FZ goes to VCC/2 on nrf24l01
-IRQ/8 is left disconnected on nrf24l01 - -![NRF_Pins](https://user-images.githubusercontent.com/57457139/178093717-39effd5c-ebe2-4253-b13c-70517d7902f9.png) - -If the nRF module is acting a bit flakey, try adding a capacitor to the vcc/gnd lines! I've not tried the Plus model so it may have a bigger need for a cap. Otherwise, I haven't had any major issues. Anything from a 3.3 uF to 10 uF should do. (Watch your positive/negative placement! Negative to ground.) I learned if you wanna get fancy, include a 0.1 uF cap in parallel. The 3.3 uF to 10 uF will respond to slow freq changes while the 0.1 uF will respond to the high freq switching spikes that the larger one cannot. That said, a single 10 uF will likely suffice for the Mousejack attack. ¯\\\_(ツ)_/¯ - -![NRF_Capacitor](https://user-images.githubusercontent.com/57457139/178169959-d030f9a6-d2ac-46af-af8b-470ff092c8a7.jpg) - -Selfmade NRF24 breakoutboard: -![NRF_soldered](https://user-images.githubusercontent.com/22019133/183419103-9c40b28b-8152-4212-98e0-9a3358f69518.jpeg) -![NRF_soldered2](https://user-images.githubusercontent.com/22019133/183419176-26c0359b-0ecb-4015-8f8b-3a75209502ba.jpeg) - -## Practical hints from einstein2150 -If you are not successfull with the NRF Sniff Plugin you can try to get the MAC of the device with the crazyradio pa USB dongle. Have a look here: https://github.com/SySS-Research/nrf24-playset - - -A sample output of the NRF-Research script could be like -``` -[2022-08-05 13:28:56.366] Found nRF24 device with address 38:24:93:C0:07 on channel 75\ -[2022-08-05 13:28:56.371] Checking communication\ -[2022-08-05 13:28:59.088] Scan for nRF24 device\ -[2022-08-05 13:28:59.097] Actively searching for address 07:C0:93:24:38\ -``` - -Be carefull with the byte-order using in mousejacker! The correct byte order is the reverse-byteorder. In my example the reversed one is ```07:C0:93:24:38``` for my Logitech R400 presenter. -The next thing which could make trouble is the datarate. In my case the Logitech-device is only responding at 2Mbit. Commands at 1Mbit are not detected. - -Now its time to write all the relevant information in the config file. In my case you are creating a file ```addresses.txt``` in the SD directory of ```/nrfsniff```. The file content corresponding to the results of the research is ```07C0932438,2``` representing the reversed byte order of the MAC and the comma-separated datarate. - -Start the Mouse Jacker plugin and select the prepared ```addresses.txt```. If everything is alright you are starting with your MAC ready for attack: - -![mousejacker start-screen](https://user-images.githubusercontent.com/22019133/183419533-ef5c8df1-e328-45e3-b85d-376513d69c82.jpeg) - -If you have troube you can check if a datarate of 1 Mbit will help. Change ```07C0932438,2``` to ```07C0932438,1``` in this case. Another problem in the practical use is electromagnetical noise. In my case the external USB-3.1-Hub creating massive noise in the 2,4 Ghz-Frequency around a distance of 5 cm. Try using a long USB connection-cable for the receiver. In my case the response of the attack raises significant because the signals of the NRF-breakoutboard is no more covered with noise. - diff --git a/applications/plugins/mousejacker/application.fam b/applications/plugins/mousejacker/application.fam index 05835700b..725e81ae8 100644 --- a/applications/plugins/mousejacker/application.fam +++ b/applications/plugins/mousejacker/application.fam @@ -9,7 +9,7 @@ App( "dialogs", ], stack_size=2 * 1024, - order=50, + order=60, fap_icon="mouse_10px.png", fap_category="GPIO", fap_icon_assets="images", diff --git a/applications/plugins/mousejacker/icons/badkb_10px.png b/applications/plugins/mousejacker/icons/badkb_10px.png deleted file mode 100644 index 037474aa3..000000000 Binary files a/applications/plugins/mousejacker/icons/badkb_10px.png and /dev/null differ diff --git a/applications/plugins/mousejacker/icons/sub1_10px.png b/applications/plugins/mousejacker/icons/sub1_10px.png deleted file mode 100644 index 5a25fdf4e..000000000 Binary files a/applications/plugins/mousejacker/icons/sub1_10px.png and /dev/null differ diff --git a/applications/plugins/mousejacker/mousejacker.c b/applications/plugins/mousejacker/mousejacker.c index 3bd772889..8aaea0689 100644 --- a/applications/plugins/mousejacker/mousejacker.c +++ b/applications/plugins/mousejacker/mousejacker.c @@ -184,7 +184,7 @@ static bool process_ducky_file( mj_process_ducky_script( nrf24_HANDLE, addr, addr_size, rate, (char*)file_buf, plugin_state); FURI_LOG_D(TAG, "finished execution"); - DOLPHIN_DEED(getRandomDeed()); + // DOLPHIN_DEED(getRandomDeed()); loaded = true; } else { FURI_LOG_D(TAG, "load failed. file size: %d", file_size); diff --git a/applications/plugins/mousejacker/mousejacker_ducky.c b/applications/plugins/mousejacker/mousejacker_ducky.c index b3b04d836..04b0bfaca 100644 --- a/applications/plugins/mousejacker/mousejacker_ducky.c +++ b/applications/plugins/mousejacker/mousejacker_ducky.c @@ -3,6 +3,7 @@ static const char ducky_cmd_comment[] = {"REM"}; static const char ducky_cmd_delay[] = {"DELAY "}; static const char ducky_cmd_string[] = {"STRING "}; +static const char ducky_cmd_altstring[] = {"ALTSTRING "}; static const char ducky_cmd_repeat[] = {"REPEAT "}; static uint8_t LOGITECH_HID_TEMPLATE[] = @@ -11,6 +12,10 @@ static uint8_t LOGITECH_HELLO[] = {0x00, 0x4F, 0x00, 0x04, 0xB0, 0x10, 0x00, 0x0 static uint8_t LOGITECH_KEEPALIVE[] = {0x00, 0x40, 0x00, 0x55, 0x6B}; uint8_t prev_hid = 0; +static bool holding_ctrl = false; +static bool holding_shift = false; +static bool holding_alt = false; +static bool holding_gui = false; #define RT_THRESHOLD 50 #define LOGITECH_MIN_CHANNEL 2 @@ -65,7 +70,10 @@ MJDuckyKey mj_ducky_keys[] = {{" ", 44, 0}, {"!", 30, 2}, {"\"" {"LEFTARROW", 80, 0}, {"RIGHTARROW", 79, 0}, {"PAGEDOWN", 78, 0}, {"PAUSE", 72, 0}, {"SPACE", 44, 0}, {"UPARROW", 82, 0}, {"F11", 68, 0}, {"F7", 64, 0}, {"UP", 82, 0}, - {"LEFT", 80, 0}}; + {"LEFT", 80, 0}, {"NUM 1", 89, 0}, {"NUM 2", 90, 0}, + {"NUM 3", 91, 0}, {"NUM 4", 92, 0}, {"NUM 5", 93, 0}, + {"NUM 6", 94, 0}, {"NUM 7", 95, 0}, {"NUM 8", 96, 0}, + {"NUM 9", 97, 0}, {"NUM 0", 98, 0}}; /* static bool mj_ducky_get_number(const char* param, uint32_t* val) { @@ -89,7 +97,8 @@ static uint32_t mj_ducky_get_command_len(const char* line) { static bool mj_get_ducky_key(char* key, size_t keylen, MJDuckyKey* dk) { //FURI_LOG_D(TAG, "looking up key %s with length %d", key, keylen); for(uint i = 0; i < sizeof(mj_ducky_keys) / sizeof(MJDuckyKey); i++) { - if(!strncmp(mj_ducky_keys[i].name, key, keylen)) { + if(strlen(mj_ducky_keys[i].name) == keylen && + !strncmp(mj_ducky_keys[i].name, key, keylen)) { memcpy(dk, &mj_ducky_keys[i], sizeof(MJDuckyKey)); return true; } @@ -152,6 +161,30 @@ static void build_hid_packet(uint8_t mod, uint8_t hid, uint8_t* payload) { checksum(payload, LOGITECH_HID_TEMPLATE_SIZE); } +static void release_key( + FuriHalSpiBusHandle* handle, + uint8_t* addr, + uint8_t addr_size, + uint8_t rate, + PluginState* plugin_state) { + // This function release keys currently pressed, but keep pressing special keys + // if holding mod keys variable are set to true + + uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0}; + build_hid_packet( + 0 | holding_ctrl | holding_shift << 1 | holding_alt << 2 | holding_gui << 3, + 0, + hid_payload); + inject_packet( + handle, + addr, + addr_size, + rate, + hid_payload, + LOGITECH_HID_TEMPLATE_SIZE, + plugin_state); // empty hid packet +} + static void send_hid_packet( FuriHalSpiBusHandle* handle, uint8_t* addr, @@ -161,24 +194,22 @@ static void send_hid_packet( uint8_t hid, PluginState* plugin_state) { uint8_t hid_payload[LOGITECH_HID_TEMPLATE_SIZE] = {0}; - build_hid_packet(0, 0, hid_payload); - if(hid == prev_hid) - inject_packet( - handle, - addr, - addr_size, - rate, - hid_payload, - LOGITECH_HID_TEMPLATE_SIZE, - plugin_state); // empty hid packet + if(hid == prev_hid) release_key(handle, addr, addr_size, rate, plugin_state); prev_hid = hid; - build_hid_packet(mod, hid, hid_payload); + build_hid_packet( + mod | holding_ctrl | holding_shift << 1 | holding_alt << 2 | holding_gui << 3, + hid, + hid_payload); inject_packet( handle, addr, addr_size, rate, hid_payload, LOGITECH_HID_TEMPLATE_SIZE, plugin_state); furi_delay_ms(12); } +static bool ducky_end_line(const char chr) { + return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n')); +} + // returns false if there was an error processing script line static bool mj_process_ducky_line( FuriHalSpiBusHandle* handle, @@ -251,6 +282,32 @@ static bool mj_process_ducky_line( send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); } + return true; + } else if(strncmp(line_tmp, ducky_cmd_altstring, strlen(ducky_cmd_altstring)) == 0) { + // ALTSTRING + line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; + for(size_t i = 0; i < strlen(line_tmp); i++) { + if((line_tmp[i] < ' ') || (line_tmp[i] > '~')) { + continue; // Skip non-printable chars + } + + char alt_code[4]; + // Getting altcode of the char + snprintf(alt_code, 4, "%u", line_tmp[i]); + + uint8_t j = 0; + while(!ducky_end_line(alt_code[j])) { + char pad_num[5] = {'N', 'U', 'M', ' ', alt_code[j]}; + if(!mj_get_ducky_key(pad_num, 5, &dk)) return false; + holding_alt = true; + FURI_LOG_D(TAG, "Sending %s", pad_num); + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + j++; + } + holding_alt = false; + release_key(handle, addr, addr_size, rate, plugin_state); + } + return true; } else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) { // REPEAT @@ -269,7 +326,9 @@ static bool mj_process_ducky_line( } else if(strncmp(line_tmp, "ALT", strlen("ALT")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 4, dk.hid, plugin_state); + holding_alt = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_alt = false; return true; } else if( strncmp(line_tmp, "GUI", strlen("GUI")) == 0 || @@ -277,33 +336,47 @@ static bool mj_process_ducky_line( strncmp(line_tmp, "COMMAND", strlen("COMMAND")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 8, dk.hid, plugin_state); + holding_gui = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_gui = false; return true; } else if( strncmp(line_tmp, "CTRL-ALT", strlen("CTRL-ALT")) == 0 || strncmp(line_tmp, "CONTROL-ALT", strlen("CONTROL-ALT")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 4 | 1, dk.hid, plugin_state); + holding_ctrl = true; + holding_alt = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_ctrl = false; + holding_alt = false; return true; } else if( strncmp(line_tmp, "CTRL-SHIFT", strlen("CTRL-SHIFT")) == 0 || strncmp(line_tmp, "CONTROL-SHIFT", strlen("CONTROL-SHIFT")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 1 | 2, dk.hid, plugin_state); + holding_ctrl = true; + holding_shift = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_ctrl = false; + holding_shift = false; return true; } else if( strncmp(line_tmp, "CTRL", strlen("CTRL")) == 0 || strncmp(line_tmp, "CONTROL", strlen("CONTROL")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 1, dk.hid, plugin_state); + holding_ctrl = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_ctrl = false; return true; } else if(strncmp(line_tmp, "SHIFT", strlen("SHIFT")) == 0) { line_tmp = &line_tmp[mj_ducky_get_command_len(line_tmp) + 1]; if(!mj_get_ducky_key(line_tmp, strlen(line_tmp), &dk)) return false; - send_hid_packet(handle, addr, addr_size, rate, dk.mod | 2, dk.hid, plugin_state); + holding_shift = true; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + holding_shift = false; return true; } else if( strncmp(line_tmp, "ESC", strlen("ESC")) == 0 || @@ -344,6 +417,10 @@ static bool mj_process_ducky_line( if(!mj_get_ducky_key("SPACE", 5, &dk)) return false; send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); return true; + } else if(strncmp(line_tmp, "TAB", strlen("TAB")) == 0) { + if(!mj_get_ducky_key("TAB", 3, &dk)) return false; + send_hid_packet(handle, addr, addr_size, rate, dk.mod, dk.hid, plugin_state); + return true; } return false; diff --git a/applications/plugins/nrfsniff/nrfsniff.c b/applications/plugins/nrfsniff/nrfsniff.c index ce2836152..2dbf8f851 100644 --- a/applications/plugins/nrfsniff/nrfsniff.c +++ b/applications/plugins/nrfsniff/nrfsniff.c @@ -291,7 +291,7 @@ static void wrap_up(Storage* storage, NotificationApp* notification) { hexlify(addr, 5, top_address); found_count++; save_addr_to_file(storage, addr, 5, notification); - DOLPHIN_DEED(getRandomDeed()); + // DOLPHIN_DEED(getRandomDeed()); if(confirmed_idx < MAX_CONFIRMED) memcpy(confirmed[confirmed_idx++], addr, 5); break; } diff --git a/applications/plugins/picopass/application.fam b/applications/plugins/picopass/application.fam index 5d331e708..48cbba316 100644 --- a/applications/plugins/picopass/application.fam +++ b/applications/plugins/picopass/application.fam @@ -1,6 +1,6 @@ App( appid="Picopass", - name="PicoPass Reader", + name="PicoPass", apptype=FlipperAppType.EXTERNAL, targets=["f7"], entry_point="picopass_app", @@ -9,7 +9,7 @@ App( "gui", ], stack_size=4 * 1024, - order=175, + order=30, fap_icon="125_10px.png", fap_category="Tools", fap_libs=["mbedtls"], diff --git a/applications/plugins/picopass/picopass.c b/applications/plugins/picopass/picopass.c index 805f6760e..bedaf38ef 100644 --- a/applications/plugins/picopass/picopass.c +++ b/applications/plugins/picopass/picopass.c @@ -137,9 +137,9 @@ void picopass_text_store_clear(Picopass* picopass) { memset(picopass->text_store, 0, sizeof(picopass->text_store)); } -static const NotificationSequence picopass_sequence_blink_start_blue = { +static const NotificationSequence picopass_sequence_blink_start_cyan = { &message_blink_start_10, - &message_blink_set_color_blue, + &message_blink_set_color_cyan, &message_do_not_reset, NULL, }; @@ -150,7 +150,7 @@ static const NotificationSequence picopass_sequence_blink_stop = { }; void picopass_blink_start(Picopass* picopass) { - notification_message(picopass->notifications, &picopass_sequence_blink_start_blue); + notification_message(picopass->notifications, &picopass_sequence_blink_start_cyan); } void picopass_blink_stop(Picopass* picopass) { @@ -171,6 +171,16 @@ void picopass_show_loading_popup(void* context, bool show) { } } +bool picopass_is_memset(const uint8_t* data, const uint8_t pattern, size_t size) { + bool result = size > 0; + while(size > 0) { + result &= (*data == pattern); + data++; + size--; + } + return result; +} + int32_t picopass_app(void* p) { UNUSED(p); Picopass* picopass = picopass_alloc(); diff --git a/applications/plugins/picopass/picopass_device.c b/applications/plugins/picopass/picopass_device.c index de01834bc..a5414b92b 100644 --- a/applications/plugins/picopass/picopass_device.c +++ b/applications/plugins/picopass/picopass_device.c @@ -368,7 +368,7 @@ ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* r record->CardNumber = (bot >> 1) & 0xFFFF; record->FacilityCode = (bot >> 17) & 0xFF; - FURI_LOG_D(TAG, "FC:%u CN: %u\n", record->FacilityCode, record->CardNumber); + FURI_LOG_D(TAG, "FC: %u CN: %u", record->FacilityCode, record->CardNumber); record->valid = true; } else { record->CardNumber = 0; diff --git a/applications/plugins/picopass/picopass_device.h b/applications/plugins/picopass/picopass_device.h index 150b095a7..99f1ceea6 100644 --- a/applications/plugins/picopass/picopass_device.h +++ b/applications/plugins/picopass/picopass_device.h @@ -22,6 +22,7 @@ #define PICOPASS_KD_BLOCK_INDEX 3 #define PICOPASS_KC_BLOCK_INDEX 4 #define PICOPASS_AIA_BLOCK_INDEX 5 +#define PICOPASS_PACS_CFG_BLOCK_INDEX 6 #define PICOPASS_APP_FOLDER ANY_PATH("picopass") #define PICOPASS_APP_EXTENSION ".picopass" diff --git a/applications/plugins/picopass/picopass_i.h b/applications/plugins/picopass/picopass_i.h index 8f954c83c..79c2a1af8 100644 --- a/applications/plugins/picopass/picopass_i.h +++ b/applications/plugins/picopass/picopass_i.h @@ -81,3 +81,15 @@ void picopass_blink_start(Picopass* picopass); void picopass_blink_stop(Picopass* picopass); void picopass_show_loading_popup(void* context, bool show); + +/** Check if memory is set to pattern + * + * @warning zero size will return false + * + * @param[in] data Pointer to the byte array + * @param[in] pattern The pattern + * @param[in] size The byte array size + * + * @return True if memory is set to pattern, false otherwise + */ +bool picopass_is_memset(const uint8_t* data, const uint8_t pattern, size_t size); diff --git a/applications/plugins/picopass/picopass_worker.c b/applications/plugins/picopass/picopass_worker.c index e886deb33..441efb339 100644 --- a/applications/plugins/picopass/picopass_worker.c +++ b/applications/plugins/picopass/picopass_worker.c @@ -5,7 +5,8 @@ #define TAG "PicopassWorker" const uint8_t picopass_iclass_key[] = {0xaf, 0xa7, 0x85, 0xa7, 0xda, 0xb3, 0x33, 0x78}; -const uint8_t picopass_factory_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00}; +const uint8_t picopass_factory_credit_key[] = {0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00}; +const uint8_t picopass_factory_debit_key[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87}; static void picopass_worker_enable_field() { furi_hal_nfc_ll_txrx_on(); @@ -197,6 +198,28 @@ static ReturnCode picopass_auth_standard(uint8_t* csn, uint8_t* div_key) { return rfalPicoPassPollerCheck(mac, &chkRes); } +static ReturnCode picopass_auth_factory(uint8_t* csn, uint8_t* div_key) { + rfalPicoPassReadCheckRes rcRes; + rfalPicoPassCheckRes chkRes; + + ReturnCode err; + + uint8_t mac[4] = {0}; + uint8_t ccnr[12] = {0}; + + err = rfalPicoPassPollerReadCheck(&rcRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); + return err; + } + memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 + + loclass_diversifyKey(csn, picopass_factory_debit_key, div_key); + loclass_opt_doReaderMAC(ccnr, div_key, mac); + + return rfalPicoPassPollerCheck(mac, &chkRes); +} + static ReturnCode picopass_auth_dict( uint8_t* csn, PicopassPacs* pacs, @@ -264,14 +287,23 @@ static ReturnCode picopass_auth_dict( ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { ReturnCode err; - FURI_LOG_E(TAG, "Trying standard legacy key"); + FURI_LOG_I(TAG, "Trying standard legacy key"); err = picopass_auth_standard( AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data); if(err == ERR_NONE) { + memcpy(pacs->key, picopass_iclass_key, PICOPASS_BLOCK_LEN); return ERR_NONE; } - FURI_LOG_E(TAG, "Starting user dictionary attack"); + FURI_LOG_I(TAG, "Trying factory default key"); + err = picopass_auth_factory( + AA1[PICOPASS_CSN_BLOCK_INDEX].data, AA1[PICOPASS_KD_BLOCK_INDEX].data); + if(err == ERR_NONE) { + memcpy(pacs->key, picopass_factory_debit_key, PICOPASS_BLOCK_LEN); + return ERR_NONE; + } + + FURI_LOG_I(TAG, "Starting user dictionary attack"); err = picopass_auth_dict( AA1[PICOPASS_CSN_BLOCK_INDEX].data, pacs, @@ -281,7 +313,7 @@ ReturnCode picopass_auth(PicopassBlock* AA1, PicopassPacs* pacs) { return ERR_NONE; } - FURI_LOG_E(TAG, "Starting in-built dictionary attack"); + FURI_LOG_I(TAG, "Starting system dictionary attack"); err = picopass_auth_dict( AA1[PICOPASS_CSN_BLOCK_INDEX].data, pacs, @@ -406,6 +438,84 @@ ReturnCode picopass_write_card(PicopassBlock* AA1) { return ERR_NONE; } +ReturnCode picopass_write_block(PicopassPacs* pacs, uint8_t blockNo, uint8_t* newBlock) { + rfalPicoPassIdentifyRes idRes; + rfalPicoPassSelectRes selRes; + rfalPicoPassReadCheckRes rcRes; + rfalPicoPassCheckRes chkRes; + + ReturnCode err; + + uint8_t div_key[8] = {0}; + uint8_t mac[4] = {0}; + uint8_t ccnr[12] = {0}; + + err = rfalPicoPassPollerIdentify(&idRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerIdentify error %d", err); + return err; + } + + err = rfalPicoPassPollerSelect(idRes.CSN, &selRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerSelect error %d", err); + return err; + } + + err = rfalPicoPassPollerReadCheck(&rcRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerReadCheck error %d", err); + return err; + } + memcpy(ccnr, rcRes.CCNR, sizeof(rcRes.CCNR)); // last 4 bytes left 0 + + loclass_diversifyKey(selRes.CSN, pacs->key, div_key); + loclass_opt_doReaderMAC(ccnr, div_key, mac); + + err = rfalPicoPassPollerCheck(mac, &chkRes); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerCheck error %d", err); + return err; + } + + FURI_LOG_D(TAG, "rfalPicoPassPollerWriteBlock %d", blockNo); + uint8_t data[9] = { + blockNo, + newBlock[0], + newBlock[1], + newBlock[2], + newBlock[3], + newBlock[4], + newBlock[5], + newBlock[6], + newBlock[7]}; + loclass_doMAC_N(data, sizeof(data), div_key, mac); + FURI_LOG_D( + TAG, + "loclass_doMAC_N %d %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x", + blockNo, + data[1], + data[2], + data[3], + data[4], + data[5], + data[6], + data[7], + data[8], + mac[0], + mac[1], + mac[2], + mac[3]); + + err = rfalPicoPassPollerWriteBlock(data[0], data + 1, mac); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "rfalPicoPassPollerWriteBlock error %d", err); + return err; + } + + return ERR_NONE; +} + int32_t picopass_worker_task(void* context) { PicopassWorker* picopass_worker = context; @@ -414,6 +524,8 @@ int32_t picopass_worker_task(void* context) { picopass_worker_detect(picopass_worker); } else if(picopass_worker->state == PicopassWorkerStateWrite) { picopass_worker_write(picopass_worker); + } else if(picopass_worker->state == PicopassWorkerStateWriteStandardKey) { + picopass_worker_write_standard_key(picopass_worker); } picopass_worker_disable_field(ERR_NONE); @@ -448,7 +560,7 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { } // Thank you proxmark! - pacs->legacy = (memcmp(AA1[5].data, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0); + pacs->legacy = picopass_is_memset(AA1[5].data, 0xFF, 8); pacs->se_enabled = (memcmp(AA1[5].data, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); if(pacs->se_enabled) { FURI_LOG_D(TAG, "SE enabled"); @@ -520,3 +632,46 @@ void picopass_worker_write(PicopassWorker* picopass_worker) { furi_delay_ms(100); } } + +void picopass_worker_write_standard_key(PicopassWorker* picopass_worker) { + PicopassDeviceData* dev_data = picopass_worker->dev_data; + PicopassBlock* AA1 = dev_data->AA1; + PicopassPacs* pacs = &dev_data->pacs; + ReturnCode err; + PicopassWorkerEvent nextState = PicopassWorkerEventSuccess; + + uint8_t* csn = AA1[PICOPASS_CSN_BLOCK_INDEX].data; + uint8_t* configBlock = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data; + uint8_t fuses = configBlock[7]; + uint8_t* oldKey = AA1[PICOPASS_KD_BLOCK_INDEX].data; + + uint8_t newKey[PICOPASS_BLOCK_LEN] = {0}; + loclass_diversifyKey(csn, picopass_iclass_key, newKey); + + if((fuses & 0x80) == 0x80) { + FURI_LOG_D(TAG, "Plain write for personalized mode key change"); + } else { + FURI_LOG_D(TAG, "XOR write for application mode key change"); + // XOR when in application mode + for(size_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { + newKey[i] ^= oldKey[i]; + } + } + + while(picopass_worker->state == PicopassWorkerStateWriteStandardKey) { + if(picopass_detect_card(1000) == ERR_NONE) { + err = picopass_write_block(pacs, PICOPASS_KD_BLOCK_INDEX, newKey); + if(err != ERR_NONE) { + FURI_LOG_E(TAG, "picopass_write_block error %d", err); + nextState = PicopassWorkerEventFail; + } + + // Notify caller and exit + if(picopass_worker->callback) { + picopass_worker->callback(nextState, picopass_worker->context); + } + break; + } + furi_delay_ms(100); + } +} diff --git a/applications/plugins/picopass/picopass_worker.h b/applications/plugins/picopass/picopass_worker.h index 29a890a18..775212c66 100644 --- a/applications/plugins/picopass/picopass_worker.h +++ b/applications/plugins/picopass/picopass_worker.h @@ -12,6 +12,7 @@ typedef enum { // Main worker states PicopassWorkerStateDetect, PicopassWorkerStateWrite, + PicopassWorkerStateWriteStandardKey, // Transition PicopassWorkerStateStop, } PicopassWorkerState; diff --git a/applications/plugins/picopass/picopass_worker_i.h b/applications/plugins/picopass/picopass_worker_i.h index ded40e6c6..cf55fbdf5 100644 --- a/applications/plugins/picopass/picopass_worker_i.h +++ b/applications/plugins/picopass/picopass_worker_i.h @@ -31,3 +31,4 @@ int32_t picopass_worker_task(void* context); void picopass_worker_detect(PicopassWorker* picopass_worker); void picopass_worker_write(PicopassWorker* picopass_worker); +void picopass_worker_write_standard_key(PicopassWorker* picopass_worker); diff --git a/applications/plugins/picopass/scenes/picopass_scene_config.h b/applications/plugins/picopass/scenes/picopass_scene_config.h index 27d6bbcd7..95700787f 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_config.h +++ b/applications/plugins/picopass/scenes/picopass_scene_config.h @@ -11,3 +11,5 @@ ADD_SCENE(picopass, delete, Delete) ADD_SCENE(picopass, delete_success, DeleteSuccess) ADD_SCENE(picopass, write_card, WriteCard) ADD_SCENE(picopass, write_card_success, WriteCardSuccess) +ADD_SCENE(picopass, read_factory_success, ReadFactorySuccess) +ADD_SCENE(picopass, write_key, WriteKey) diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_card.c b/applications/plugins/picopass/scenes/picopass_scene_read_card.c index 8188207a2..90422a2e7 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_read_card.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_card.c @@ -1,6 +1,8 @@ #include "../picopass_i.h" #include +const uint8_t picopass_factory_key_check[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87}; + void picopass_read_card_worker_callback(PicopassWorkerEvent event, void* context) { UNUSED(event); Picopass* picopass = context; @@ -34,7 +36,14 @@ bool picopass_scene_read_card_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == PicopassCustomEventWorkerExit) { - scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); + if(memcmp( + picopass->dev->dev_data.pacs.key, + picopass_factory_key_check, + PICOPASS_BLOCK_LEN) == 0) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadFactorySuccess); + } else { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCardSuccess); + } consumed = true; } } diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c b/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c index bb170ac45..f078d460a 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c +++ b/applications/plugins/picopass/scenes/picopass_scene_read_card_success.c @@ -15,6 +15,7 @@ void picopass_scene_read_card_success_widget_callback( void picopass_scene_read_card_success_on_enter(void* context) { Picopass* picopass = context; + FuriString* csn_str = furi_string_alloc_set("CSN:"); FuriString* credential_str = furi_string_alloc(); FuriString* wiegand_str = furi_string_alloc(); @@ -30,27 +31,31 @@ void picopass_scene_read_card_success_on_enter(void* context) { PicopassPacs* pacs = &picopass->dev->dev_data.pacs; Widget* widget = picopass->widget; - uint8_t csn[PICOPASS_BLOCK_LEN]; - memcpy(csn, &AA1->data[PICOPASS_CSN_BLOCK_INDEX], PICOPASS_BLOCK_LEN); + uint8_t csn[PICOPASS_BLOCK_LEN] = {0}; + memcpy(csn, AA1[PICOPASS_CSN_BLOCK_INDEX].data, PICOPASS_BLOCK_LEN); for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { - furi_string_cat_printf(csn_str, " %02X", csn[i]); + furi_string_cat_printf(csn_str, "%02X ", csn[i]); } - // Neither of these are valid. Indicates the block was all 0x00 or all 0xff - if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) { + bool no_key = picopass_is_memset(pacs->key, 0x00, PICOPASS_BLOCK_LEN); + bool empty = + picopass_is_memset(AA1[PICOPASS_PACS_CFG_BLOCK_INDEX].data, 0xFF, PICOPASS_BLOCK_LEN); + + if(no_key) { furi_string_cat_printf(wiegand_str, "Read Failed"); if(pacs->se_enabled) { furi_string_cat_printf(credential_str, "SE enabled"); } + } else if(empty) { + furi_string_cat_printf(wiegand_str, "Empty"); + } else if(pacs->record.bitLength == 0 || pacs->record.bitLength == 255) { + // Neither of these are valid. Indicates the block was all 0x00 or all 0xff + furi_string_cat_printf(wiegand_str, "Invalid PACS"); - widget_add_button_element( - widget, - GuiButtonTypeLeft, - "Retry", - picopass_scene_read_card_success_widget_callback, - picopass); - + if(pacs->se_enabled) { + furi_string_cat_printf(credential_str, "SE enabled"); + } } else { size_t bytesLength = 1 + pacs->record.bitLength / 8; furi_string_set(credential_str, ""); @@ -69,12 +74,18 @@ void picopass_scene_read_card_success_on_enter(void* context) { furi_string_cat_printf(sio_str, "+SIO"); } - widget_add_button_element( - widget, - GuiButtonTypeLeft, - "Retry", - picopass_scene_read_card_success_widget_callback, - picopass); + if(pacs->key) { + if(pacs->sio) { + furi_string_cat_printf(sio_str, " "); + } + furi_string_cat_printf(sio_str, "Key: "); + + uint8_t key[PICOPASS_BLOCK_LEN]; + memcpy(key, &pacs->key, PICOPASS_BLOCK_LEN); + for(uint8_t i = 0; i < PICOPASS_BLOCK_LEN; i++) { + furi_string_cat_printf(sio_str, "%02X", key[i]); + } + } widget_add_button_element( widget, @@ -84,6 +95,13 @@ void picopass_scene_read_card_success_on_enter(void* context) { picopass); } + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + picopass_scene_read_card_success_widget_callback, + picopass); + widget_add_string_element( widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(csn_str)); widget_add_string_element( diff --git a/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c b/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c new file mode 100644 index 000000000..8e32d21f7 --- /dev/null +++ b/applications/plugins/picopass/scenes/picopass_scene_read_factory_success.c @@ -0,0 +1,78 @@ +#include "../picopass_i.h" +#include + +void picopass_scene_read_factory_success_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + furi_assert(context); + Picopass* picopass = context; + + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(picopass->view_dispatcher, result); + } +} + +void picopass_scene_read_factory_success_on_enter(void* context) { + Picopass* picopass = context; + FuriString* title = furi_string_alloc_set("Factory Default"); + FuriString* subtitle = furi_string_alloc_set(""); + + DOLPHIN_DEED(DolphinDeedNfcReadSuccess); + + // Send notification + notification_message(picopass->notifications, &sequence_success); + + // Setup view + Widget* widget = picopass->widget; + //PicopassPacs* pacs = &picopass->dev->dev_data.pacs; + PicopassBlock* AA1 = picopass->dev->dev_data.AA1; + + uint8_t* configBlock = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data; + uint8_t fuses = configBlock[7]; + + if((fuses & 0x80) == 0x80) { + furi_string_cat_printf(subtitle, "Personalization mode"); + } else { + furi_string_cat_printf(subtitle, "Application mode"); + } + + widget_add_button_element( + widget, + GuiButtonTypeCenter, + "Write Standard iClass Key", + picopass_scene_read_factory_success_widget_callback, + picopass); + + widget_add_string_element( + widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(title)); + widget_add_string_element( + widget, 64, 20, AlignCenter, AlignCenter, FontPrimary, furi_string_get_cstr(subtitle)); + + furi_string_free(title); + furi_string_free(subtitle); + + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); +} + +bool picopass_scene_read_factory_success_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(picopass->scene_manager); + } else if(event.event == GuiButtonTypeCenter) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteKey); + consumed = true; + } + } + return consumed; +} + +void picopass_scene_read_factory_success_on_exit(void* context) { + Picopass* picopass = context; + + // Clear view + widget_reset(picopass->widget); +} diff --git a/applications/plugins/picopass/scenes/picopass_scene_save_name.c b/applications/plugins/picopass/scenes/picopass_scene_save_name.c index 8239002d9..59f33c79a 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_save_name.c +++ b/applications/plugins/picopass/scenes/picopass_scene_save_name.c @@ -21,7 +21,7 @@ void picopass_scene_save_name_on_enter(void* context) { } else { picopass_text_store_set(picopass, picopass->dev->dev_name); } - text_input_set_header_text(text_input, "Name The Card"); + text_input_set_header_text(text_input, "Name the card"); text_input_set_result_callback( text_input, picopass_scene_save_name_text_input_callback, diff --git a/applications/plugins/picopass/scenes/picopass_scene_start.c b/applications/plugins/picopass/scenes/picopass_scene_start.c index 6d1aeedcd..d33a1d264 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_start.c +++ b/applications/plugins/picopass/scenes/picopass_scene_start.c @@ -32,13 +32,18 @@ bool picopass_scene_start_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexRead) { + scene_manager_set_scene_state( + picopass->scene_manager, PicopassSceneStart, SubmenuIndexRead); scene_manager_next_scene(picopass->scene_manager, PicopassSceneReadCard); consumed = true; } else if(event.event == SubmenuIndexSaved) { + // Explicitly save state so that the correct item is + // reselected if the user cancels loading a file. + scene_manager_set_scene_state( + picopass->scene_manager, PicopassSceneStart, SubmenuIndexSaved); scene_manager_next_scene(picopass->scene_manager, PicopassSceneFileSelect); consumed = true; } - scene_manager_set_scene_state(picopass->scene_manager, PicopassSceneStart, event.event); } return consumed; diff --git a/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c b/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c index 108e7d1ce..4bbca816a 100644 --- a/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c +++ b/applications/plugins/picopass/scenes/picopass_scene_write_card_success.c @@ -16,6 +16,7 @@ void picopass_scene_write_card_success_widget_callback( void picopass_scene_write_card_success_on_enter(void* context) { Picopass* picopass = context; Widget* widget = picopass->widget; + FuriString* str = furi_string_alloc_set("Write Success!"); DOLPHIN_DEED(DolphinDeedNfcReadSuccess); @@ -29,6 +30,18 @@ void picopass_scene_write_card_success_on_enter(void* context) { picopass_scene_write_card_success_widget_callback, picopass); + widget_add_button_element( + widget, + GuiButtonTypeRight, + "Menu", + picopass_scene_write_card_success_widget_callback, + picopass); + + widget_add_string_element( + widget, 64, 5, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(str)); + + furi_string_free(str); + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewWidget); } diff --git a/applications/plugins/picopass/scenes/picopass_scene_write_key.c b/applications/plugins/picopass/scenes/picopass_scene_write_key.c new file mode 100644 index 000000000..83d594ca2 --- /dev/null +++ b/applications/plugins/picopass/scenes/picopass_scene_write_key.c @@ -0,0 +1,53 @@ +#include "../picopass_i.h" +#include + +void picopass_write_key_worker_callback(PicopassWorkerEvent event, void* context) { + UNUSED(event); + Picopass* picopass = context; + view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventWorkerExit); +} + +void picopass_scene_write_key_on_enter(void* context) { + Picopass* picopass = context; + DOLPHIN_DEED(DolphinDeedNfcSave); + + // Setup view + Popup* popup = picopass->popup; + popup_set_header(popup, "Writing\niClass\nkey", 68, 30, AlignLeft, AlignTop); + popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61); + + // Start worker + view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup); + picopass_worker_start( + picopass->worker, + PicopassWorkerStateWriteStandardKey, + &picopass->dev->dev_data, + picopass_write_key_worker_callback, + picopass); + + picopass_blink_start(picopass); +} + +bool picopass_scene_write_key_on_event(void* context, SceneManagerEvent event) { + Picopass* picopass = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == PicopassCustomEventWorkerExit) { + scene_manager_next_scene(picopass->scene_manager, PicopassSceneWriteCardSuccess); + consumed = true; + } + } + return consumed; +} + +void picopass_scene_write_key_on_exit(void* context) { + Picopass* picopass = context; + + // Stop worker + picopass_worker_stop(picopass->worker); + // Clear view + popup_reset(picopass->popup); + + picopass_blink_stop(picopass); +} diff --git a/applications/plugins/subbrute b/applications/plugins/subbrute index 819b53293..7cdb9e138 160000 --- a/applications/plugins/subbrute +++ b/applications/plugins/subbrute @@ -1 +1 @@ -Subproject commit 819b532937b8920504cd54385e25389c199285f9 +Subproject commit 7cdb9e1386778ad7351f7e3b3389980afaeafea3 diff --git a/applications/services/applications.h b/applications/services/applications.h index c0672f7da..acbfea312 100644 --- a/applications/services/applications.h +++ b/applications/services/applications.h @@ -14,7 +14,6 @@ typedef struct { const size_t stack_size; const Icon* icon; const FlipperApplicationFlag flags; - const char* link; } FlipperApplication; typedef void (*FlipperOnStartHook)(void); diff --git a/applications/services/bt/bt_service/bt.c b/applications/services/bt/bt_service/bt.c index 964eff28d..ece02bb46 100644 --- a/applications/services/bt/bt_service/bt.c +++ b/applications/services/bt/bt_service/bt.c @@ -463,7 +463,7 @@ int32_t bt_srv(void* p) { Bt* bt = bt_alloc(); if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { - FURI_LOG_W(TAG, "Skipped BT init: device in special startup mode"); + FURI_LOG_W(TAG, "Skipping start in special boot mode"); ble_glue_wait_for_c2_start(FURI_HAL_BT_C2_START_TIMEOUT); furi_record_create(RECORD_BT, bt); return 0; diff --git a/applications/services/cli/cli.c b/applications/services/cli/cli.c index 384d17808..b68505c51 100644 --- a/applications/services/cli/cli.c +++ b/applications/services/cli/cli.c @@ -461,7 +461,7 @@ int32_t cli_srv(void* p) { if(furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) { cli_session_open(cli, &cli_vcp); } else { - FURI_LOG_W(TAG, "Skipped CLI session open: device in special startup mode"); + FURI_LOG_W(TAG, "Skipping start in special boot mode"); } while(1) { diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index f37349b03..75400bd38 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -12,26 +12,48 @@ // Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'` #define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d" -void cli_command_device_info_callback(const char* key, const char* value, bool last, void* context) { - UNUSED(context); +void cli_command_info_callback(const char* key, const char* value, bool last, void* context) { UNUSED(last); + UNUSED(context); printf("%-30s: %s\r\n", key, value); } -/* - * Device Info Command +/** Info Command + * * This command is intended to be used by humans + * + * Arguments: + * - device - print device info + * - power - print power info + * - power_debug - print power debug info + * + * @param cli The cli instance + * @param args The arguments + * @param context The context */ -void cli_command_device_info(Cli* cli, FuriString* args, void* context) { +void cli_command_info(Cli* cli, FuriString* args, void* context) { UNUSED(cli); - UNUSED(args); - furi_hal_info_get(cli_command_device_info_callback, '_', context); + + if(context) { + furi_hal_info_get(cli_command_info_callback, '_', NULL); + return; + } + + if(!furi_string_cmp(args, "device")) { + furi_hal_info_get(cli_command_info_callback, '.', NULL); + } else if(!furi_string_cmp(args, "power")) { + furi_hal_power_info_get(cli_command_info_callback, '.', NULL); + } else if(!furi_string_cmp(args, "power_debug")) { + furi_hal_power_debug_get(cli_command_info_callback, NULL); + } else { + cli_print_usage("info", "", furi_string_get_cstr(args)); + } } void cli_command_help(Cli* cli, FuriString* args, void* context) { UNUSED(args); UNUSED(context); - printf("Commands we have:"); + printf("Commands available:"); // Command count const size_t commands_count = CliCommandTree_size(cli->commands); @@ -61,9 +83,9 @@ void cli_command_help(Cli* cli, FuriString* args, void* context) { if(furi_string_size(args) > 0) { cli_nl(); - printf("Also I have no clue what '"); + printf("`"); printf("%s", furi_string_get_cstr(args)); - printf("' is."); + printf("` command not found"); } } @@ -420,8 +442,9 @@ void cli_command_i2c(Cli* cli, FuriString* args, void* context) { } void cli_commands_init(Cli* cli) { - cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_device_info, NULL); - cli_add_command(cli, "device_info", CliCommandFlagParallelSafe, cli_command_device_info, NULL); + cli_add_command(cli, "!", CliCommandFlagParallelSafe, cli_command_info, (void*)true); + cli_add_command(cli, "info", CliCommandFlagParallelSafe, cli_command_info, NULL); + cli_add_command(cli, "device_info", CliCommandFlagParallelSafe, cli_command_info, (void*)true); cli_add_command(cli, "src", CliCommandFlagParallelSafe, cli_command_src, NULL); cli_add_command(cli, "source", CliCommandFlagParallelSafe, cli_command_src, NULL); diff --git a/applications/services/desktop/animations/animation_manager.c b/applications/services/desktop/animations/animation_manager.c index 2d100b2e1..ade83a3d8 100644 --- a/applications/services/desktop/animations/animation_manager.c +++ b/applications/services/desktop/animations/animation_manager.c @@ -415,7 +415,7 @@ static StorageAnimation* } } - uint32_t lucky_number = furi_hal_random_get() % (whole_weight != 0 ? whole_weight : 1); + uint32_t lucky_number = furi_hal_random_get() % whole_weight; uint32_t weight = 0; StorageAnimation* selected = NULL; diff --git a/applications/services/desktop/animations/animation_manager.h b/applications/services/desktop/animations/animation_manager.h index a3305ec19..d5a6ba384 100644 --- a/applications/services/desktop/animations/animation_manager.h +++ b/applications/services/desktop/animations/animation_manager.h @@ -156,4 +156,4 @@ void animation_manager_unload_and_stall_animation(AnimationManager* animation_ma * * @animation_manager instance */ -void animation_manager_load_and_continue_animation(AnimationManager* animation_manager); \ No newline at end of file +void animation_manager_load_and_continue_animation(AnimationManager* animation_manager); diff --git a/applications/services/desktop/animations/animation_storage.c b/applications/services/desktop/animations/animation_storage.c index f6181caa2..d04871e62 100644 --- a/applications/services/desktop/animations/animation_storage.c +++ b/applications/services/desktop/animations/animation_storage.c @@ -325,7 +325,7 @@ static bool animation_storage_load_frames( FURI_CONST_ASSIGN(icon->width, width); icon->frames = malloc(sizeof(const uint8_t*) * icon->frame_count); - bool frames_ok = true; + bool frames_ok = false; File* file = storage_file_alloc(storage); FileInfo file_info; FuriString* filename; @@ -333,41 +333,34 @@ static bool animation_storage_load_frames( size_t max_filesize = ROUND_UP_TO(width, 8) * height + 2; for(int i = 0; i < icon->frame_count; ++i) { - FURI_CONST_ASSIGN_PTR(icon->frames[i], 0); - if(frames_ok) { - frames_ok = false; - furi_string_printf(filename, "%s/%s/frame_%d.bm", ANIMATION_DIR, name, i); - do { - if(storage_common_stat(storage, furi_string_get_cstr(filename), &file_info) != - FSE_OK) - break; - if(file_info.size > max_filesize) { - FURI_LOG_E( - TAG, - "Filesize %lld, max: %d (width %d, height %d)", - file_info.size, - max_filesize, - width, - height); - break; - } - if(!storage_file_open( - file, furi_string_get_cstr(filename), FSAM_READ, FSOM_OPEN_EXISTING)) { - FURI_LOG_E(TAG, "Can't open file \'%s\'", furi_string_get_cstr(filename)); - break; - } + frames_ok = false; + furi_string_printf(filename, "%s/%s/frame_%d.bm", ANIMATION_DIR, name, i); - FURI_CONST_ASSIGN_PTR(icon->frames[i], malloc(file_info.size)); - if(storage_file_read(file, (void*)icon->frames[i], file_info.size) != - file_info.size) { - FURI_LOG_E(TAG, "Read failed: \'%s\'", furi_string_get_cstr(filename)); - break; - } else { - frames_ok = true; - } - storage_file_close(file); - } while(0); + if(storage_common_stat(storage, furi_string_get_cstr(filename), &file_info) != FSE_OK) + break; + if(file_info.size > max_filesize) { + FURI_LOG_E( + TAG, + "Filesize %lld, max: %d (width %d, height %d)", + file_info.size, + max_filesize, + width, + height); + break; } + if(!storage_file_open( + file, furi_string_get_cstr(filename), FSAM_READ, FSOM_OPEN_EXISTING)) { + FURI_LOG_E(TAG, "Can't open file \'%s\'", furi_string_get_cstr(filename)); + break; + } + + FURI_CONST_ASSIGN_PTR(icon->frames[i], malloc(file_info.size)); + if(storage_file_read(file, (void*)icon->frames[i], file_info.size) != file_info.size) { + FURI_LOG_E(TAG, "Read failed: \'%s\'", furi_string_get_cstr(filename)); + break; + } + storage_file_close(file); + frames_ok = true; } if(!frames_ok) { diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 9ca81f29a..1fe23bb1d 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -17,6 +17,8 @@ #include "helpers/pin_lock.h" #include "helpers/slideshow_filename.h" +#define TAG "Desktop" + static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); @@ -304,43 +306,44 @@ int32_t desktop_srv(void* p) { UNUSED(p); if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { - FURI_LOG_W("Desktop", "Desktop load skipped. Device is in special startup mode."); - } else { - Desktop* desktop = desktop_alloc(); - - bool loaded = DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(!loaded) { - memset(&desktop->settings, 0, sizeof(desktop->settings)); - DESKTOP_SETTINGS_SAVE(&desktop->settings); - } - - scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); - - desktop_pin_lock_init(&desktop->settings); - - if(!desktop_pin_lock_is_locked()) { - if(!loader_is_locked(desktop->loader)) { - desktop_auto_lock_arm(desktop); - } - } else { - desktop_lock(desktop); - } - - if(desktop_check_file_flag(SLIDESHOW_FS_PATH)) { - scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow); - } - - if(!furi_hal_version_do_i_belong_here()) { - scene_manager_next_scene(desktop->scene_manager, DesktopSceneHwMismatch); - } - - if(furi_hal_rtc_get_fault_data()) { - scene_manager_next_scene(desktop->scene_manager, DesktopSceneFault); - } - - view_dispatcher_run(desktop->view_dispatcher); - desktop_free(desktop); + FURI_LOG_W(TAG, "Skipping start in special boot mode"); + return 0; } + Desktop* desktop = desktop_alloc(); + + bool loaded = DESKTOP_SETTINGS_LOAD(&desktop->settings); + if(!loaded) { + memset(&desktop->settings, 0, sizeof(desktop->settings)); + DESKTOP_SETTINGS_SAVE(&desktop->settings); + } + + scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); + + desktop_pin_lock_init(&desktop->settings); + + if(!desktop_pin_lock_is_locked()) { + if(!loader_is_locked(desktop->loader)) { + desktop_auto_lock_arm(desktop); + } + } else { + desktop_lock(desktop); + } + + if(desktop_check_file_flag(SLIDESHOW_FS_PATH)) { + scene_manager_next_scene(desktop->scene_manager, DesktopSceneSlideshow); + } + + if(!furi_hal_version_do_i_belong_here()) { + scene_manager_next_scene(desktop->scene_manager, DesktopSceneHwMismatch); + } + + if(furi_hal_rtc_get_fault_data()) { + scene_manager_next_scene(desktop->scene_manager, DesktopSceneFault); + } + + view_dispatcher_run(desktop->view_dispatcher); + desktop_free(desktop); + return 0; } diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index e61c38dd2..cfca72ff7 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -1,6 +1,6 @@ #include #include -#include "applications/services/applications.h" +#include #include #include diff --git a/applications/services/desktop/views/desktop_view_debug.c b/applications/services/desktop/views/desktop_view_debug.c index abb9d2c26..8c72001b4 100644 --- a/applications/services/desktop/views/desktop_view_debug.c +++ b/applications/services/desktop/views/desktop_view_debug.c @@ -75,7 +75,8 @@ void desktop_debug_render(Canvas* canvas, void* model) { c2_ver ? c2_ver->StackTypeString : ""); canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer); - snprintf(buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), "dev"); + snprintf( + buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), version_get_gitbranch(ver)); canvas_draw_str(canvas, 0, 50 + STATUS_BAR_Y_SHIFT, buffer); } else { diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index 9e02f2bdf..f9530fe84 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -1,13 +1,9 @@ #include #include -#include #include #include "../desktop_i.h" #include "desktop_view_lock_menu.h" -#include "xtreme/settings.h" - -#define LOCK_MENU_ITEMS_NB 5 typedef enum { DesktopLockMenuIndexLock, diff --git a/applications/services/desktop/views/desktop_view_main.c b/applications/services/desktop/views/desktop_view_main.c index f1f4b637a..c1009fde1 100644 --- a/applications/services/desktop/views/desktop_view_main.c +++ b/applications/services/desktop/views/desktop_view_main.c @@ -85,7 +85,6 @@ DesktopMainView* desktop_main_alloc() { DesktopMainView* main_view = malloc(sizeof(DesktopMainView)); main_view->view = view_alloc(); - view_allocate_model(main_view->view, ViewModelTypeLockFree, 1); view_set_context(main_view->view, main_view); view_set_input_callback(main_view->view, desktop_main_input_callback); diff --git a/applications/services/desktop/views/desktop_view_slideshow.c b/applications/services/desktop/views/desktop_view_slideshow.c index 002a16f68..e528d6878 100644 --- a/applications/services/desktop/views/desktop_view_slideshow.c +++ b/applications/services/desktop/views/desktop_view_slideshow.c @@ -61,9 +61,9 @@ static bool desktop_view_slideshow_input(InputEvent* event, void* context) { furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_SHORT); } else if(event->type == InputTypeRelease) { furi_timer_stop(instance->timer); - // if(!slideshow_is_one_page(model->slideshow)) { - // furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG); - // } + /*if(!slideshow_is_one_page(model->slideshow)) { + furi_timer_start(instance->timer, DESKTOP_SLIDESHOW_POWEROFF_LONG); + }*/ } } view_commit_model(instance->view, update_view); diff --git a/applications/services/dolphin/dolphin.c b/applications/services/dolphin/dolphin.c index bd81ff1ab..cf37c5cd9 100644 --- a/applications/services/dolphin/dolphin.c +++ b/applications/services/dolphin/dolphin.c @@ -6,7 +6,6 @@ #include #include #include -#include "furi_hal_random.h" #include #define DOLPHIN_LOCK_EVENT_FLAG (0x1) @@ -23,18 +22,6 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { dolphin_event_send_async(dolphin, &event); } -DolphinDeed getRandomDeed() { - DolphinDeed returnGrp[14] = {1, 5, 8, 10, 12, 15, 17, 20, 21, 25, 26, 28, 29, 32}; - static bool rand_generator_inited = false; - if(!rand_generator_inited) { - srand(furi_get_tick()); - rand_generator_inited = true; - } - uint8_t diceRoll = (rand() % COUNT_OF(returnGrp)); // JUST TO GET IT GOING? AND FIX BUG - diceRoll = (rand() % COUNT_OF(returnGrp)); - return returnGrp[diceRoll]; -} - DolphinStats dolphin_stats(Dolphin* dolphin) { furi_assert(dolphin); @@ -173,6 +160,12 @@ static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin) { int32_t dolphin_srv(void* p) { UNUSED(p); + + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + FURI_LOG_W(TAG, "Skipping start in special boot mode"); + return 0; + } + Dolphin* dolphin = dolphin_alloc(); furi_record_create(RECORD_DOLPHIN, dolphin); diff --git a/applications/services/dolphin/dolphin.h b/applications/services/dolphin/dolphin.h index e8fc12dd3..8757e2a37 100644 --- a/applications/services/dolphin/dolphin.h +++ b/applications/services/dolphin/dolphin.h @@ -44,10 +44,6 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed); */ DolphinStats dolphin_stats(Dolphin* dolphin); -/** GET RANDOM 3PT DEED - */ -DolphinDeed getRandomDeed(); - /** Flush dolphin queue and save state * Thread safe, blocking */ diff --git a/applications/services/dolphin/helpers/dolphin_state.c b/applications/services/dolphin/helpers/dolphin_state.c index 419245a7c..31f9d4030 100644 --- a/applications/services/dolphin/helpers/dolphin_state.c +++ b/applications/services/dolphin/helpers/dolphin_state.c @@ -170,7 +170,7 @@ void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed) { int32_t new_butthurt = ((int32_t)dolphin_state->data.butthurt) - (butthurt_icounter_level_old != butthurt_icounter_level_new); new_butthurt = CLAMP(new_butthurt, BUTTHURT_MAX, BUTTHURT_MIN); - if(new_butthurt >= 7) new_butthurt = BUTTHURT_MIN; // FLIPPER STAYS HAPPY + dolphin_state->data.butthurt = new_butthurt; dolphin_state->data.timestamp = dolphin_state_timestamp(); dolphin_state->dirty = true; diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 47366e2a2..f2a5f359f 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -59,7 +59,7 @@ uint8_t* canvas_get_buffer(Canvas* canvas) { return u8g2_GetBufferPtr(&canvas->fb); } -size_t canvas_get_buffer_size(Canvas* canvas) { +size_t canvas_get_buffer_size(const Canvas* canvas) { furi_assert(canvas); return u8g2_GetBufferTileWidth(&canvas->fb) * u8g2_GetBufferTileHeight(&canvas->fb) * 8; } @@ -77,17 +77,17 @@ void canvas_frame_set( canvas->height = height; } -uint8_t canvas_width(Canvas* canvas) { +uint8_t canvas_width(const Canvas* canvas) { furi_assert(canvas); return canvas->width; } -uint8_t canvas_height(Canvas* canvas) { +uint8_t canvas_height(const Canvas* canvas) { furi_assert(canvas); return canvas->height; } -uint8_t canvas_current_font_height(Canvas* canvas) { +uint8_t canvas_current_font_height(const Canvas* canvas) { furi_assert(canvas); uint8_t font_height = u8g2_GetMaxCharHeight(&canvas->fb); @@ -98,10 +98,10 @@ uint8_t canvas_current_font_height(Canvas* canvas) { return font_height; } -CanvasFontParameters* canvas_get_font_params(Canvas* canvas, Font font) { +const CanvasFontParameters* canvas_get_font_params(const Canvas* canvas, Font font) { furi_assert(canvas); furi_assert(font < FontTotalNumber); - return (CanvasFontParameters*)&canvas_font_params[font]; + return &canvas_font_params[font]; } void canvas_clear(Canvas* canvas) { diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index a372b0ccc..79ad2bcc5 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -86,7 +86,7 @@ void canvas_commit(Canvas* canvas); * * @return width in pixels. */ -uint8_t canvas_width(Canvas* canvas); +uint8_t canvas_width(const Canvas* canvas); /** Get Canvas height * @@ -94,7 +94,7 @@ uint8_t canvas_width(Canvas* canvas); * * @return height in pixels. */ -uint8_t canvas_height(Canvas* canvas); +uint8_t canvas_height(const Canvas* canvas); /** Get current font height * @@ -102,7 +102,7 @@ uint8_t canvas_height(Canvas* canvas); * * @return height in pixels. */ -uint8_t canvas_current_font_height(Canvas* canvas); +uint8_t canvas_current_font_height(const Canvas* canvas); /** Get font parameters * @@ -111,7 +111,7 @@ uint8_t canvas_current_font_height(Canvas* canvas); * * @return pointer to CanvasFontParameters structure */ -CanvasFontParameters* canvas_get_font_params(Canvas* canvas, Font font); +const CanvasFontParameters* canvas_get_font_params(const Canvas* canvas, Font font); /** Clear canvas * diff --git a/applications/services/gui/canvas_i.h b/applications/services/gui/canvas_i.h index 3aa1b1d07..745599c95 100644 --- a/applications/services/gui/canvas_i.h +++ b/applications/services/gui/canvas_i.h @@ -49,7 +49,7 @@ uint8_t* canvas_get_buffer(Canvas* canvas); * * @return size of canvas in bytes */ -size_t canvas_get_buffer_size(Canvas* canvas); +size_t canvas_get_buffer_size(const Canvas* canvas); /** Set drawing region relative to real screen buffer * diff --git a/applications/services/gui/elements.c b/applications/services/gui/elements.c index 3cdc36bd5..90682d68e 100644 --- a/applications/services/gui/elements.c +++ b/applications/services/gui/elements.c @@ -639,7 +639,7 @@ void elements_text_box( bool inverse_present = false; Font current_font = FontSecondary; Font prev_font = FontSecondary; - CanvasFontParameters* font_params = canvas_get_font_params(canvas, current_font); + const CanvasFontParameters* font_params = canvas_get_font_params(canvas, current_font); // Fill line parameters uint8_t line_leading_min = font_params->leading_min; diff --git a/applications/services/gui/gui.c b/applications/services/gui/gui.c index 1c2a5bfc5..835bca2c8 100644 --- a/applications/services/gui/gui.c +++ b/applications/services/gui/gui.c @@ -501,7 +501,7 @@ void gui_remove_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, gui_unlock(gui); } -size_t gui_get_framebuffer_size(Gui* gui) { +size_t gui_get_framebuffer_size(const Gui* gui) { furi_assert(gui); return canvas_get_buffer_size(gui->canvas); } diff --git a/applications/services/gui/gui.h b/applications/services/gui/gui.h index 4e7fc2e4d..d7d73f27b 100644 --- a/applications/services/gui/gui.h +++ b/applications/services/gui/gui.h @@ -94,7 +94,7 @@ void gui_remove_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, * @param gui Gui instance * @return size_t size of frame buffer in bytes */ -size_t gui_get_framebuffer_size(Gui* gui); +size_t gui_get_framebuffer_size(const Gui* gui); /** Set lockdown mode * diff --git a/applications/services/gui/icon_animation.c b/applications/services/gui/icon_animation.c index 48c862208..b63d233f3 100644 --- a/applications/services/gui/icon_animation.c +++ b/applications/services/gui/icon_animation.c @@ -29,7 +29,7 @@ void icon_animation_set_update_callback( instance->callback_context = context; } -const uint8_t* icon_animation_get_data(IconAnimation* instance) { +const uint8_t* icon_animation_get_data(const IconAnimation* instance) { return instance->icon->frames[instance->frame]; } @@ -51,12 +51,12 @@ void icon_animation_timer_callback(void* context) { } } -uint8_t icon_animation_get_width(IconAnimation* instance) { +uint8_t icon_animation_get_width(const IconAnimation* instance) { furi_assert(instance); return instance->icon->width; } -uint8_t icon_animation_get_height(IconAnimation* instance) { +uint8_t icon_animation_get_height(const IconAnimation* instance) { furi_assert(instance); return instance->icon->height; } @@ -83,7 +83,7 @@ void icon_animation_stop(IconAnimation* instance) { } } -bool icon_animation_is_last_frame(IconAnimation* instance) { +bool icon_animation_is_last_frame(const IconAnimation* instance) { furi_assert(instance); return instance->icon->frame_count - instance->frame <= 1; } diff --git a/applications/services/gui/icon_animation.h b/applications/services/gui/icon_animation.h index 684790353..6e58df31d 100644 --- a/applications/services/gui/icon_animation.h +++ b/applications/services/gui/icon_animation.h @@ -55,7 +55,7 @@ void icon_animation_set_update_callback( * * @return width in pixels */ -uint8_t icon_animation_get_width(IconAnimation* instance); +uint8_t icon_animation_get_width(const IconAnimation* instance); /** Get icon animation height * @@ -63,7 +63,7 @@ uint8_t icon_animation_get_width(IconAnimation* instance); * * @return height in pixels */ -uint8_t icon_animation_get_height(IconAnimation* instance); +uint8_t icon_animation_get_height(const IconAnimation* instance); /** Start icon animation * @@ -83,7 +83,7 @@ void icon_animation_stop(IconAnimation* instance); * * @return true if last frame */ -bool icon_animation_is_last_frame(IconAnimation* instance); +bool icon_animation_is_last_frame(const IconAnimation* instance); #ifdef __cplusplus } diff --git a/applications/services/gui/icon_animation_i.h b/applications/services/gui/icon_animation_i.h index 4053a120d..62858d288 100644 --- a/applications/services/gui/icon_animation_i.h +++ b/applications/services/gui/icon_animation_i.h @@ -24,7 +24,7 @@ struct IconAnimation { * * @return pointer to current frame XBM bitmap data */ -const uint8_t* icon_animation_get_data(IconAnimation* instance); +const uint8_t* icon_animation_get_data(const IconAnimation* instance); /** Advance to next frame * diff --git a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c index d8fc11311..5d522c74b 100644 --- a/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c +++ b/applications/services/gui/modules/widget_elements/widget_element_text_scroll.c @@ -74,7 +74,7 @@ static void widget_element_text_scroll_fill_lines(Canvas* canvas, WidgetElement* } // Set canvas font canvas_set_font(canvas, line_tmp.font); - CanvasFontParameters* params = canvas_get_font_params(canvas, line_tmp.font); + const CanvasFontParameters* params = canvas_get_font_params(canvas, line_tmp.font); total_height += params->height; if(total_height > model->height) { model->scroll_pos_total++; @@ -138,7 +138,7 @@ static void widget_element_text_scroll_draw(Canvas* canvas, WidgetElement* eleme TextScrollLineArray_next(it), curr_line++) { if(curr_line < model->scroll_pos_current) continue; TextScrollLineArray* line = TextScrollLineArray_ref(it); - CanvasFontParameters* params = canvas_get_font_params(canvas, line->font); + const CanvasFontParameters* params = canvas_get_font_params(canvas, line->font); if(y + params->descender > model->y + model->height) break; canvas_set_font(canvas, line->font); if(line->horizontal == AlignLeft) { diff --git a/applications/services/gui/scene_manager.c b/applications/services/gui/scene_manager.c index 484d1dbde..4122b3bc3 100644 --- a/applications/services/gui/scene_manager.c +++ b/applications/services/gui/scene_manager.c @@ -34,7 +34,7 @@ void scene_manager_set_scene_state(SceneManager* scene_manager, uint32_t scene_i scene_manager->scene[scene_id].state = state; } -uint32_t scene_manager_get_scene_state(SceneManager* scene_manager, uint32_t scene_id) { +uint32_t scene_manager_get_scene_state(const SceneManager* scene_manager, uint32_t scene_id) { furi_assert(scene_manager); furi_assert(scene_id < scene_manager->scene_handlers->scene_num); @@ -184,7 +184,7 @@ bool scene_manager_search_and_switch_to_previous_scene_one_of( return scene_found; } -bool scene_manager_has_previous_scene(SceneManager* scene_manager, uint32_t scene_id) { +bool scene_manager_has_previous_scene(const SceneManager* scene_manager, uint32_t scene_id) { furi_assert(scene_manager); bool scene_found = false; diff --git a/applications/services/gui/scene_manager.h b/applications/services/gui/scene_manager.h index 5b833e5de..c349a12ce 100644 --- a/applications/services/gui/scene_manager.h +++ b/applications/services/gui/scene_manager.h @@ -63,7 +63,7 @@ void scene_manager_set_scene_state(SceneManager* scene_manager, uint32_t scene_i * * @return Scene state */ -uint32_t scene_manager_get_scene_state(SceneManager* scene_manager, uint32_t scene_id); +uint32_t scene_manager_get_scene_state(const SceneManager* scene_manager, uint32_t scene_id); /** Scene Manager allocation and configuration * @@ -134,7 +134,7 @@ bool scene_manager_previous_scene(SceneManager* scene_manager); * * @return true if previous scene was found, false otherwise */ -bool scene_manager_has_previous_scene(SceneManager* scene_manager, uint32_t scene_id); +bool scene_manager_has_previous_scene(const SceneManager* scene_manager, uint32_t scene_id); /** Search and switch to previous Scene * diff --git a/applications/services/gui/view_port.c b/applications/services/gui/view_port.c index ffd01450b..5760ed577 100644 --- a/applications/services/gui/view_port.c +++ b/applications/services/gui/view_port.c @@ -89,7 +89,7 @@ void view_port_set_width(ViewPort* view_port, uint8_t width) { view_port->width = width; } -uint8_t view_port_get_width(ViewPort* view_port) { +uint8_t view_port_get_width(const ViewPort* view_port) { furi_assert(view_port); return view_port->width; } @@ -99,7 +99,7 @@ void view_port_set_height(ViewPort* view_port, uint8_t height) { view_port->height = height; } -uint8_t view_port_get_height(ViewPort* view_port) { +uint8_t view_port_get_height(const ViewPort* view_port) { furi_assert(view_port); return view_port->height; } @@ -112,7 +112,7 @@ void view_port_enabled_set(ViewPort* view_port, bool enabled) { } } -bool view_port_is_enabled(ViewPort* view_port) { +bool view_port_is_enabled(const ViewPort* view_port) { furi_assert(view_port); return view_port->is_enabled; } diff --git a/applications/services/gui/view_port.h b/applications/services/gui/view_port.h index 703e99248..752fc46ba 100644 --- a/applications/services/gui/view_port.h +++ b/applications/services/gui/view_port.h @@ -56,7 +56,7 @@ void view_port_free(ViewPort* view_port); * @param width wanted width, 0 - auto. */ void view_port_set_width(ViewPort* view_port, uint8_t width); -uint8_t view_port_get_width(ViewPort* view_port); +uint8_t view_port_get_width(const ViewPort* view_port); /** Set view_port height. * @@ -66,7 +66,7 @@ uint8_t view_port_get_width(ViewPort* view_port); * @param height wanted height, 0 - auto. */ void view_port_set_height(ViewPort* view_port, uint8_t height); -uint8_t view_port_get_height(ViewPort* view_port); +uint8_t view_port_get_height(const ViewPort* view_port); /** Enable or disable view_port rendering. * @@ -75,7 +75,7 @@ uint8_t view_port_get_height(ViewPort* view_port); * @warning automatically dispatches update event */ void view_port_enabled_set(ViewPort* view_port, bool enabled); -bool view_port_is_enabled(ViewPort* view_port); +bool view_port_is_enabled(const ViewPort* view_port); /** ViewPort event callbacks * diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index f2edf0a33..caaf9f11b 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -2,7 +2,6 @@ #include #include "loader/loader.h" #include "loader_i.h" -#include "applications/services/desktop/desktop_i.h" #define TAG "LoaderSrv" @@ -48,18 +47,13 @@ static void loader_menu_callback(void* _ctx, uint32_t index) { furi_assert(application->app); furi_assert(application->name); - furi_assert(application->link); - if(strcmp(application->link, "NULL") != 0) { - loader_start(NULL, "Applications", application->link); - } else { - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; - } - - loader_start_application(application, NULL); + if(!loader_lock(loader_instance)) { + FURI_LOG_E(TAG, "Loader is locked"); + return; } + + loader_start_application(application, NULL); } static void loader_submenu_callback(void* context, uint32_t index) { @@ -162,12 +156,7 @@ static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { UNUSED(instance); printf("Applications:\r\n"); for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - if(strcmp(FLIPPER_APPS[i].link, "NULL") != 0) { - printf( - "\tFor %s, Use: Applications %s\r\n", FLIPPER_APPS[i].name, FLIPPER_APPS[i].link); - } else { - printf("\t%s\r\n", FLIPPER_APPS[i].name); - } + printf("\t%s\r\n", FLIPPER_APPS[i].name); } printf("Plugins:\r\n"); @@ -175,7 +164,7 @@ static void loader_cli_list(Cli* cli, FuriString* args, Loader* instance) { printf("\t%s\r\n", FLIPPER_PLUGINS[i].name); } - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && FLIPPER_DEBUG_APPS_COUNT != 0) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { printf("Debug:\r\n"); for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { printf("\t%s\r\n", FLIPPER_DEBUG_APPS[i].name); @@ -273,7 +262,7 @@ void loader_unlock(Loader* instance) { FURI_CRITICAL_EXIT(); } -bool loader_is_locked(Loader* instance) { +bool loader_is_locked(const Loader* instance) { return instance->lock_count > 0; } @@ -429,7 +418,7 @@ static void loader_build_menu() { loader_submenu_callback, (void*)LoaderMenuViewPlugins); } - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && FLIPPER_DEBUG_APPS_COUNT != 0) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && (FLIPPER_DEBUG_APPS_COUNT > 0)) { menu_add_item( loader_instance->primary_menu, "Debug Tools", @@ -448,9 +437,8 @@ static void loader_build_menu() { } static void loader_build_submenu() { - size_t i; - FURI_LOG_I(TAG, "Building plugins menu"); + size_t i; for(i = 0; i < FLIPPER_PLUGINS_COUNT; i++) { submenu_add_item( loader_instance->plugins_menu, @@ -531,4 +519,4 @@ int32_t loader_srv(void* p) { FuriPubSub* loader_get_pubsub(Loader* instance) { return instance->pubsub; -} \ No newline at end of file +} diff --git a/applications/services/loader/loader.h b/applications/services/loader/loader.h index 954e79c57..8dbc4fc35 100644 --- a/applications/services/loader/loader.h +++ b/applications/services/loader/loader.h @@ -43,7 +43,7 @@ bool loader_lock(Loader* instance); void loader_unlock(Loader* instance); /** Get loader lock status */ -bool loader_is_locked(Loader* instance); +bool loader_is_locked(const Loader* instance); /** Show primary loader */ void loader_show_menu(); diff --git a/applications/services/locale/locale.h b/applications/services/locale/locale.h index 5f2a4d87f..61fb4c605 100644 --- a/applications/services/locale/locale.h +++ b/applications/services/locale/locale.h @@ -81,7 +81,7 @@ void locale_format_time( * * @return The Locale DateFormat. */ -LocaleDateFormat locale_get_date_format(); +LocaleDateFormat locale_get_date_format(void); /** Set Locale DateFormat * diff --git a/applications/services/power/power_cli.c b/applications/services/power/power_cli.c index f4a10f0a9..021ce3553 100644 --- a/applications/services/power/power_cli.c +++ b/applications/services/power/power_cli.c @@ -26,24 +26,6 @@ void power_cli_reboot2dfu(Cli* cli, FuriString* args) { power_reboot(PowerBootModeDfu); } -static void power_cli_callback(const char* key, const char* value, bool last, void* context) { - UNUSED(last); - UNUSED(context); - printf("%-24s: %s\r\n", key, value); -} - -void power_cli_info(Cli* cli, FuriString* args) { - UNUSED(cli); - UNUSED(args); - furi_hal_power_info_get(power_cli_callback, '_', NULL); -} - -void power_cli_debug(Cli* cli, FuriString* args) { - UNUSED(cli); - UNUSED(args); - furi_hal_power_debug_get(power_cli_callback, NULL); -} - void power_cli_5v(Cli* cli, FuriString* args) { UNUSED(cli); if(!furi_string_cmp(args, "0")) { @@ -74,8 +56,6 @@ static void power_cli_command_print_usage() { printf("\toff\t - shutdown power\r\n"); printf("\treboot\t - reboot\r\n"); printf("\treboot2dfu\t - reboot to dfu bootloader\r\n"); - printf("\tinfo\t - show power info\r\n"); - printf("\tdebug\t - show debug information\r\n"); printf("\t5v <0 or 1>\t - enable or disable 5v ext\r\n"); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { printf("\t3v3 <0 or 1>\t - enable or disable 3v3 ext\r\n"); @@ -108,16 +88,6 @@ void power_cli(Cli* cli, FuriString* args, void* context) { break; } - if(furi_string_cmp_str(cmd, "info") == 0) { - power_cli_info(cli, args); - break; - } - - if(furi_string_cmp_str(cmd, "debug") == 0) { - power_cli_debug(cli, args); - break; - } - if(furi_string_cmp_str(cmd, "5v") == 0) { power_cli_5v(cli, args); break; diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index 62bb3c85a..7c1b9be58 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -5,6 +5,7 @@ #include "xtreme/settings.h" #define POWER_OFF_TIMEOUT 90 +#define TAG "Power" void power_draw_battery_callback(Canvas* canvas, void* context) { furi_assert(context); @@ -73,7 +74,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { } else if( (battery_icon == BatteryIconBarPercent) && (power->state != PowerStateCharging) && // Default bar display with percentage - (power->info.voltage_battery_charging >= + (power->info.voltage_battery_charge_limit >= 4.2)) { // not looking nice with low voltage indicator canvas_set_font(canvas, FontBatteryPercent); @@ -117,7 +118,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_set_color(canvas, ColorBlack); canvas_draw_str_aligned( canvas, 15, 4, AlignCenter, AlignCenter, batteryPercentileSecondDigit); - } else { // charge >= 62, both digits are white + } else { // charge >= 74, both digits are white canvas_set_color(canvas, ColorWhite); canvas_draw_str_aligned( canvas, 11, 4, AlignCenter, AlignCenter, batteryPercentile); @@ -128,7 +129,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { } // TODO: Verify if it displays correctly with custom battery skins !!! - if(power->info.voltage_battery_charging < 4.2) { + if(power->info.voltage_battery_charge_limit < 4.2) { // Battery charging voltage is modified, indicate with cross pattern canvas_invert_color(canvas); uint8_t battery_bar_width = (power->info.charge + 4) / 5; @@ -442,7 +443,7 @@ static bool power_update_info(Power* power) { info.capacity_full = furi_hal_power_get_battery_full_capacity(); info.current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger); info.current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge); - info.voltage_battery_charging = furi_hal_power_get_battery_charging_voltage(); + info.voltage_battery_charge_limit = furi_hal_power_get_battery_charge_voltage_limit(); info.voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger); info.voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge); info.voltage_vbus = furi_hal_power_get_usb_voltage(); @@ -513,6 +514,12 @@ static void power_check_battery_level_change(Power* power) { int32_t power_srv(void* p) { UNUSED(p); + + if(furi_hal_rtc_get_boot_mode() != FuriHalRtcBootModeNormal) { + FURI_LOG_W(TAG, "Skipping start in special boot mode"); + return 0; + } + Power* power = power_alloc(); if(!LOAD_POWER_SETTINGS(&power->shutdown_idle_delay_ms)) { power->shutdown_idle_delay_ms = 0; diff --git a/applications/services/power/power_service/power.h b/applications/services/power/power_service/power.h index 1752643d1..cb2fc8fad 100644 --- a/applications/services/power/power_service/power.h +++ b/applications/services/power/power_service/power.h @@ -52,7 +52,7 @@ typedef struct { float current_charger; float current_gauge; - float voltage_battery_charging; + float voltage_battery_charge_limit; float voltage_charger; float voltage_gauge; float voltage_vbus; diff --git a/applications/services/storage/storage_cli.c b/applications/services/storage/storage_cli.c index eeaa7fce8..ff2055697 100644 --- a/applications/services/storage/storage_cli.c +++ b/applications/services/storage/storage_cli.c @@ -1,6 +1,5 @@ #include #include -#include #include #include @@ -61,28 +60,26 @@ static void storage_cli_info(Cli* cli, FuriString* path) { } } else if(furi_string_cmp_str(path, STORAGE_EXT_PATH_PREFIX) == 0) { SDInfo sd_info; - SD_CID sd_cid; FS_Error error = storage_sd_info(api, &sd_info); - BSP_SD_GetCIDRegister(&sd_cid); if(error != FSE_OK) { storage_cli_print_error(error); } else { printf( "Label: %s\r\nType: %s\r\n%luKiB total\r\n%luKiB free\r\n" - "%02x%2.2s %5.5s %i.%i\r\nSN:%04lx %02i/%i\r\n", + "%02x%s %s v%i.%i\r\nSN:%04lx %02i/%i\r\n", sd_info.label, sd_api_get_fs_type_text(sd_info.fs_type), sd_info.kb_total, sd_info.kb_free, - sd_cid.ManufacturerID, - sd_cid.OEM_AppliID, - sd_cid.ProdName, - sd_cid.ProdRev >> 4, - sd_cid.ProdRev & 0xf, - sd_cid.ProdSN, - sd_cid.ManufactMonth, - sd_cid.ManufactYear + 2000); + sd_info.manufacturer_id, + sd_info.oem_id, + sd_info.product_name, + sd_info.product_revision_major, + sd_info.product_revision_minor, + sd_info.product_serial_number, + sd_info.manufacturing_month, + sd_info.manufacturing_year); } } else { storage_cli_print_usage(); diff --git a/applications/services/storage/storage_external_api.c b/applications/services/storage/storage_external_api.c index 6929a9cbd..c5dfd533e 100644 --- a/applications/services/storage/storage_external_api.c +++ b/applications/services/storage/storage_external_api.c @@ -12,9 +12,7 @@ #define TAG "StorageAPI" -#define S_API_PROLOGUE \ - FuriSemaphore* semaphore = furi_semaphore_alloc(1, 0); \ - furi_check(semaphore != NULL); +#define S_API_PROLOGUE FuriApiLock lock = api_lock_alloc_locked(); #define S_FILE_API_PROLOGUE \ Storage* storage = file->storage; \ @@ -24,13 +22,12 @@ furi_check( \ furi_message_queue_put(storage->message_queue, &message, FuriWaitForever) == \ FuriStatusOk); \ - furi_semaphore_acquire(semaphore, FuriWaitForever); \ - furi_semaphore_free(semaphore); + api_lock_wait_unlock_and_free(lock) #define S_API_MESSAGE(_command) \ SAReturn return_data; \ StorageMessage message = { \ - .semaphore = semaphore, \ + .lock = lock, \ .command = _command, \ .data = &data, \ .return_data = &return_data, \ diff --git a/applications/services/storage/storage_glue.c b/applications/services/storage/storage_glue.c index 22f2e3dfa..cccf4046a 100644 --- a/applications/services/storage/storage_glue.c +++ b/applications/services/storage/storage_glue.c @@ -31,29 +31,13 @@ void storage_file_clear(StorageFile* obj) { /****************** storage data ******************/ void storage_data_init(StorageData* storage) { - storage->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - furi_check(storage->mutex != NULL); storage->data = NULL; storage->status = StorageStatusNotReady; StorageFileList_init(storage->files); } -bool storage_data_lock(StorageData* storage) { - return (furi_mutex_acquire(storage->mutex, FuriWaitForever) == FuriStatusOk); -} - -bool storage_data_unlock(StorageData* storage) { - return (furi_mutex_release(storage->mutex) == FuriStatusOk); -} - StorageStatus storage_data_status(StorageData* storage) { - StorageStatus status; - - storage_data_lock(storage); - status = storage->status; - storage_data_unlock(storage); - - return status; + return storage->status; } const char* storage_data_status_text(StorageData* storage) { diff --git a/applications/services/storage/storage_glue.h b/applications/services/storage/storage_glue.h index 6fdc70099..501c26abc 100644 --- a/applications/services/storage/storage_glue.h +++ b/applications/services/storage/storage_glue.h @@ -38,8 +38,6 @@ void storage_file_set(StorageFile* obj, const StorageFile* src); void storage_file_clear(StorageFile* obj); void storage_data_init(StorageData* storage); -bool storage_data_lock(StorageData* storage); -bool storage_data_unlock(StorageData* storage); StorageStatus storage_data_status(StorageData* storage); const char* storage_data_status_text(StorageData* storage); void storage_data_timestamp(StorageData* storage); @@ -57,7 +55,6 @@ struct StorageData { const FS_Api* fs_api; StorageApi api; void* data; - FuriMutex* mutex; StorageStatus status; StorageFileList_t files; uint32_t timestamp; diff --git a/applications/services/storage/storage_message.h b/applications/services/storage/storage_message.h index 987268017..3edb1018e 100644 --- a/applications/services/storage/storage_message.h +++ b/applications/services/storage/storage_message.h @@ -1,5 +1,6 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { @@ -130,7 +131,7 @@ typedef enum { } StorageCommand; typedef struct { - FuriSemaphore* semaphore; + FuriApiLock lock; StorageCommand command; SAData* data; SAReturn* return_data; diff --git a/applications/services/storage/storage_processing.c b/applications/services/storage/storage_processing.c index 795a5d11c..b1ea5d29b 100644 --- a/applications/services/storage/storage_processing.c +++ b/applications/services/storage/storage_processing.c @@ -2,15 +2,7 @@ #include #include -#define FS_CALL(_storage, _fn) \ - storage_data_lock(_storage); \ - ret = _storage->fs_api->_fn; \ - storage_data_unlock(_storage); - -#define ST_CALL(_storage, _fn) \ - storage_data_lock(_storage); \ - ret = _storage->api._fn; \ - storage_data_unlock(_storage); +#define FS_CALL(_storage, _fn) ret = _storage->fs_api->_fn; static StorageData* storage_get_storage_by_type(Storage* app, StorageType type) { furi_check(type == ST_EXT || type == ST_INT); @@ -44,16 +36,11 @@ static const char* remove_vfs(const char* path) { static StorageType storage_get_type_by_path(Storage* app, const char* path) { StorageType type = ST_ERROR; - if(strlen(path) >= strlen(STORAGE_EXT_PATH_PREFIX) && - memcmp(path, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) { + if(memcmp(path, STORAGE_EXT_PATH_PREFIX, strlen(STORAGE_EXT_PATH_PREFIX)) == 0) { type = ST_EXT; - } else if( - strlen(path) >= strlen(STORAGE_INT_PATH_PREFIX) && - memcmp(path, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) { + } else if(memcmp(path, STORAGE_INT_PATH_PREFIX, strlen(STORAGE_INT_PATH_PREFIX)) == 0) { type = ST_INT; - } else if( - strlen(path) >= strlen(STORAGE_ANY_PATH_PREFIX) && - memcmp(path, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) { + } else if(memcmp(path, STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == 0) { type = ST_ANY; } @@ -68,21 +55,15 @@ static StorageType storage_get_type_by_path(Storage* app, const char* path) { } static void storage_path_change_to_real_storage(FuriString* path, StorageType real_storage) { - if(memcmp( - furi_string_get_cstr(path), STORAGE_ANY_PATH_PREFIX, strlen(STORAGE_ANY_PATH_PREFIX)) == - 0) { + if(furi_string_search(path, STORAGE_ANY_PATH_PREFIX) == 0) { switch(real_storage) { case ST_EXT: - furi_string_set_char(path, 0, STORAGE_EXT_PATH_PREFIX[0]); - furi_string_set_char(path, 1, STORAGE_EXT_PATH_PREFIX[1]); - furi_string_set_char(path, 2, STORAGE_EXT_PATH_PREFIX[2]); - furi_string_set_char(path, 3, STORAGE_EXT_PATH_PREFIX[3]); + furi_string_replace_at( + path, 0, strlen(STORAGE_EXT_PATH_PREFIX), STORAGE_EXT_PATH_PREFIX); break; case ST_INT: - furi_string_set_char(path, 0, STORAGE_INT_PATH_PREFIX[0]); - furi_string_set_char(path, 1, STORAGE_INT_PATH_PREFIX[1]); - furi_string_set_char(path, 2, STORAGE_INT_PATH_PREFIX[2]); - furi_string_set_char(path, 3, STORAGE_INT_PATH_PREFIX[3]); + furi_string_replace_at( + path, 0, strlen(STORAGE_INT_PATH_PREFIX), STORAGE_INT_PATH_PREFIX); break; default: break; @@ -604,7 +585,7 @@ void storage_process_message_internal(Storage* app, StorageMessage* message) { break; } - furi_semaphore_release(message->semaphore); + api_lock_unlock(message->lock); } void storage_process_message(Storage* app, StorageMessage* message) { diff --git a/applications/services/storage/storage_sd_api.h b/applications/services/storage/storage_sd_api.h index f83360955..880640394 100644 --- a/applications/services/storage/storage_sd_api.h +++ b/applications/services/storage/storage_sd_api.h @@ -23,6 +23,16 @@ typedef struct { uint16_t cluster_size; uint16_t sector_size; char label[SD_LABEL_LENGTH]; + + uint8_t manufacturer_id; + char oem_id[3]; + char product_name[6]; + uint8_t product_revision_major; + uint8_t product_revision_minor; + uint32_t product_serial_number; + uint8_t manufacturing_month; + uint16_t manufacturing_year; + FS_Error error; } SDInfo; diff --git a/applications/services/storage/storages/storage_ext.c b/applications/services/storage/storages/storage_ext.c index 0c81a0006..530c88f85 100644 --- a/applications/services/storage/storages/storage_ext.c +++ b/applications/services/storage/storages/storage_ext.c @@ -26,12 +26,10 @@ static FS_Error storage_ext_parse_error(SDError error); static bool sd_mount_card(StorageData* storage, bool notify) { bool result = false; - uint8_t counter = BSP_SD_MaxMountRetryCount(); + uint8_t counter = sd_max_mount_retry_count(); uint8_t bsp_result; SDData* sd_data = storage->data; - storage_data_lock(storage); - while(result == false && counter > 0 && hal_sd_detect()) { if(notify) { NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); @@ -41,9 +39,9 @@ static bool sd_mount_card(StorageData* storage, bool notify) { if((counter % 2) == 0) { // power reset sd card - bsp_result = BSP_SD_Init(true); + bsp_result = sd_init(true); } else { - bsp_result = BSP_SD_Init(false); + bsp_result = sd_init(false); } if(bsp_result) { @@ -91,7 +89,6 @@ static bool sd_mount_card(StorageData* storage, bool notify) { } storage_data_timestamp(storage); - storage_data_unlock(storage); return result; } @@ -100,14 +97,12 @@ FS_Error sd_unmount_card(StorageData* storage) { SDData* sd_data = storage->data; SDError error; - storage_data_lock(storage); storage->status = StorageStatusNotReady; error = FR_DISK_ERR; // TODO do i need to close the files? - f_mount(0, sd_data->path, 0); - storage_data_unlock(storage); + return storage_ext_parse_error(error); } @@ -120,8 +115,6 @@ FS_Error sd_format_card(StorageData* storage) { SDData* sd_data = storage->data; SDError error; - storage_data_lock(storage); - work_area = malloc(_MAX_SS); error = f_mkfs(sd_data->path, FM_ANY, 0, work_area, _MAX_SS); free(work_area); @@ -138,8 +131,6 @@ FS_Error sd_format_card(StorageData* storage) { storage->status = StorageStatusOK; } while(false); - storage_data_unlock(storage); - return storage_ext_parse_error(error); #endif } @@ -156,14 +147,12 @@ FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info) { memset(sd_info, 0, sizeof(SDInfo)); // get fs info - storage_data_lock(storage); error = f_getlabel(sd_data->path, sd_info->label, NULL); if(error == FR_OK) { #ifndef FURI_RAM_EXEC error = f_getfree(sd_data->path, &free_clusters, &fs); #endif } - storage_data_unlock(storage); if(error == FR_OK) { // calculate size @@ -210,6 +199,20 @@ FS_Error sd_card_info(StorageData* storage, SDInfo* sd_info) { #endif } + SD_CID cid; + SdSpiStatus status = sd_get_cid(&cid); + + if(status == SdSpiStatusOK) { + sd_info->manufacturer_id = cid.ManufacturerID; + memcpy(sd_info->oem_id, cid.OEM_AppliID, sizeof(cid.OEM_AppliID)); + memcpy(sd_info->product_name, cid.ProdName, sizeof(cid.ProdName)); + sd_info->product_revision_major = cid.ProdRev >> 4; + sd_info->product_revision_minor = cid.ProdRev & 0x0F; + sd_info->product_serial_number = cid.ProdSN; + sd_info->manufacturing_year = 2000 + cid.ManufactYear; + sd_info->manufacturing_month = cid.ManufactMonth; + } + return storage_ext_parse_error(error); } diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index 518c3ff14..e0fa8204e 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -3,18 +3,13 @@ #include #include #include -#include #include #include #include #include -#include int screen_index; -#define LOW_CHARGE_THRESHOLD 10 -#define HIGH_DRAIN_CURRENT_THRESHOLD 100 - typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message); static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* message) { @@ -170,6 +165,13 @@ static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* return result; } +#include +#include +#include + +#define LOW_CHARGE_THRESHOLD 10 +#define HIGH_DRAIN_CURRENT_THRESHOLD 100 + static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) { canvas_draw_frame(canvas, x - 7, y + 7, 30, 13); canvas_draw_icon(canvas, x, y, icon); @@ -221,15 +223,15 @@ static void draw_battery(Canvas* canvas, PowerInfo* info, int x, int y) { drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); } else if(drain_current != 0) { snprintf(header, 20, "..."); - } else if(info->voltage_battery_charging < 4.2) { + } else if(info->voltage_battery_charge_limit < 4.2) { // Non-default battery charging limit, mention it snprintf(header, sizeof(header), "Limited to"); snprintf( value, sizeof(value), "%lu.%luV", - (uint32_t)(info->voltage_battery_charging), - (uint32_t)(info->voltage_battery_charging * 10) % 10); + (uint32_t)(info->voltage_battery_charge_limit), + (uint32_t)(info->voltage_battery_charge_limit * 10) % 10); } else { snprintf(header, sizeof(header), "Charged!"); } @@ -258,7 +260,15 @@ static void battery_info_draw_callback(Canvas* canvas, void* context) { char health[10]; snprintf(batt_level, sizeof(batt_level), "%lu%%", (uint32_t)info->charge); - snprintf(temperature, sizeof(temperature), "%lu C", (uint32_t)info->temperature_gauge); + if(locale_get_measurement_unit() == LocaleMeasurementUnitsMetric) { + snprintf(temperature, sizeof(temperature), "%lu C", (uint32_t)info->temperature_gauge); + } else { + snprintf( + temperature, + sizeof(temperature), + "%lu F", + (uint32_t)locale_celsius_to_fahrenheit(info->temperature_gauge)); + } snprintf( voltage, sizeof(voltage), diff --git a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c index 59071959c..c9e4b17d4 100644 --- a/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c +++ b/applications/settings/bt_settings_app/scenes/bt_settings_scene_forget_dev_success.c @@ -1,5 +1,4 @@ #include "../bt_settings_app.h" -#include "furi_hal_bt.h" #include "xtreme/assets.h" #include diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c index db9a1a01f..fdd257c18 100644 --- a/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c @@ -20,20 +20,52 @@ static const NotificationSequence sequence_note_c = { NULL, }; -#define BACKLIGHT_COUNT 5 +#define BACKLIGHT_COUNT 21 const char* const backlight_text[BACKLIGHT_COUNT] = { "0%", + "5%", + "10%", + "15%", + "20%", "25%", + "30%", + "35%", + "40%", + "45%", "50%", + "55%", + "60%", + "65%", + "70%", "75%", + "80%", + "85%", + "90%", + "95%", "100%", }; const float backlight_value[BACKLIGHT_COUNT] = { - 0.0f, + 0.00f, + 0.05f, + 0.10f, + 0.15f, + 0.20f, 0.25f, - 0.5f, + 0.30f, + 0.35f, + 0.40f, + 0.45f, + 0.50f, + 0.55f, + 0.60f, + 0.65f, + 0.70f, 0.75f, - 1.0f, + 0.80f, + 0.85f, + 0.90f, + 0.95f, + 1.00f, }; #define VOLUME_COUNT 5 diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c b/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c index 2b70662c8..e0186a5a6 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c @@ -7,7 +7,7 @@ static void power_settings_scene_battery_info_update_model(PowerSettingsApp* app .gauge_voltage = app->info.voltage_gauge, .gauge_current = app->info.current_gauge, .gauge_temperature = app->info.temperature_gauge, - .charging_voltage = app->info.voltage_battery_charging, + .charge_voltage_limit = app->info.voltage_battery_charge_limit, .charge = app->info.charge, .health = app->info.health, }; diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index d29769d21..7394fd3c5 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -69,7 +69,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { drain_current > HIGH_DRAIN_CURRENT_THRESHOLD ? "mA!" : "mA"); } else if(drain_current != 0) { snprintf(header, 20, "..."); - } else if(data->charging_voltage < 4.2) { + } else if(data->charge_voltage_limit < 4.2) { // Non-default battery charging limit, mention it snprintf(emote, sizeof(emote), "Charged!"); snprintf(header, sizeof(header), "Limited to"); @@ -77,8 +77,8 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { value, sizeof(value), "%lu.%luV", - (uint32_t)(data->charging_voltage), - (uint32_t)(data->charging_voltage * 10) % 10); + (uint32_t)(data->charge_voltage_limit), + (uint32_t)(data->charge_voltage_limit * 10) % 10); } else { snprintf(header, sizeof(header), "Charged!"); } diff --git a/applications/settings/power_settings_app/views/battery_info.h b/applications/settings/power_settings_app/views/battery_info.h index 7bfacf69e..e52d1844c 100644 --- a/applications/settings/power_settings_app/views/battery_info.h +++ b/applications/settings/power_settings_app/views/battery_info.h @@ -9,7 +9,7 @@ typedef struct { float gauge_voltage; float gauge_current; float gauge_temperature; - float charging_voltage; + float charge_voltage_limit; uint8_t charge; uint8_t health; } BatteryInfoModel; diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c index 4901e960e..a3327aada 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_sd_info.c @@ -1,5 +1,4 @@ #include "../storage_settings.h" -#include static void storage_settings_scene_sd_info_dialog_callback(DialogExResult result, void* context) { StorageSettings* app = context; @@ -12,9 +11,7 @@ void storage_settings_scene_sd_info_on_enter(void* context) { DialogEx* dialog_ex = app->dialog_ex; SDInfo sd_info; - SD_CID sd_cid; FS_Error sd_status = storage_sd_info(app->fs_api, &sd_info); - BSP_SD_GetCIDRegister(&sd_cid); scene_manager_set_scene_state(app->scene_manager, StorageSettingsSDInfo, sd_status); @@ -28,52 +25,38 @@ void storage_settings_scene_sd_info_on_enter(void* context) { dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop); dialog_ex_set_center_button_text(dialog_ex, "Ok"); } else { - char unit_kb[] = "KB"; - char unit_mb[] = "MB"; - char unit_gb[] = "GB"; - - double sd_total_val = (double)sd_info.kb_total; - char* sd_total_unit = unit_kb; - double sd_free_val = (double)sd_info.kb_free; - char* sd_free_unit = unit_kb; - - if(sd_total_val > 1024) { - sd_total_val /= 1024; - sd_total_unit = unit_mb; + double total_v = (double)sd_info.kb_total; + double free_v = (double)sd_info.kb_free; + char* units[] = {"KiB", "MiB", "GiB", "TiB"}; + uint total_i, free_i; + for(total_i = 0; total_i < COUNT_OF(units); total_i++) { + if(total_v < 1024) break; + total_v /= 1024; } - if(sd_total_val > 1024) { - sd_total_val /= 1024; - sd_total_unit = unit_gb; - } - - if(sd_free_val > 1024) { - sd_free_val /= 1024; - sd_free_unit = unit_mb; - } - if(sd_free_val > 1024) { - sd_free_val /= 1024; - sd_free_unit = unit_gb; + for(free_i = 0; free_i < COUNT_OF(units); free_i++) { + if(free_v < 1024) break; + free_v /= 1024; } furi_string_printf( app->text_string, "Label: %s\nType: %s\n%.2f %s total\n%.2f %s free %.2f%% free\n" - "%02X%2.2s %5.5s %i.%i\nSN:%04lX %02i/%i", + "%02X%s %s v%i.%i\nSN:%04lX %02i/%i", sd_info.label, sd_api_get_fs_type_text(sd_info.fs_type), - sd_total_val, - sd_total_unit, - sd_free_val, - sd_free_unit, + total_v, + units[total_i], + free_v, + units[free_i], (double)(((int)sd_info.kb_free * 100.0) / (int)sd_info.kb_total), - sd_cid.ManufacturerID, - sd_cid.OEM_AppliID, - sd_cid.ProdName, - sd_cid.ProdRev >> 4, - sd_cid.ProdRev & 0xf, - sd_cid.ProdSN, - sd_cid.ManufactMonth, - sd_cid.ManufactYear + 2000); + sd_info.manufacturer_id, + sd_info.oem_id, + sd_info.product_name, + sd_info.product_revision_major, + sd_info.product_revision_minor, + sd_info.product_serial_number, + sd_info.manufacturing_month, + sd_info.manufacturing_year); dialog_ex_set_text( dialog_ex, furi_string_get_cstr(app->text_string), 4, 1, AlignLeft, AlignTop); } @@ -112,4 +95,4 @@ void storage_settings_scene_sd_info_on_exit(void* context) { dialog_ex_reset(dialog_ex); furi_string_reset(app->text_string); -} \ No newline at end of file +} diff --git a/applications/system/updater/util/update_task_worker_backup.c b/applications/system/updater/util/update_task_worker_backup.c index ed53c353b..f2c33c2ed 100644 --- a/applications/system/updater/util/update_task_worker_backup.c +++ b/applications/system/updater/util/update_task_worker_backup.c @@ -97,7 +97,16 @@ static void update_task_cleanup_resources(UpdateTask* update_task, const uint32_ path_concat( STORAGE_EXT_PATH_PREFIX, furi_string_get_cstr(entry_ptr->name), file_path); FURI_LOG_D(TAG, "Removing %s", furi_string_get_cstr(file_path)); - storage_simply_remove(update_task->storage, furi_string_get_cstr(file_path)); + + FS_Error result = + storage_common_remove(update_task->storage, furi_string_get_cstr(file_path)); + if(result != FSE_OK && result != FSE_EXIST) { + FURI_LOG_E( + TAG, + "%s remove failed, cause %s", + furi_string_get_cstr(file_path), + storage_error_get_desc(result)); + } furi_string_free(file_path); } else if(entry_ptr->type == ResourceManifestEntryTypeDirectory) { n_dir_entries++; @@ -116,7 +125,6 @@ static void update_task_cleanup_resources(UpdateTask* update_task, const uint32_ n_dir_entries); FuriString* folder_path = furi_string_alloc(); - File* folder_file = storage_file_alloc(update_task->storage); do { path_concat( @@ -125,24 +133,17 @@ static void update_task_cleanup_resources(UpdateTask* update_task, const uint32_ folder_path); FURI_LOG_D(TAG, "Removing folder %s", furi_string_get_cstr(folder_path)); - if(!storage_dir_open(folder_file, furi_string_get_cstr(folder_path))) { - FURI_LOG_W( + FS_Error result = storage_common_remove( + update_task->storage, furi_string_get_cstr(folder_path)); + if(result != FSE_OK && result != FSE_EXIST) { + FURI_LOG_E( TAG, - "%s can't be opened, skipping", - furi_string_get_cstr(folder_path)); - break; + "%s remove failed, cause %s", + furi_string_get_cstr(folder_path), + storage_error_get_desc(result)); } - - if(storage_dir_read(folder_file, NULL, NULL, 0)) { - FURI_LOG_I( - TAG, "%s is not empty, skipping", furi_string_get_cstr(folder_path)); - break; - } - - storage_simply_remove(update_task->storage, furi_string_get_cstr(folder_path)); } while(false); - storage_file_free(folder_file); furi_string_free(folder_path); } } diff --git a/fbt_options.py b/fbt_options.py index 780e6fe92..6ffb6c4c2 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -86,7 +86,7 @@ FIRMWARE_APPS = { # Svc "basic_services", # Apps - "main_apps_default", + "main_apps", "system_apps", # Settings "settings_apps", diff --git a/firmware.scons b/firmware.scons index 92f2d1a91..a094765af 100644 --- a/firmware.scons +++ b/firmware.scons @@ -2,6 +2,7 @@ Import("ENV", "fw_build_meta") from SCons.Errors import UserError from SCons.Node import FS + import itertools from fbt_extra.util import ( @@ -171,7 +172,7 @@ sources = [apps_c] # Gather sources only from app folders in current configuration sources.extend( itertools.chain.from_iterable( - fwenv.GlobRecursive(source_type, appdir.relpath, exclude="lib") + fwenv.GlobRecursive(source_type, appdir.relpath, exclude=["lib"]) for appdir, source_type in fwenv["APPBUILD"].get_builtin_app_folders() ) ) diff --git a/firmware/targets/f18/api_symbols.csv b/firmware/targets/f18/api_symbols.csv index e4a7dfdd5..88da0db60 100644 --- a/firmware/targets/f18/api_symbols.csv +++ b/firmware/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,12.1,, +Version,+,15.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -546,6 +546,7 @@ Function,+,canvas_invert_color,void,Canvas* Function,+,canvas_reset,void,Canvas* Function,+,canvas_set_bitmap_mode,void,"Canvas*, _Bool" Function,+,canvas_set_color,void,"Canvas*, Color" +Function,+,canvas_set_custom_u8g2_font,void,"Canvas*, const uint8_t*" Function,+,canvas_set_font,void,"Canvas*, Font" Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" Function,+,canvas_string_width,uint16_t,"Canvas*, const char*" @@ -978,7 +979,7 @@ Function,+,furi_hal_power_enable_external_3_3v,void, Function,+,furi_hal_power_enable_otg,void, Function,+,furi_hal_power_gauge_is_ok,_Bool, Function,+,furi_hal_power_get_bat_health_pct,uint8_t, -Function,+,furi_hal_power_get_battery_charging_voltage,float, +Function,+,furi_hal_power_get_battery_charge_voltage_limit,float, Function,+,furi_hal_power_get_battery_current,float,FuriHalPowerIC Function,+,furi_hal_power_get_battery_design_capacity,uint32_t, Function,+,furi_hal_power_get_battery_full_capacity,uint32_t, @@ -997,7 +998,7 @@ Function,+,furi_hal_power_is_charging_done,_Bool, Function,+,furi_hal_power_is_otg_enabled,_Bool, Function,+,furi_hal_power_off,void, Function,+,furi_hal_power_reset,void, -Function,+,furi_hal_power_set_battery_charging_voltage,void,float +Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float Function,+,furi_hal_power_shutdown,void, Function,+,furi_hal_power_sleep,void, Function,+,furi_hal_power_sleep_available,_Bool, @@ -1016,6 +1017,7 @@ Function,+,furi_hal_region_is_frequency_allowed,_Bool,uint32_t Function,+,furi_hal_region_is_provisioned,_Bool, Function,+,furi_hal_region_set,void,FuriHalRegion* 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_rtc_datetime_to_timestamp,uint32_t,FuriHalRtcDateTime* @@ -1061,11 +1063,13 @@ Function,+,furi_hal_spi_bus_handle_deinit,void,FuriHalSpiBusHandle* Function,+,furi_hal_spi_bus_handle_init,void,FuriHalSpiBusHandle* Function,+,furi_hal_spi_bus_init,void,FuriHalSpiBus* Function,+,furi_hal_spi_bus_rx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, uint32_t" -Function,+,furi_hal_spi_bus_trx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, uint8_t*, size_t, uint32_t" -Function,+,furi_hal_spi_bus_tx,_Bool,"FuriHalSpiBusHandle*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_bus_trx,_Bool,"FuriHalSpiBusHandle*, const uint8_t*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_bus_trx_dma,_Bool,"FuriHalSpiBusHandle*, uint8_t*, uint8_t*, size_t, uint32_t" +Function,+,furi_hal_spi_bus_tx,_Bool,"FuriHalSpiBusHandle*, const uint8_t*, size_t, uint32_t" Function,-,furi_hal_spi_config_deinit_early,void, Function,-,furi_hal_spi_config_init,void, Function,-,furi_hal_spi_config_init_early,void, +Function,-,furi_hal_spi_dma_init,void, Function,+,furi_hal_spi_release,void,FuriHalSpiBusHandle* Function,+,furi_hal_switch,void,void* Function,+,furi_hal_uart_deinit,void,FuriHalUartId @@ -1119,6 +1123,7 @@ Function,+,furi_kernel_unlock,int32_t, Function,+,furi_log_get_level,FuriLogLevel, Function,-,furi_log_init,void, Function,+,furi_log_print_format,void,"FuriLogLevel, const char*, const char*, ..." +Function,+,furi_log_print_raw_format,void,"FuriLogLevel, const char*, ..." Function,+,furi_log_set_level,void,FuriLogLevel Function,-,furi_log_set_puts,void,FuriLogPuts Function,-,furi_log_set_timestamp,void,FuriLogTimestamp @@ -1231,6 +1236,7 @@ Function,+,furi_thread_flags_wait,uint32_t,"uint32_t, uint32_t, uint32_t" Function,+,furi_thread_free,void,FuriThread* Function,+,furi_thread_get_current,FuriThread*, Function,+,furi_thread_get_current_id,FuriThreadId, +Function,+,furi_thread_get_current_priority,FuriThreadPriority, Function,+,furi_thread_get_heap_size,size_t,FuriThread* Function,+,furi_thread_get_id,FuriThreadId,FuriThread* Function,+,furi_thread_get_name,const char*,FuriThreadId @@ -1244,6 +1250,7 @@ Function,+,furi_thread_mark_as_service,void,FuriThread* Function,+,furi_thread_resume,void,FuriThreadId Function,+,furi_thread_set_callback,void,"FuriThread*, FuriThreadCallback" Function,+,furi_thread_set_context,void,"FuriThread*, void*" +Function,+,furi_thread_set_current_priority,void,FuriThreadPriority Function,+,furi_thread_set_name,void,"FuriThread*, const char*" Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" diff --git a/firmware/targets/f18/furi_hal/furi_hal.c b/firmware/targets/f18/furi_hal/furi_hal.c index ad35a0074..0a68fdb69 100644 --- a/firmware/targets/f18/furi_hal/furi_hal.c +++ b/firmware/targets/f18/furi_hal/furi_hal.c @@ -51,6 +51,7 @@ void furi_hal_init() { furi_hal_version_init(); furi_hal_spi_config_init(); + furi_hal_spi_dma_init(); furi_hal_speaker_init(); FURI_LOG_I(TAG, "Speaker OK"); diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.c b/firmware/targets/f18/furi_hal/furi_hal_resources.c index dafeefdd0..41cc80bfb 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_resources.c +++ b/firmware/targets/f18/furi_hal/furi_hal_resources.c @@ -199,3 +199,27 @@ void furi_hal_resources_init() { NVIC_SetPriority(EXTI15_10_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(EXTI15_10_IRQn); } + +int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio) { + // TODO: describe second ROW + if(gpio == &gpio_ext_pa7) + return 2; + else if(gpio == &gpio_ext_pa6) + return 3; + else if(gpio == &gpio_ext_pa4) + return 4; + else if(gpio == &gpio_ext_pb3) + return 5; + else if(gpio == &gpio_ext_pb2) + return 6; + else if(gpio == &gpio_ext_pc3) + return 7; + else if(gpio == &gpio_ext_pc1) + return 15; + else if(gpio == &gpio_ext_pc0) + return 16; + else if(gpio == &ibutton_gpio) + return 17; + else + return -1; +} diff --git a/firmware/targets/f18/furi_hal/furi_hal_resources.h b/firmware/targets/f18/furi_hal/furi_hal_resources.h index ef2cdae7f..a24afbf94 100644 --- a/firmware/targets/f18/furi_hal/furi_hal_resources.h +++ b/firmware/targets/f18/furi_hal/furi_hal_resources.h @@ -111,6 +111,13 @@ void furi_hal_resources_deinit_early(); void furi_hal_resources_init(); +/** + * Get a corresponding external connector pin number for a gpio + * @param gpio GpioPin + * @return pin number or -1 if gpio is not on the external connector + */ +int32_t furi_hal_resources_get_ext_pin_number(const GpioPin* gpio); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 5416734b6..5d4295513 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -498,6 +498,10 @@ Function,+,acquire_mutex,void*,"ValueMutex*, uint32_t" Function,-,aligned_alloc,void*,"size_t, size_t" Function,+,aligned_free,void,void* Function,+,aligned_malloc,void*,"size_t, size_t" +Function,-,alutech_get_custom_btn,uint8_t, +Function,-,alutech_get_original_btn,uint8_t, +Function,-,alutech_reset_original_btn,void, +Function,-,alutech_set_btn,void,uint8_t Function,-,arc4random,__uint32_t, Function,-,arc4random_buf,void,"void*, size_t" Function,-,arc4random_uniform,__uint32_t,__uint32_t @@ -624,7 +628,7 @@ Function,-,bzero,void,"void*, size_t" Function,-,calloc,void*,"size_t, size_t" Function,+,canvas_clear,void,Canvas* Function,+,canvas_commit,void,Canvas* -Function,+,canvas_current_font_height,uint8_t,Canvas* +Function,+,canvas_current_font_height,uint8_t,const Canvas* Function,+,canvas_draw_bitmap,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" Function,+,canvas_draw_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,canvas_draw_circle,void,"Canvas*, uint8_t, uint8_t, uint8_t" @@ -645,11 +649,11 @@ Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, co Function,-,canvas_frame_set,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,-,canvas_free,void,Canvas* Function,+,canvas_get_buffer,uint8_t*,Canvas* -Function,+,canvas_get_buffer_size,size_t,Canvas* -Function,+,canvas_get_font_params,CanvasFontParameters*,"Canvas*, Font" +Function,+,canvas_get_buffer_size,size_t,const Canvas* +Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font" Function,-,canvas_get_orientation,CanvasOrientation,const Canvas* Function,+,canvas_glyph_width,uint8_t,"Canvas*, char" -Function,+,canvas_height,uint8_t,Canvas* +Function,+,canvas_height,uint8_t,const Canvas* Function,-,canvas_init,Canvas*, Function,+,canvas_invert_color,void,Canvas* Function,+,canvas_reset,void,Canvas* @@ -660,7 +664,7 @@ Function,+,canvas_set_font,void,"Canvas*, Font" Function,+,canvas_set_font_direction,void,"Canvas*, CanvasDirection" Function,-,canvas_set_orientation,void,"Canvas*, CanvasOrientation" Function,+,canvas_string_width,uint16_t,"Canvas*, const char*" -Function,+,canvas_width,uint8_t,Canvas* +Function,+,canvas_width,uint8_t,const Canvas* Function,-,cbrt,double,double Function,-,cbrtf,float,float Function,-,cbrtl,long double,long double @@ -1173,20 +1177,13 @@ Function,+,furi_hal_i2c_tx,_Bool,"FuriHalI2cBusHandle*, const uint8_t, const uin Function,+,furi_hal_i2c_write_mem,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t*, uint8_t, uint32_t" Function,+,furi_hal_i2c_write_reg_16,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint16_t, uint32_t" Function,+,furi_hal_i2c_write_reg_8,_Bool,"FuriHalI2cBusHandle*, uint8_t, uint8_t, uint8_t, uint32_t" -Function,+,furi_hal_ibutton_add_interrupt,void,"GpioExtiCallback, void*" Function,+,furi_hal_ibutton_emulate_set_next,void,uint32_t Function,+,furi_hal_ibutton_emulate_start,void,"uint32_t, FuriHalIbuttonEmulateCallback, void*" Function,+,furi_hal_ibutton_emulate_stop,void, Function,-,furi_hal_ibutton_init,void, -Function,+,furi_hal_ibutton_pin_get_level,_Bool, -Function,+,furi_hal_ibutton_pin_high,void, -Function,+,furi_hal_ibutton_pin_low,void, -Function,+,furi_hal_ibutton_remove_interrupt,void, -Function,+,furi_hal_ibutton_start_drive,void, -Function,+,furi_hal_ibutton_start_drive_in_isr,void, -Function,+,furi_hal_ibutton_start_interrupt,void, -Function,+,furi_hal_ibutton_start_interrupt_in_isr,void, -Function,+,furi_hal_ibutton_stop,void, +Function,+,furi_hal_ibutton_pin_configure,void, +Function,+,furi_hal_ibutton_pin_reset,void, +Function,+,furi_hal_ibutton_pin_write,void,const _Bool Function,+,furi_hal_info_get,void,"PropertyValueCallback, char, void*" Function,+,furi_hal_infrared_async_rx_set_capture_isr_callback,void,"FuriHalInfraredRxCaptureCallback, void*" Function,+,furi_hal_infrared_async_rx_set_timeout,void,uint32_t @@ -1198,7 +1195,9 @@ Function,+,furi_hal_infrared_async_tx_set_signal_sent_isr_callback,void,"FuriHal Function,+,furi_hal_infrared_async_tx_start,void,"uint32_t, float" Function,+,furi_hal_infrared_async_tx_stop,void, Function,+,furi_hal_infrared_async_tx_wait_termination,void, +Function,+,furi_hal_infrared_get_debug_out_status,_Bool, Function,+,furi_hal_infrared_is_busy,_Bool, +Function,+,furi_hal_infrared_set_debug_out,void,_Bool Function,-,furi_hal_init,void, Function,-,furi_hal_init_early,void, Function,-,furi_hal_interrupt_init,void, @@ -1261,7 +1260,7 @@ Function,+,furi_hal_power_enable_external_3_3v,void, Function,+,furi_hal_power_enable_otg,void, Function,+,furi_hal_power_gauge_is_ok,_Bool, Function,+,furi_hal_power_get_bat_health_pct,uint8_t, -Function,+,furi_hal_power_get_battery_charging_voltage,float, +Function,+,furi_hal_power_get_battery_charge_voltage_limit,float, Function,+,furi_hal_power_get_battery_current,float,FuriHalPowerIC Function,+,furi_hal_power_get_battery_design_capacity,uint32_t, Function,+,furi_hal_power_get_battery_full_capacity,uint32_t, @@ -1280,7 +1279,7 @@ Function,+,furi_hal_power_is_charging_done,_Bool, Function,+,furi_hal_power_is_otg_enabled,_Bool, Function,+,furi_hal_power_off,void, Function,+,furi_hal_power_reset,void, -Function,+,furi_hal_power_set_battery_charging_voltage,void,float +Function,+,furi_hal_power_set_battery_charge_voltage_limit,void,float Function,+,furi_hal_power_shutdown,void, Function,+,furi_hal_power_sleep,void, Function,+,furi_hal_power_sleep_available,_Bool, @@ -1386,6 +1385,7 @@ Function,+,furi_hal_subghz_flush_rx,void, Function,+,furi_hal_subghz_flush_tx,void, Function,+,furi_hal_subghz_get_lqi,uint8_t, Function,+,furi_hal_subghz_get_radio_type,SubGhzRadioType, +Function,+,furi_hal_subghz_get_rolling_counter_mult,uint8_t, Function,+,furi_hal_subghz_get_rssi,float, Function,+,furi_hal_subghz_idle,void, Function,-,furi_hal_subghz_init,void, @@ -1407,6 +1407,7 @@ Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath Function,+,furi_hal_subghz_set_radio_type,_Bool,SubGhzRadioType +Function,+,furi_hal_subghz_set_rolling_counter_mult,void,uint8_t Function,-,furi_hal_subghz_shutdown,void, Function,+,furi_hal_subghz_sleep,void, Function,+,furi_hal_subghz_start_async_rx,void,"FuriHalSubGhzCaptureCallback, void*" @@ -1470,6 +1471,7 @@ Function,+,furi_kernel_unlock,int32_t, Function,+,furi_log_get_level,FuriLogLevel, Function,-,furi_log_init,void, Function,+,furi_log_print_format,void,"FuriLogLevel, const char*, const char*, ..." +Function,+,furi_log_print_raw_format,void,"FuriLogLevel, const char*, ..." Function,+,furi_log_set_level,void,FuriLogLevel Function,-,furi_log_set_puts,void,FuriLogPuts Function,-,furi_log_set_timestamp,void,FuriLogTimestamp @@ -1582,6 +1584,7 @@ Function,+,furi_thread_flags_wait,uint32_t,"uint32_t, uint32_t, uint32_t" Function,+,furi_thread_free,void,FuriThread* Function,+,furi_thread_get_current,FuriThread*, Function,+,furi_thread_get_current_id,FuriThreadId, +Function,+,furi_thread_get_current_priority,FuriThreadPriority, Function,+,furi_thread_get_heap_size,size_t,FuriThread* Function,+,furi_thread_get_id,FuriThreadId,FuriThread* Function,+,furi_thread_get_name,const char*,FuriThreadId @@ -1595,6 +1598,7 @@ Function,+,furi_thread_mark_as_service,void,FuriThread* Function,+,furi_thread_resume,void,FuriThreadId Function,+,furi_thread_set_callback,void,"FuriThread*, FuriThreadCallback" Function,+,furi_thread_set_context,void,"FuriThread*, void*" +Function,+,furi_thread_set_current_priority,void,FuriThreadPriority Function,+,furi_thread_set_name,void,"FuriThread*, const char*" Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" @@ -1623,7 +1627,6 @@ Function,-,gap_init,_Bool,"GapConfig*, GapEventCallback, void*" Function,-,gap_start_advertising,void, Function,-,gap_stop_advertising,void, Function,-,gap_thread_stop,void, -Function,+,getRandomDeed,DolphinDeed, Function,-,getc,int,FILE* Function,-,getc_unlocked,int,FILE* Function,-,getchar,int, @@ -1638,7 +1641,7 @@ Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, voi Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer" Function,+,gui_direct_draw_acquire,Canvas*,Gui* Function,+,gui_direct_draw_release,void,Gui* -Function,+,gui_get_framebuffer_size,size_t,Gui* +Function,+,gui_get_framebuffer_size,size_t,const Gui* Function,+,gui_remove_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" Function,+,gui_remove_view_port,void,"Gui*, ViewPort*" Function,+,gui_set_lockdown,void,"Gui*, _Bool" @@ -1681,9 +1684,9 @@ Function,+,ibutton_worker_write_set_callback,void,"iButtonWorker*, iButtonWorker Function,+,ibutton_worker_write_start,void,"iButtonWorker*, iButtonKey*" Function,+,icon_animation_alloc,IconAnimation*,const Icon* Function,+,icon_animation_free,void,IconAnimation* -Function,+,icon_animation_get_height,uint8_t,IconAnimation* -Function,+,icon_animation_get_width,uint8_t,IconAnimation* -Function,+,icon_animation_is_last_frame,_Bool,IconAnimation* +Function,+,icon_animation_get_height,uint8_t,const IconAnimation* +Function,+,icon_animation_get_width,uint8_t,const IconAnimation* +Function,+,icon_animation_is_last_frame,_Bool,const IconAnimation* Function,+,icon_animation_set_update_callback,void,"IconAnimation*, IconAnimationCallback, void*" Function,+,icon_animation_start,void,IconAnimation* Function,+,icon_animation_stop,void,IconAnimation* @@ -1779,8 +1782,12 @@ Function,-,j1f,float,float Function,-,jn,double,"int, double" Function,-,jnf,float,"int, float" Function,-,jrand48,long,unsigned short[3] +Function,-,keeloq_get_custom_btn,uint8_t, +Function,-,keeloq_get_original_btn,uint8_t, Function,-,keeloq_reset_kl_type,void, Function,-,keeloq_reset_mfname,void, +Function,-,keeloq_reset_original_btn,void, +Function,-,keeloq_set_btn,void,uint8_t Function,-,l64a,char*,long Function,-,labs,long,long Function,-,lcong48,void,unsigned short[7] @@ -1827,7 +1834,7 @@ Function,-,llround,long long int,double Function,-,llroundf,long long int,float Function,-,llroundl,long long int,long double Function,+,loader_get_pubsub,FuriPubSub*,Loader* -Function,+,loader_is_locked,_Bool,Loader* +Function,+,loader_is_locked,_Bool,const Loader* Function,+,loader_lock,_Bool,Loader* Function,+,loader_show_menu,void, Function,+,loader_start,LoaderStatus,"Loader*, const char*, const char*" @@ -2128,6 +2135,10 @@ Function,-,nfcv_inventory,ReturnCode,uint8_t* Function,-,nfcv_read_blocks,ReturnCode,"NfcVReader*, NfcVData*" Function,-,nfcv_read_card,_Bool,"NfcVReader*, FuriHalNfcDevData*, NfcVData*" Function,-,nfcv_read_sysinfo,ReturnCode,"FuriHalNfcDevData*, NfcVData*" +Function,-,nice_flors_get_custom_btn,uint8_t, +Function,-,nice_flors_get_original_btn,uint8_t, +Function,-,nice_flors_reset_original_btn,void, +Function,-,nice_flors_set_btn,void,uint8_t Function,+,notification_internal_message,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*" Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*" @@ -2140,7 +2151,7 @@ Function,+,onewire_device_detach,void,OneWireDevice* Function,+,onewire_device_free,void,OneWireDevice* Function,+,onewire_device_get_id_p,uint8_t*,OneWireDevice* Function,+,onewire_device_send_id,void,OneWireDevice* -Function,+,onewire_host_alloc,OneWireHost*, +Function,+,onewire_host_alloc,OneWireHost*,const GpioPin* Function,+,onewire_host_free,void,OneWireHost* Function,+,onewire_host_read,uint8_t,OneWireHost* Function,+,onewire_host_read_bit,_Bool,OneWireHost* @@ -2154,7 +2165,7 @@ Function,+,onewire_host_stop,void,OneWireHost* Function,+,onewire_host_target_search,void,"OneWireHost*, uint8_t" Function,+,onewire_host_write,void,"OneWireHost*, uint8_t" Function,+,onewire_host_write_bit,void,"OneWireHost*, _Bool" -Function,+,onewire_slave_alloc,OneWireSlave*, +Function,+,onewire_slave_alloc,OneWireSlave*,const GpioPin* Function,+,onewire_slave_attach,void,"OneWireSlave*, OneWireDevice*" Function,+,onewire_slave_detach,void,OneWireSlave* Function,+,onewire_slave_free,void,OneWireSlave* @@ -2484,11 +2495,11 @@ Function,-,scalbnl,long double,"long double, int" Function,-,scanf,int,"const char*, ..." Function,+,scene_manager_alloc,SceneManager*,"const SceneManagerHandlers*, void*" Function,+,scene_manager_free,void,SceneManager* -Function,+,scene_manager_get_scene_state,uint32_t,"SceneManager*, uint32_t" +Function,+,scene_manager_get_scene_state,uint32_t,"const SceneManager*, uint32_t" Function,+,scene_manager_handle_back_event,_Bool,SceneManager* Function,+,scene_manager_handle_custom_event,_Bool,"SceneManager*, uint32_t" Function,+,scene_manager_handle_tick_event,void,SceneManager* -Function,+,scene_manager_has_previous_scene,_Bool,"SceneManager*, uint32_t" +Function,+,scene_manager_has_previous_scene,_Bool,"const SceneManager*, uint32_t" Function,+,scene_manager_next_scene,void,"SceneManager*, uint32_t" Function,+,scene_manager_previous_scene,_Bool,SceneManager* Function,+,scene_manager_search_and_switch_to_another_scene,_Bool,"SceneManager*, uint32_t" @@ -2532,6 +2543,10 @@ Function,-,siprintf,int,"char*, const char*, ..." Function,-,siscanf,int,"const char*, const char*, ..." Function,-,sniprintf,int,"char*, size_t, const char*, ..." Function,+,snprintf,int,"char*, size_t, const char*, ..." +Function,-,somfy_telis_get_custom_btn,uint8_t, +Function,-,somfy_telis_get_original_btn,uint8_t, +Function,-,somfy_telis_reset_original_btn,void, +Function,-,somfy_telis_set_btn,void,uint8_t Function,-,sprintf,int,"char*, const char*, ..." Function,-,sqrt,double,double Function,-,sqrtf,float,float @@ -3262,7 +3277,7 @@ Function,-,subghz_protocol_encoder_star_line_yield,LevelDuration,void* Function,-,subghz_protocol_faac_slh_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint32_t, uint32_t, const char*, SubGhzRadioPreset*" Function,-,subghz_protocol_keeloq_bft_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, uint32_t, const char*, SubGhzRadioPreset*" Function,-,subghz_protocol_keeloq_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, const char*, SubGhzRadioPreset*" -Function,-,subghz_protocol_nice_flor_s_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*" +Function,-,subghz_protocol_nice_flor_s_create_data,_Bool,"void*, FlipperFormat*, uint32_t, uint8_t, uint16_t, SubGhzRadioPreset*, _Bool" Function,-,subghz_protocol_nice_flor_s_encrypt,uint64_t,"uint64_t, const char*" Function,+,subghz_protocol_raw_file_encoder_worker_set_callback_end,void,"SubGhzProtocolEncoderRAW*, SubGhzProtocolEncoderRAWCallbackEnd, void*" Function,+,subghz_protocol_raw_gen_fff_data,void,"FlipperFormat*, const char*" @@ -4604,11 +4619,11 @@ Function,+,view_port_alloc,ViewPort*, Function,+,view_port_draw_callback_set,void,"ViewPort*, ViewPortDrawCallback, void*" Function,+,view_port_enabled_set,void,"ViewPort*, _Bool" Function,+,view_port_free,void,ViewPort* -Function,+,view_port_get_height,uint8_t,ViewPort* +Function,+,view_port_get_height,uint8_t,const ViewPort* Function,+,view_port_get_orientation,ViewPortOrientation,const ViewPort* -Function,+,view_port_get_width,uint8_t,ViewPort* +Function,+,view_port_get_width,uint8_t,const ViewPort* Function,+,view_port_input_callback_set,void,"ViewPort*, ViewPortInputCallback, void*" -Function,+,view_port_is_enabled,_Bool,ViewPort* +Function,+,view_port_is_enabled,_Bool,const ViewPort* Function,+,view_port_set_height,void,"ViewPort*, uint8_t" Function,+,view_port_set_orientation,void,"ViewPort*, ViewPortOrientation" Function,+,view_port_set_width,void,"ViewPort*, uint8_t" diff --git a/firmware/targets/f7/fatfs/sd_spi_io.c b/firmware/targets/f7/fatfs/sd_spi_io.c index 93b837e85..68903acfb 100644 --- a/firmware/targets/f7/fatfs/sd_spi_io.c +++ b/firmware/targets/f7/fatfs/sd_spi_io.c @@ -17,7 +17,6 @@ #define SD_DUMMY_BYTE 0xFF #define SD_ANSWER_RETRY_COUNT 8 #define SD_IDLE_RETRY_COUNT 100 -#define SD_BLOCK_SIZE 512 #define FLAG_SET(x, y) (((x) & (y)) == (y)) @@ -598,23 +597,6 @@ static SdSpiStatus sd_spi_get_cid(SD_CID* Cid) { return ret; } -static inline bool sd_cache_get(uint32_t address, uint32_t* data) { - uint8_t* cached_data = sector_cache_get(address); - if(cached_data) { - memcpy(data, cached_data, SD_BLOCK_SIZE); - return true; - } - return false; -} - -static inline void sd_cache_put(uint32_t address, uint32_t* data) { - sector_cache_put(address, (uint8_t*)data); -} - -static inline void sd_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) { - sector_cache_invalidate_range(start_sector, end_sector); -} - static SdSpiStatus sd_spi_cmd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) { uint32_t block_address = address; @@ -833,30 +815,12 @@ SdSpiStatus sd_get_card_info(SD_CardInfo* card_info) { SdSpiStatus sd_read_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) { - SdSpiStatus status = SdSpiStatusError; - - bool single_sector_read = (blocks == 1); - - if(single_sector_read) { - if(sd_cache_get(address, data)) { - return SdSpiStatusOK; - } - - status = sd_spi_cmd_read_blocks(data, address, blocks, timeout_ms); - - if(status == SdSpiStatusOK) { - sd_cache_put(address, data); - } - } else { - status = sd_spi_cmd_read_blocks(data, address, blocks, timeout_ms); - } - + SdSpiStatus status = sd_spi_cmd_read_blocks(data, address, blocks, timeout_ms); return status; } SdSpiStatus sd_write_blocks(uint32_t* data, uint32_t address, uint32_t blocks, uint32_t timeout_ms) { - sd_cache_invalidate_range(address, address + blocks); SdSpiStatus status = sd_spi_cmd_write_blocks(data, address, blocks, timeout_ms); return status; } diff --git a/firmware/targets/f7/fatfs/sd_spi_io.h b/firmware/targets/f7/fatfs/sd_spi_io.h index 8850eceb7..954c78c40 100644 --- a/firmware/targets/f7/fatfs/sd_spi_io.h +++ b/firmware/targets/f7/fatfs/sd_spi_io.h @@ -5,6 +5,7 @@ #define __IO volatile #define SD_TIMEOUT_MS (1000) +#define SD_BLOCK_SIZE 512 typedef enum { SdSpiStatusOK, diff --git a/firmware/targets/f7/fatfs/sector_cache.c b/firmware/targets/f7/fatfs/sector_cache.c index d23c1d5ad..efb520ec8 100644 --- a/firmware/targets/f7/fatfs/sector_cache.c +++ b/firmware/targets/f7/fatfs/sector_cache.c @@ -8,7 +8,6 @@ #define SECTOR_SIZE 512 #define N_SECTORS 8 -#define TAG "SDCache" typedef struct { uint32_t itr; @@ -20,15 +19,11 @@ static SectorCache* cache = NULL; void sector_cache_init() { if(cache == NULL) { - // TODO: tuneup allocation order, to place cache in mem pool (MEM2) cache = memmgr_alloc_from_pool(sizeof(SectorCache)); } if(cache != NULL) { - FURI_LOG_I(TAG, "Init"); memset(cache, 0, sizeof(SectorCache)); - } else { - FURI_LOG_E(TAG, "Init failed"); } } diff --git a/firmware/targets/f7/fatfs/spi_sd_hal.c b/firmware/targets/f7/fatfs/spi_sd_hal.c deleted file mode 100644 index bfe046b58..000000000 --- a/firmware/targets/f7/fatfs/spi_sd_hal.c +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include - -#define SD_DUMMY_BYTE 0xFF - -const uint32_t SpiTimeout = 1000; -uint8_t SD_IO_WriteByte(uint8_t Data); - -/****************************************************************************** - BUS OPERATIONS - *******************************************************************************/ - -/** - * @brief SPI Write byte(s) to device - * @param DataIn: Pointer to data buffer to write - * @param DataOut: Pointer to data buffer for read data - * @param DataLength: number of bytes to write - * @retval None - */ -static void SPIx_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength) { - furi_check(furi_hal_spi_bus_trx( - furi_hal_sd_spi_handle, (uint8_t*)DataIn, DataOut, DataLength, SpiTimeout)); -} - -/** - * @brief SPI Write a byte to device - * @param Value: value to be written - * @retval None - */ -__attribute__((unused)) static void SPIx_Write(uint8_t Value) { - furi_check(furi_hal_spi_bus_tx(furi_hal_sd_spi_handle, (uint8_t*)&Value, 1, SpiTimeout)); -} - -/****************************************************************************** - LINK OPERATIONS - *******************************************************************************/ - -/********************************* LINK SD ************************************/ -/** - * @brief Initialize the SD Card and put it into StandBy State (Ready for - * data transfer). - * @retval None - */ -void SD_IO_Init(void) { - uint8_t counter = 0; - - /* SD chip select high */ - furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, true); - furi_delay_us(10); - - /* Send dummy byte 0xFF, 10 times with CS high */ - /* Rise CS and MOSI for 80 clocks cycles */ - for(counter = 0; counter <= 200; counter++) { - /* Send dummy byte 0xFF */ - SD_IO_WriteByte(SD_DUMMY_BYTE); - } -} - -/** - * @brief Set SD interface Chip Select state - * @param val: 0 (low) or 1 (high) state - * @retval None - */ -void SD_IO_CSState(uint8_t val) { - /* Some SD Cards are prone to fail if CLK-ed too soon after CS transition. Worst case found: 8us */ - if(val == 1) { - furi_delay_us(10); // Exit guard time for some SD cards - furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, true); - } else { - furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, false); - furi_delay_us(10); // Entry guard time for some SD cards - } -} - -/** - * @brief Write byte(s) on the SD - * @param DataIn: Pointer to data buffer to write - * @param DataOut: Pointer to data buffer for read data - * @param DataLength: number of bytes to write - * @retval None - */ -void SD_IO_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength) { - /* Send the byte */ - SPIx_WriteReadData(DataIn, DataOut, DataLength); -} - -/** - * @brief Write a byte on the SD. - * @param Data: byte to send. - * @retval Data written - */ -uint8_t SD_IO_WriteByte(uint8_t Data) { - uint8_t tmp; - - /* Send the byte */ - SPIx_WriteReadData(&Data, &tmp, 1); - return tmp; -} diff --git a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c b/firmware/targets/f7/fatfs/stm32_adafruit_sd.c deleted file mode 100644 index 998adee29..000000000 --- a/firmware/targets/f7/fatfs/stm32_adafruit_sd.c +++ /dev/null @@ -1,1113 +0,0 @@ -/** - ****************************************************************************** - * @file stm32_adafruit_sd.c - * @author MCD Application Team - * @version V3.0.0 - * @date 23-December-2016 - * @brief This file provides a set of functions needed to manage the SD card - * mounted on the Adafruit 1.8" TFT LCD shield (reference ID 802), - * that is used with the STM32 Nucleo board through SPI interface. - * It implements a high level communication layer for read and write - * from/to this memory. The needed STM32XXxx hardware resources (SPI and - * GPIO) are defined in stm32XXxx_nucleo.h file, and the initialization is - * performed in SD_IO_Init() function declared in stm32XXxx_nucleo.c - * file. - * You can easily tailor this driver to any other development board, - * by just adapting the defines for hardware resources and - * SD_IO_Init() function. - * - * +-------------------------------------------------------+ - * | Pin assignment | - * +-------------------------+---------------+-------------+ - * | STM32XXxx SPI Pins | SD | Pin | - * +-------------------------+---------------+-------------+ - * | SD_SPI_CS_PIN | ChipSelect | 1 | - * | SD_SPI_MOSI_PIN / MOSI | DataIn | 2 | - * | | GND | 3 (0 V) | - * | | VDD | 4 (3.3 V)| - * | SD_SPI_SCK_PIN / SCLK | Clock | 5 | - * | | GND | 6 (0 V) | - * | SD_SPI_MISO_PIN / MISO | DataOut | 7 | - * +-------------------------+---------------+-------------+ - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* File Info : ----------------------------------------------------------------- - User NOTES -1. How to use this driver: --------------------------- - - This driver does not need a specific component driver for the micro SD device - to be included with. - -2. Driver description: ---------------------- - + Initialization steps: - o Initialize the micro SD card using the BSP_SD_Init() function. - o Checking the SD card presence is not managed because SD detection pin is - not physically mapped on the Adafruit shield. - o The function BSP_SD_GetCardInfo() is used to get the micro SD card information - which is stored in the structure "SD_CardInfo". - - + Micro SD card operations - o The micro SD card can be accessed with read/write block(s) operations once - it is ready for access. The access can be performed in polling - mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks() - - o The SD erase block(s) is performed using the function BSP_SD_Erase() with - specifying the number of blocks to erase. - o The SD runtime status is returned when calling the function BSP_SD_GetStatus(). - -------------------------------------------------------------------------------*/ - -/* Includes ------------------------------------------------------------------*/ -#include "stm32_adafruit_sd.h" -#include "stdlib.h" -#include "string.h" -#include "stdio.h" -#include -#include "sector_cache.h" - -/** @addtogroup BSP - * @{ - */ - -/** @addtogroup STM32_ADAFRUIT - * @{ - */ - -/** @defgroup STM32_ADAFRUIT_SD - * @{ - */ - -/* Private typedef -----------------------------------------------------------*/ - -/** @defgroup STM32_ADAFRUIT_SD_Private_Types_Definitions - * @{ - */ -typedef struct { - uint8_t r1; - uint8_t r2; - uint8_t r3; - uint8_t r4; - uint8_t r5; -} SD_CmdAnswer_typedef; - -/** - * @} - */ - -/* Private define ------------------------------------------------------------*/ - -/** @defgroup STM32_ADAFRUIT_SD_Private_Defines - * @{ - */ -#define SD_DUMMY_BYTE 0xFF - -#define SD_MAX_FRAME_LENGTH 17 /* Lenght = 16 + 1 */ -#define SD_CMD_LENGTH 6 - -#define SD_MAX_TRY 100 /* Number of try */ - -#define SD_CSD_STRUCT_V1 0x2 /* CSD struct version V1 */ -#define SD_CSD_STRUCT_V2 0x1 /* CSD struct version V2 */ - -/** - * @brief SD ansewer format - */ -typedef enum { - SD_ANSWER_R1_EXPECTED, - SD_ANSWER_R1B_EXPECTED, - SD_ANSWER_R2_EXPECTED, - SD_ANSWER_R3_EXPECTED, - SD_ANSWER_R4R5_EXPECTED, - SD_ANSWER_R7_EXPECTED, -} SD_Answer_type; - -/** - * @brief Start Data tokens: - * Tokens (necessary because at nop/idle (and CS active) only 0xff is - * on the data/command line) - */ -#define SD_TOKEN_START_DATA_SINGLE_BLOCK_READ \ - 0xFE /* Data token start byte, Start Single Block Read */ -#define SD_TOKEN_START_DATA_MULTIPLE_BLOCK_READ \ - 0xFE /* Data token start byte, Start Multiple Block Read */ -#define SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE \ - 0xFE /* Data token start byte, Start Single Block Write */ -#define SD_TOKEN_START_DATA_MULTIPLE_BLOCK_WRITE \ - 0xFD /* Data token start byte, Start Multiple Block Write */ -#define SD_TOKEN_STOP_DATA_MULTIPLE_BLOCK_WRITE \ - 0xFD /* Data toke stop byte, Stop Multiple Block Write */ - -/** - * @brief Commands: CMDxx = CMD-number | 0x40 - */ -#define SD_CMD_GO_IDLE_STATE 0 /* CMD0 = 0x40 */ -#define SD_CMD_SEND_OP_COND 1 /* CMD1 = 0x41 */ -#define SD_CMD_SEND_IF_COND 8 /* CMD8 = 0x48 */ -#define SD_CMD_SEND_CSD 9 /* CMD9 = 0x49 */ -#define SD_CMD_SEND_CID 10 /* CMD10 = 0x4A */ -#define SD_CMD_STOP_TRANSMISSION 12 /* CMD12 = 0x4C */ -#define SD_CMD_SEND_STATUS 13 /* CMD13 = 0x4D */ -#define SD_CMD_SET_BLOCKLEN 16 /* CMD16 = 0x50 */ -#define SD_CMD_READ_SINGLE_BLOCK 17 /* CMD17 = 0x51 */ -#define SD_CMD_READ_MULT_BLOCK 18 /* CMD18 = 0x52 */ -#define SD_CMD_SET_BLOCK_COUNT 23 /* CMD23 = 0x57 */ -#define SD_CMD_WRITE_SINGLE_BLOCK 24 /* CMD24 = 0x58 */ -#define SD_CMD_WRITE_MULT_BLOCK 25 /* CMD25 = 0x59 */ -#define SD_CMD_PROG_CSD 27 /* CMD27 = 0x5B */ -#define SD_CMD_SET_WRITE_PROT 28 /* CMD28 = 0x5C */ -#define SD_CMD_CLR_WRITE_PROT 29 /* CMD29 = 0x5D */ -#define SD_CMD_SEND_WRITE_PROT 30 /* CMD30 = 0x5E */ -#define SD_CMD_SD_ERASE_GRP_START 32 /* CMD32 = 0x60 */ -#define SD_CMD_SD_ERASE_GRP_END 33 /* CMD33 = 0x61 */ -#define SD_CMD_UNTAG_SECTOR 34 /* CMD34 = 0x62 */ -#define SD_CMD_ERASE_GRP_START 35 /* CMD35 = 0x63 */ -#define SD_CMD_ERASE_GRP_END 36 /* CMD36 = 0x64 */ -#define SD_CMD_UNTAG_ERASE_GROUP 37 /* CMD37 = 0x65 */ -#define SD_CMD_ERASE 38 /* CMD38 = 0x66 */ -#define SD_CMD_SD_APP_OP_COND 41 /* CMD41 = 0x69 */ -#define SD_CMD_APP_CMD 55 /* CMD55 = 0x77 */ -#define SD_CMD_READ_OCR 58 /* CMD55 = 0x79 */ - -/** - * @brief SD reponses and error flags - */ -typedef enum { - /* R1 answer value */ - SD_R1_NO_ERROR = (0x00), - SD_R1_IN_IDLE_STATE = (0x01), - SD_R1_ERASE_RESET = (0x02), - SD_R1_ILLEGAL_COMMAND = (0x04), - SD_R1_COM_CRC_ERROR = (0x08), - SD_R1_ERASE_SEQUENCE_ERROR = (0x10), - SD_R1_ADDRESS_ERROR = (0x20), - SD_R1_PARAMETER_ERROR = (0x40), - - /* R2 answer value */ - SD_R2_NO_ERROR = 0x00, - SD_R2_CARD_LOCKED = 0x01, - SD_R2_LOCKUNLOCK_ERROR = 0x02, - SD_R2_ERROR = 0x04, - SD_R2_CC_ERROR = 0x08, - SD_R2_CARD_ECC_FAILED = 0x10, - SD_R2_WP_VIOLATION = 0x20, - SD_R2_ERASE_PARAM = 0x40, - SD_R2_OUTOFRANGE = 0x80, - - /** - * @brief Data response error - */ - SD_DATA_OK = (0x05), - SD_DATA_CRC_ERROR = (0x0B), - SD_DATA_WRITE_ERROR = (0x0D), - SD_DATA_OTHER_ERROR = (0xFF) -} SD_Error; - -/** - * @} - */ - -/* Private macro -------------------------------------------------------------*/ - -/** @defgroup STM32_ADAFRUIT_SD_Private_Macros - * @{ - */ - -/** - * @} - */ - -/* Private variables ---------------------------------------------------------*/ - -/** @defgroup STM32_ADAFRUIT_SD_Private_Variables - * @{ - */ -__IO uint8_t SdStatus = SD_NOT_PRESENT; - -/* flag_SDHC : - 0 : Standard capacity - 1 : High capacity -*/ -uint16_t flag_SDHC = 0; - -/** - * @} - */ - -/* Private function prototypes -----------------------------------------------*/ -static uint8_t SD_GetCIDRegister(SD_CID* Cid); -static uint8_t SD_GetCSDRegister(SD_CSD* Csd); -static uint8_t SD_GetDataResponse(void); -static uint8_t SD_GoIdleState(void); -static SD_CmdAnswer_typedef SD_SendCmd(uint8_t Cmd, uint32_t Arg, uint8_t Crc, uint8_t Answer); -static uint8_t SD_WaitData(uint8_t data); -static uint8_t SD_ReadData(void); -/** @defgroup STM32_ADAFRUIT_SD_Private_Function_Prototypes - * @{ - */ -/** - * @} - */ - -/* Private functions ---------------------------------------------------------*/ - -void SD_SPI_Bus_To_Down_State() { - furi_hal_gpio_init_ex( - furi_hal_sd_spi_handle->miso, - GpioModeOutputPushPull, - GpioPullNo, - GpioSpeedVeryHigh, - GpioAltFnUnused); - furi_hal_gpio_init_ex( - furi_hal_sd_spi_handle->mosi, - GpioModeOutputPushPull, - GpioPullNo, - GpioSpeedVeryHigh, - GpioAltFnUnused); - furi_hal_gpio_init_ex( - furi_hal_sd_spi_handle->sck, - GpioModeOutputPushPull, - GpioPullNo, - GpioSpeedVeryHigh, - GpioAltFnUnused); - - furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, false); - furi_hal_gpio_write(furi_hal_sd_spi_handle->miso, false); - furi_hal_gpio_write(furi_hal_sd_spi_handle->mosi, false); - furi_hal_gpio_write(furi_hal_sd_spi_handle->sck, false); -} - -void SD_SPI_Bus_To_Normal_State() { - furi_hal_gpio_write(furi_hal_sd_spi_handle->cs, true); - - furi_hal_gpio_init_ex( - furi_hal_sd_spi_handle->miso, - GpioModeAltFunctionPushPull, - GpioPullUp, - GpioSpeedVeryHigh, - GpioAltFn5SPI2); - furi_hal_gpio_init_ex( - furi_hal_sd_spi_handle->mosi, - GpioModeAltFunctionPushPull, - GpioPullUp, - GpioSpeedVeryHigh, - GpioAltFn5SPI2); - furi_hal_gpio_init_ex( - furi_hal_sd_spi_handle->sck, - GpioModeAltFunctionPushPull, - GpioPullUp, - GpioSpeedVeryHigh, - GpioAltFn5SPI2); -} - -/** @defgroup STM32_ADAFRUIT_SD_Private_Functions - * @{ - */ - -uint8_t BSP_SD_MaxMountRetryCount() { - return 10; -} - -/** - * @brief Initializes the SD/SD communication. - * @param None - * @retval The SD Response: - * - MSD_ERROR: Sequence failed - * - MSD_OK: Sequence succeed - */ -uint8_t BSP_SD_Init(bool reset_card) { - /* Slow speed init */ - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_slow); - furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_slow; - - /* We must reset card in spi_lock context */ - if(reset_card) { - /* disable power and set low on all bus pins */ - furi_hal_power_disable_external_3_3v(); - SD_SPI_Bus_To_Down_State(); - hal_sd_detect_set_low(); - furi_delay_ms(250); - - /* reinit bus and enable power */ - SD_SPI_Bus_To_Normal_State(); - hal_sd_detect_init(); - furi_hal_power_enable_external_3_3v(); - furi_delay_ms(100); - } - - /* Configure IO functionalities for SD pin */ - SD_IO_Init(); - - /* SD detection pin is not physically mapped on the Adafruit shield */ - SdStatus = SD_PRESENT; - uint8_t res = BSP_SD_ERROR; - - for(uint8_t i = 0; i < 128; i++) { - res = SD_GoIdleState(); - if(res == BSP_SD_OK) break; - } - - furi_hal_sd_spi_handle = NULL; - furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); - - sector_cache_init(); - - /* SD initialized and set to SPI mode properly */ - return res; -} - -/** - * @brief Returns information about specific card. - * @param pCardInfo: Pointer to a SD_CardInfo structure that contains all SD - * card information. - * @retval The SD Response: - * - MSD_ERROR: Sequence failed - * - MSD_OK: Sequence succeed - */ -uint8_t BSP_SD_GetCardInfo(SD_CardInfo* pCardInfo) { - uint8_t status; - - status = SD_GetCSDRegister(&(pCardInfo->Csd)); - status |= SD_GetCIDRegister(&(pCardInfo->Cid)); - if(flag_SDHC == 1) { - pCardInfo->LogBlockSize = 512; - pCardInfo->CardBlockSize = 512; - pCardInfo->CardCapacity = ((uint64_t)pCardInfo->Csd.version.v2.DeviceSize + 1UL) * 1024UL * - (uint64_t)pCardInfo->LogBlockSize; - pCardInfo->LogBlockNbr = (pCardInfo->CardCapacity) / (pCardInfo->LogBlockSize); - } else { - pCardInfo->CardCapacity = (pCardInfo->Csd.version.v1.DeviceSize + 1); - pCardInfo->CardCapacity *= (1UL << (pCardInfo->Csd.version.v1.DeviceSizeMul + 2)); - pCardInfo->LogBlockSize = 512; - pCardInfo->CardBlockSize = 1UL << (pCardInfo->Csd.RdBlockLen); - pCardInfo->CardCapacity *= pCardInfo->CardBlockSize; - pCardInfo->LogBlockNbr = (pCardInfo->CardCapacity) / (pCardInfo->LogBlockSize); - } - - return status; -} - -/** - * @brief Reads block(s) from a specified address in the SD card, in polling mode. - * @param pData: Pointer to the buffer that will contain the data to transmit - * @param ReadAddr: Address from where data is to be read. The address is counted - * in blocks of 512bytes - * @param NumOfBlocks: Number of SD blocks to read - * @param Timeout: This parameter is used for compatibility with BSP implementation - * @retval SD status - */ -uint8_t - BSP_SD_ReadBlocks(uint32_t* pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) { - UNUSED(Timeout); // FIXME! - uint32_t offset = 0; - uint32_t addr; - uint8_t retr = BSP_SD_ERROR; - SD_CmdAnswer_typedef response; - uint16_t BlockSize = 512; - uint8_t* cached_data; - - bool single_sector_read = (NumOfBlocks == 1); - if(single_sector_read && (cached_data = sector_cache_get(ReadAddr))) { - memcpy(pData, cached_data, BlockSize); - return BSP_SD_OK; - } - - /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and - Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ - response = SD_SendCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(response.r1 != SD_R1_NO_ERROR) { - goto error; - } - - /* Initialize the address */ - addr = (ReadAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); - - /* Data transfer */ - while(NumOfBlocks--) { - /* Send CMD17 (SD_CMD_READ_SINGLE_BLOCK) to read one block */ - /* Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */ - response = SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK, addr, 0xFF, SD_ANSWER_R1_EXPECTED); - if(response.r1 != SD_R1_NO_ERROR) { - goto error; - } - - /* Now look for the data token to signify the start of the data */ - if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { - /* Read the SD block data : read NumByteToRead data */ - SD_IO_WriteReadData(NULL, (uint8_t*)pData + offset, BlockSize); - - /* Set next read address*/ - offset += BlockSize; - addr = ((flag_SDHC == 1) ? (addr + 1) : (addr + BlockSize)); - - /* get CRC bytes (not really needed by us, but required by SD) */ - SD_IO_WriteByte(SD_DUMMY_BYTE); - SD_IO_WriteByte(SD_DUMMY_BYTE); - } else { - goto error; - } - - /* End the command data read cycle */ - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - } - - if(single_sector_read) { - sector_cache_put(ReadAddr, (uint8_t*)pData); - } - - retr = BSP_SD_OK; - -error: - /* Send dummy byte: 8 Clock pulses of delay */ - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Return the reponse */ - return retr; -} - -/** - * @brief Writes block(s) to a specified address in the SD card, in polling mode. - * @param pData: Pointer to the buffer that will contain the data to transmit - * @param WriteAddr: Address from where data is to be written. The address is counted - * in blocks of 512bytes - * @param NumOfBlocks: Number of SD blocks to write - * @param Timeout: This parameter is used for compatibility with BSP implementation - * @retval SD status - */ -uint8_t BSP_SD_WriteBlocks( - uint32_t* pData, - uint32_t WriteAddr, - uint32_t NumOfBlocks, - uint32_t Timeout) { - UNUSED(Timeout); // FIXME! - uint32_t offset = 0; - uint32_t addr; - uint8_t retr = BSP_SD_ERROR; - SD_CmdAnswer_typedef response; - uint16_t BlockSize = 512; - sector_cache_invalidate_range(WriteAddr, WriteAddr + NumOfBlocks); - - /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and - Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ - response = SD_SendCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(response.r1 != SD_R1_NO_ERROR) { - goto error; - } - - /* Initialize the address */ - addr = (WriteAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); - - /* Data transfer */ - while(NumOfBlocks--) { - /* Send CMD24 (SD_CMD_WRITE_SINGLE_BLOCK) to write blocks and - Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */ - response = SD_SendCmd(SD_CMD_WRITE_SINGLE_BLOCK, addr, 0xFF, SD_ANSWER_R1_EXPECTED); - if(response.r1 != SD_R1_NO_ERROR) { - goto error; - } - - /* Send dummy byte for NWR timing : one byte between CMDWRITE and TOKEN */ - SD_IO_WriteByte(SD_DUMMY_BYTE); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Send the data token to signify the start of the data */ - SD_IO_WriteByte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE); - - /* Write the block data to SD */ - SD_IO_WriteReadData((uint8_t*)pData + offset, NULL, BlockSize); - - /* Set next write address */ - offset += BlockSize; - addr = ((flag_SDHC == 1) ? (addr + 1) : (addr + BlockSize)); - - /* Put CRC bytes (not really needed by us, but required by SD) */ - SD_IO_WriteByte(SD_DUMMY_BYTE); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Read data response */ - if(SD_GetDataResponse() != SD_DATA_OK) { - /* Set response value to failure */ - goto error; - } - - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - } - retr = BSP_SD_OK; - -error: - - /* Send dummy byte: 8 Clock pulses of delay */ - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Return the reponse */ - return retr; -} - -/** - * @brief Erases the specified memory area of the given SD card. - * @param StartAddr: Start address in Blocks (Size of a block is 512bytes) - * @param EndAddr: End address in Blocks (Size of a block is 512bytes) - * @retval SD status - */ -uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr) { - uint8_t retr = BSP_SD_ERROR; - SD_CmdAnswer_typedef response; - uint16_t BlockSize = 512; - - /* Send CMD32 (Erase group start) and check if the SD acknowledged the erase command: R1 response (0x00: no errors) */ - response = SD_SendCmd( - SD_CMD_SD_ERASE_GRP_START, - (StartAddr) * (flag_SDHC == 1 ? 1 : BlockSize), - 0xFF, - SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(response.r1 == SD_R1_NO_ERROR) { - /* Send CMD33 (Erase group end) and Check if the SD acknowledged the erase command: R1 response (0x00: no errors) */ - response = SD_SendCmd( - SD_CMD_SD_ERASE_GRP_END, - (EndAddr * 512) * (flag_SDHC == 1 ? 1 : BlockSize), - 0xFF, - SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(response.r1 == SD_R1_NO_ERROR) { - /* Send CMD38 (Erase) and Check if the SD acknowledged the erase command: R1 response (0x00: no errors) */ - response = SD_SendCmd(SD_CMD_ERASE, 0, 0xFF, SD_ANSWER_R1B_EXPECTED); - if(response.r1 == SD_R1_NO_ERROR) { - retr = BSP_SD_OK; - } - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - } - } - - /* Return the reponse */ - return retr; -} - -/** - * @brief Returns the SD status. - * @param None - * @retval The SD status. - */ -uint8_t BSP_SD_GetCardState(void) { - SD_CmdAnswer_typedef retr; - - /* Send CMD13 (SD_SEND_STATUS) to get SD status */ - retr = SD_SendCmd(SD_CMD_SEND_STATUS, 0, 0xFF, SD_ANSWER_R2_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Find SD status according to card state */ - if((retr.r1 == SD_R1_NO_ERROR) && (retr.r2 == SD_R2_NO_ERROR)) { - return BSP_SD_OK; - } - - return BSP_SD_ERROR; -} - -/** - * @brief Reads the SD card SCD register. - * Reading the contents of the CSD register in SPI mode is a simple - * read-block transaction. - * @param Csd: pointer on an SCD register structure - * @retval SD status - */ -uint8_t SD_GetCSDRegister(SD_CSD* Csd) { - uint16_t counter = 0; - uint8_t CSD_Tab[16]; - uint8_t retr = BSP_SD_ERROR; - SD_CmdAnswer_typedef response; - - /* Send CMD9 (CSD register) or CMD10(CSD register) and Wait for response in the R1 format (0x00 is no errors) */ - response = SD_SendCmd(SD_CMD_SEND_CSD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); - if(response.r1 == SD_R1_NO_ERROR) { - if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { - for(counter = 0; counter < 16; counter++) { - /* Store CSD register value on CSD_Tab */ - CSD_Tab[counter] = SD_IO_WriteByte(SD_DUMMY_BYTE); - } - - /* Get CRC bytes (not really needed by us, but required by SD) */ - SD_IO_WriteByte(SD_DUMMY_BYTE); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /************************************************************************* - CSD header decoding - *************************************************************************/ - - /* Byte 0 */ - Csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6; - Csd->Reserved1 = CSD_Tab[0] & 0x3F; - - /* Byte 1 */ - Csd->TAAC = CSD_Tab[1]; - - /* Byte 2 */ - Csd->NSAC = CSD_Tab[2]; - - /* Byte 3 */ - Csd->MaxBusClkFrec = CSD_Tab[3]; - - /* Byte 4/5 */ - Csd->CardComdClasses = (CSD_Tab[4] << 4) | ((CSD_Tab[5] & 0xF0) >> 4); - Csd->RdBlockLen = CSD_Tab[5] & 0x0F; - - /* Byte 6 */ - Csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7; - Csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6; - Csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5; - Csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4; - - /************************************************************************* - CSD v1/v2 decoding - *************************************************************************/ - - if(flag_SDHC == 0) { - Csd->version.v1.Reserved1 = ((CSD_Tab[6] & 0x0C) >> 2); - - Csd->version.v1.DeviceSize = ((CSD_Tab[6] & 0x03) << 10) | (CSD_Tab[7] << 2) | - ((CSD_Tab[8] & 0xC0) >> 6); - Csd->version.v1.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3; - Csd->version.v1.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07); - Csd->version.v1.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5; - Csd->version.v1.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2; - Csd->version.v1.DeviceSizeMul = ((CSD_Tab[9] & 0x03) << 1) | - ((CSD_Tab[10] & 0x80) >> 7); - } else { - Csd->version.v2.Reserved1 = ((CSD_Tab[6] & 0x0F) << 2) | - ((CSD_Tab[7] & 0xC0) >> 6); - Csd->version.v2.DeviceSize = ((CSD_Tab[7] & 0x3F) << 16) | (CSD_Tab[8] << 8) | - CSD_Tab[9]; - Csd->version.v2.Reserved2 = ((CSD_Tab[10] & 0x80) >> 8); - } - - Csd->EraseSingleBlockEnable = (CSD_Tab[10] & 0x40) >> 6; - Csd->EraseSectorSize = ((CSD_Tab[10] & 0x3F) << 1) | ((CSD_Tab[11] & 0x80) >> 7); - Csd->WrProtectGrSize = (CSD_Tab[11] & 0x7F); - Csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7; - Csd->Reserved2 = (CSD_Tab[12] & 0x60) >> 5; - Csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2; - Csd->MaxWrBlockLen = ((CSD_Tab[12] & 0x03) << 2) | ((CSD_Tab[13] & 0xC0) >> 6); - Csd->WriteBlockPartial = (CSD_Tab[13] & 0x20) >> 5; - Csd->Reserved3 = (CSD_Tab[13] & 0x1F); - Csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7; - Csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6; - Csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5; - Csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4; - Csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2; - Csd->Reserved4 = (CSD_Tab[14] & 0x03); - Csd->crc = (CSD_Tab[15] & 0xFE) >> 1; - Csd->Reserved5 = (CSD_Tab[15] & 0x01); - - retr = BSP_SD_OK; - } - } - - /* Send dummy byte: 8 Clock pulses of delay */ - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Return the reponse */ - return retr; -} - -/** - * @brief Reads the SD card CID register. - * Reading the contents of the CID register in SPI mode is a simple - * read-block transaction. - * @param Cid: pointer on an CID register structure - * @retval SD status - */ -uint8_t SD_GetCIDRegister(SD_CID* Cid) { - uint32_t counter = 0; - uint8_t retr = BSP_SD_ERROR; - uint8_t CID_Tab[16]; - SD_CmdAnswer_typedef response; - - /* Send CMD10 (CID register) and Wait for response in the R1 format (0x00 is no errors) */ - response = SD_SendCmd(SD_CMD_SEND_CID, 0, 0xFF, SD_ANSWER_R1_EXPECTED); - if(response.r1 == SD_R1_NO_ERROR) { - if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) { - /* Store CID register value on CID_Tab */ - for(counter = 0; counter < 16; counter++) { - CID_Tab[counter] = SD_IO_WriteByte(SD_DUMMY_BYTE); - } - - /* Get CRC bytes (not really needed by us, but required by SD) */ - SD_IO_WriteByte(SD_DUMMY_BYTE); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Byte 0 */ - Cid->ManufacturerID = CID_Tab[0]; - - /* Byte 1 */ - memcpy(Cid->OEM_AppliID, CID_Tab + 1, 2); - - /* Byte 3 */ - memcpy(Cid->ProdName, CID_Tab + 3, 5); - - /* Byte 8 */ - Cid->ProdRev = CID_Tab[8]; - - /* Byte 9 */ - Cid->ProdSN = CID_Tab[9] << 24; - - /* Byte 10 */ - Cid->ProdSN |= CID_Tab[10] << 16; - - /* Byte 11 */ - Cid->ProdSN |= CID_Tab[11] << 8; - - /* Byte 12 */ - Cid->ProdSN |= CID_Tab[12]; - - /* Byte 13 */ - Cid->Reserved1 = (CID_Tab[13] & 0xF0) >> 4; - Cid->ManufactYear = (CID_Tab[13] & 0x0F) << 4; - - /* Byte 14 */ - Cid->ManufactYear |= (CID_Tab[14] & 0xF0) >> 4; - Cid->ManufactMonth = (CID_Tab[14] & 0x0F); - - /* Byte 15 */ - Cid->CID_CRC = (CID_Tab[15] & 0xFE) >> 1; - Cid->Reserved2 = 1; - - retr = BSP_SD_OK; - } - } - - /* Send dummy byte: 8 Clock pulses of delay */ - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Return the reponse */ - return retr; -} - -uint8_t BSP_SD_GetCIDRegister(SD_CID* Cid) { - uint8_t retr = BSP_SD_ERROR; - - /* Slow speed init */ - furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_slow); - furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_slow; - - memset(Cid, 0, sizeof(SD_CID)); - retr = SD_GetCIDRegister(Cid); - - furi_hal_sd_spi_handle = NULL; - furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_slow); - return retr; -} - -/** - * @brief Sends 5 bytes command to the SD card and get response - * @param Cmd: The user expected command to send to SD card. - * @param Arg: The command argument. - * @param Crc: The CRC. - * @param Answer: SD_ANSWER_NOT_EXPECTED or SD_ANSWER_EXPECTED - * @retval SD status - */ -SD_CmdAnswer_typedef SD_SendCmd(uint8_t Cmd, uint32_t Arg, uint8_t Crc, uint8_t Answer) { - uint8_t frame[SD_CMD_LENGTH], frameout[SD_CMD_LENGTH]; - SD_CmdAnswer_typedef retr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - - /* R1 Lenght = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 1 Bytes answer + NEC(0) = 15bytes */ - /* R1b identical to R1 + Busy information */ - /* R2 Lenght = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 2 Bytes answer + NEC(0) = 16bytes */ - - /* Prepare Frame to send */ - frame[0] = (Cmd | 0x40); /* Construct byte 1 */ - frame[1] = (uint8_t)(Arg >> 24); /* Construct byte 2 */ - frame[2] = (uint8_t)(Arg >> 16); /* Construct byte 3 */ - frame[3] = (uint8_t)(Arg >> 8); /* Construct byte 4 */ - frame[4] = (uint8_t)(Arg); /* Construct byte 5 */ - frame[5] = (Crc | 0x01); /* Construct byte 6 */ - - /* Send the command */ - SD_IO_CSState(0); - SD_IO_WriteReadData(frame, frameout, SD_CMD_LENGTH); /* Send the Cmd bytes */ - - switch(Answer) { - case SD_ANSWER_R1_EXPECTED: - retr.r1 = SD_ReadData(); - break; - case SD_ANSWER_R1B_EXPECTED: - retr.r1 = SD_ReadData(); - retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE); - /* Set CS High */ - SD_IO_CSState(1); - furi_delay_us(1000); - /* Set CS Low */ - SD_IO_CSState(0); - - /* Wait IO line return 0xFF */ - while(SD_IO_WriteByte(SD_DUMMY_BYTE) != 0xFF) - ; - break; - case SD_ANSWER_R2_EXPECTED: - retr.r1 = SD_ReadData(); - retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE); - break; - case SD_ANSWER_R3_EXPECTED: - case SD_ANSWER_R7_EXPECTED: - retr.r1 = SD_ReadData(); - retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE); - retr.r3 = SD_IO_WriteByte(SD_DUMMY_BYTE); - retr.r4 = SD_IO_WriteByte(SD_DUMMY_BYTE); - retr.r5 = SD_IO_WriteByte(SD_DUMMY_BYTE); - break; - default: - break; - } - return retr; -} - -/** - * @brief Gets the SD card data response and check the busy flag. - * @param None - * @retval The SD status: Read data response xxx01 - * - status 010: Data accecpted - * - status 101: Data rejected due to a crc error - * - status 110: Data rejected due to a Write error. - * - status 111: Data rejected due to other error. - */ -uint8_t SD_GetDataResponse(void) { - uint8_t dataresponse; - uint8_t rvalue = SD_DATA_OTHER_ERROR; - - dataresponse = SD_IO_WriteByte(SD_DUMMY_BYTE); - SD_IO_WriteByte(SD_DUMMY_BYTE); /* read the busy response byte*/ - - /* Mask unused bits */ - switch(dataresponse & 0x1F) { - case SD_DATA_OK: - rvalue = SD_DATA_OK; - - /* Set CS High */ - SD_IO_CSState(1); - /* Set CS Low */ - SD_IO_CSState(0); - - /* Wait IO line return 0xFF */ - while(SD_IO_WriteByte(SD_DUMMY_BYTE) != 0xFF) - ; - break; - case SD_DATA_CRC_ERROR: - rvalue = SD_DATA_CRC_ERROR; - break; - case SD_DATA_WRITE_ERROR: - rvalue = SD_DATA_WRITE_ERROR; - break; - default: - break; - } - - /* Return response */ - return rvalue; -} - -/** - * @brief Put the SD in Idle state. - * @param None - * @retval SD status - */ -uint8_t SD_GoIdleState(void) { - SD_CmdAnswer_typedef response; - __IO uint8_t counter; - /* Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode and - wait for In Idle State Response (R1 Format) equal to 0x01 */ - counter = 0; - do { - counter++; - response = SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95, SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(counter >= SD_MAX_TRY) { - return BSP_SD_ERROR; - } - } while(response.r1 != SD_R1_IN_IDLE_STATE); - - /* Send CMD8 (SD_CMD_SEND_IF_COND) to check the power supply status - and wait until response (R7 Format) equal to 0xAA and */ - response = SD_SendCmd(SD_CMD_SEND_IF_COND, 0x1AA, 0x87, SD_ANSWER_R7_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { - /* initialise card V1 */ - counter = 0; - do { - counter++; - /* initialise card V1 */ - /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ - response = SD_SendCmd(SD_CMD_APP_CMD, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */ - response = //-V519 - SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(counter >= SD_MAX_TRY) { - return BSP_SD_ERROR; - } - } while(response.r1 == SD_R1_IN_IDLE_STATE); - flag_SDHC = 0; - } else if(response.r1 == SD_R1_IN_IDLE_STATE) { - /* initialise card V2 */ - counter = 0; - do { - counter++; - /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ - response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - - /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */ - response = //-V519 - SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x40000000, 0xFF, SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(counter >= SD_MAX_TRY) { - return BSP_SD_ERROR; - } - } while(response.r1 == SD_R1_IN_IDLE_STATE); - - if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) { - counter = 0; - do { - counter++; - /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ - response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(response.r1 != SD_R1_IN_IDLE_STATE) { - return BSP_SD_ERROR; - } - /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */ - response = - SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(counter >= SD_MAX_TRY) { - return BSP_SD_ERROR; - } - } while(response.r1 == SD_R1_IN_IDLE_STATE); - } - - /* Send CMD58 (SD_CMD_READ_OCR) to initialize SDHC or SDXC cards: R3 response (0x00: no errors) */ - response = SD_SendCmd(SD_CMD_READ_OCR, 0x00000000, 0xFF, SD_ANSWER_R3_EXPECTED); - SD_IO_CSState(1); - SD_IO_WriteByte(SD_DUMMY_BYTE); - if(response.r1 != SD_R1_NO_ERROR) { - return BSP_SD_ERROR; - } - flag_SDHC = (response.r2 & 0x40) >> 6; - } else { - return BSP_SD_ERROR; - } - - return BSP_SD_OK; -} - -/** - * @brief Waits a data until a value different from SD_DUMMY_BITE - * @param None - * @retval the value read - */ -uint8_t SD_ReadData(void) { - uint8_t timeout = 0x08; - uint8_t readvalue; - - /* Check if response is got or a timeout is happen */ - do { - readvalue = SD_IO_WriteByte(SD_DUMMY_BYTE); - timeout--; - - } while((readvalue == SD_DUMMY_BYTE) && timeout); - - /* Right response got */ - return readvalue; -} - -/** - * @brief Waits a data from the SD card - * @param data : Expected data from the SD card - * @retval BSP_SD_OK or BSP_SD_TIMEOUT - */ -uint8_t SD_WaitData(uint8_t data) { - uint16_t timeout = 0xFFFF; - uint8_t readvalue; - - /* Check if response is got or a timeout is happen */ - - do { - readvalue = SD_IO_WriteByte(SD_DUMMY_BYTE); - timeout--; - } while((readvalue != data) && timeout); - - if(timeout == 0) { - /* After time out */ - return BSP_SD_TIMEOUT; - } - - /* Right response got */ - return BSP_SD_OK; -} - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/fatfs/stm32_adafruit_sd.h b/firmware/targets/f7/fatfs/stm32_adafruit_sd.h deleted file mode 100644 index a133c5922..000000000 --- a/firmware/targets/f7/fatfs/stm32_adafruit_sd.h +++ /dev/null @@ -1,245 +0,0 @@ -/** - ****************************************************************************** - * @file stm32_adafruit_sd.h - * @author MCD Application Team - * @version V3.0.0 - * @date 23-December-2016 - * @brief This file contains the common defines and functions prototypes for - * the stm32_adafruit_sd.c driver. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32_ADAFRUIT_SD_H -#define __STM32_ADAFRUIT_SD_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include -#include - -/** @addtogroup BSP - * @{ - */ -#define __IO volatile - -/** @addtogroup STM32_ADAFRUIT - * @{ - */ - -/** @defgroup STM32_ADAFRUIT_SD - * @{ - */ - -/** @defgroup STM32_ADAFRUIT_SD_Exported_Types - * @{ - */ - -/** - * @brief SD status structure definition - */ -enum { BSP_SD_OK = 0x00, MSD_OK = 0x00, BSP_SD_ERROR = 0x01, BSP_SD_TIMEOUT }; - -typedef struct { - uint8_t Reserved1 : 2; /* Reserved */ - uint16_t DeviceSize : 12; /* Device Size */ - uint8_t MaxRdCurrentVDDMin : 3; /* Max. read current @ VDD min */ - uint8_t MaxRdCurrentVDDMax : 3; /* Max. read current @ VDD max */ - uint8_t MaxWrCurrentVDDMin : 3; /* Max. write current @ VDD min */ - uint8_t MaxWrCurrentVDDMax : 3; /* Max. write current @ VDD max */ - uint8_t DeviceSizeMul : 3; /* Device size multiplier */ -} struct_v1; - -typedef struct { - uint8_t Reserved1 : 6; /* Reserved */ - uint32_t DeviceSize : 22; /* Device Size */ - uint8_t Reserved2 : 1; /* Reserved */ -} struct_v2; - -/** - * @brief Card Specific Data: CSD Register - */ -typedef struct { - /* Header part */ - uint8_t CSDStruct : 2; /* CSD structure */ - uint8_t Reserved1 : 6; /* Reserved */ - uint8_t TAAC : 8; /* Data read access-time 1 */ - uint8_t NSAC : 8; /* Data read access-time 2 in CLK cycles */ - uint8_t MaxBusClkFrec : 8; /* Max. bus clock frequency */ - uint16_t CardComdClasses : 12; /* Card command classes */ - uint8_t RdBlockLen : 4; /* Max. read data block length */ - uint8_t PartBlockRead : 1; /* Partial blocks for read allowed */ - uint8_t WrBlockMisalign : 1; /* Write block misalignment */ - uint8_t RdBlockMisalign : 1; /* Read block misalignment */ - uint8_t DSRImpl : 1; /* DSR implemented */ - - /* v1 or v2 struct */ - union csd_version { - struct_v1 v1; - struct_v2 v2; - } version; - - uint8_t EraseSingleBlockEnable : 1; /* Erase single block enable */ - uint8_t EraseSectorSize : 7; /* Erase group size multiplier */ - uint8_t WrProtectGrSize : 7; /* Write protect group size */ - uint8_t WrProtectGrEnable : 1; /* Write protect group enable */ - uint8_t Reserved2 : 2; /* Reserved */ - uint8_t WrSpeedFact : 3; /* Write speed factor */ - uint8_t MaxWrBlockLen : 4; /* Max. write data block length */ - uint8_t WriteBlockPartial : 1; /* Partial blocks for write allowed */ - uint8_t Reserved3 : 5; /* Reserved */ - uint8_t FileFormatGrouop : 1; /* File format group */ - uint8_t CopyFlag : 1; /* Copy flag (OTP) */ - uint8_t PermWrProtect : 1; /* Permanent write protection */ - uint8_t TempWrProtect : 1; /* Temporary write protection */ - uint8_t FileFormat : 2; /* File Format */ - uint8_t Reserved4 : 2; /* Reserved */ - uint8_t crc : 7; /* Reserved */ - uint8_t Reserved5 : 1; /* always 1*/ - -} SD_CSD; - -/** - * @brief Card Identification Data: CID Register - */ -typedef struct { - uint8_t ManufacturerID; /* ManufacturerID */ - char OEM_AppliID[2]; /* OEM/Application ID */ - char ProdName[5]; /* Product Name */ - uint8_t ProdRev; /* Product Revision */ - uint32_t ProdSN; /* Product Serial Number */ - uint8_t Reserved1; /* Reserved1 */ - uint8_t ManufactYear; /* Manufacturing Year */ - uint8_t ManufactMonth; /* Manufacturing Month */ - uint8_t CID_CRC; /* CID CRC */ - uint8_t Reserved2; /* always 1 */ -} SD_CID; - -/** - * @brief SD Card information - */ -typedef struct { - SD_CSD Csd; - SD_CID Cid; - uint64_t CardCapacity; /*!< Card Capacity */ - uint32_t CardBlockSize; /*!< Card Block Size */ - uint32_t LogBlockNbr; /*!< Specifies the Card logical Capacity in blocks */ - uint32_t LogBlockSize; /*!< Specifies logical block size in bytes */ -} SD_CardInfo; - -/** - * @} - */ - -/** @defgroup STM32_ADAFRUIT_SPI_SD_Exported_Constants - * @{ - */ - -/** - * @brief Block Size - */ -#define SD_BLOCK_SIZE 0x200 - -/** - * @brief SD detection on its memory slot - */ -#define SD_PRESENT ((uint8_t)0x01) -#define SD_NOT_PRESENT ((uint8_t)0x00) - -#define SD_DATATIMEOUT ((uint32_t)100000000) - -/** - * @brief SD Card information structure - */ -#define BSP_SD_CardInfo SD_CardInfo - -/** - * @} - */ - -/** @defgroup STM32_ADAFRUIT_SD_Exported_Macro - * @{ - */ - -/** - * @} - */ - -/** @defgroup STM32_ADAFRUIT_SD_Exported_Functions - * @{ - */ -uint8_t BSP_SD_MaxMountRetryCount(); -uint8_t BSP_SD_Init(bool reset_card); -uint8_t - BSP_SD_ReadBlocks(uint32_t* pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); -uint8_t - BSP_SD_WriteBlocks(uint32_t* pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); -uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); -uint8_t BSP_SD_GetCardState(void); -uint8_t BSP_SD_GetCardInfo(SD_CardInfo* pCardInfo); -uint8_t BSP_SD_GetCIDRegister(SD_CID* Cid); - -/* Link functions for SD Card peripheral*/ -void SD_SPI_Slow_Init(void); -void SD_SPI_Fast_Init(void); -void SD_IO_Init(void); -void SD_IO_CSState(uint8_t state); -void SD_IO_WriteReadData(const uint8_t* DataIn, uint8_t* DataOut, uint16_t DataLength); -uint8_t SD_IO_WriteByte(uint8_t Data); - -/* Link function for HAL delay */ -void HAL_Delay(__IO uint32_t Delay); - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32_ADAFRUIT_SD_H */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/targets/f7/fatfs/user_diskio.c b/firmware/targets/f7/fatfs/user_diskio.c index b504fcd51..d7be09c53 100644 --- a/firmware/targets/f7/fatfs/user_diskio.c +++ b/firmware/targets/f7/fatfs/user_diskio.c @@ -36,6 +36,7 @@ /* Includes ------------------------------------------------------------------*/ #include "user_diskio.h" #include +#include "sector_cache.h" /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ @@ -46,7 +47,7 @@ static volatile DSTATUS Stat = STA_NOINIT; static DSTATUS User_CheckStatus(BYTE lun) { UNUSED(lun); Stat = STA_NOINIT; - if(BSP_SD_GetCardState() == MSD_OK) { + if(sd_get_card_state() == SdSpiStatusOK) { Stat &= ~STA_NOINIT; } @@ -79,6 +80,26 @@ Diskio_drvTypeDef USER_Driver = { }; /* Private functions ---------------------------------------------------------*/ +static inline bool sd_cache_get(uint32_t address, uint32_t* data) { + uint8_t* cached_data = sector_cache_get(address); + if(cached_data) { + memcpy(data, cached_data, SD_BLOCK_SIZE); + return true; + } + return false; +} + +static inline void sd_cache_put(uint32_t address, uint32_t* data) { + sector_cache_put(address, (uint8_t*)data); +} + +static inline void sd_cache_invalidate_range(uint32_t start_sector, uint32_t end_sector) { + sector_cache_invalidate_range(start_sector, end_sector); +} + +static inline void sd_cache_invalidate_all() { + sector_cache_init(); +} /** * @brief Initializes a Drive @@ -125,19 +146,38 @@ DRESULT USER_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { UNUSED(pdrv); DRESULT res = RES_ERROR; + bool single_sector = count == 1; + + if(single_sector) { + if(sd_cache_get(sector, (uint32_t*)buff)) { + return RES_OK; + } + } + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; - if(BSP_SD_ReadBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) { + if(sd_read_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) == + SdSpiStatusOK) { + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000); + /* wait until the read operation is finished */ - while(BSP_SD_GetCardState() != MSD_OK) { - } res = RES_OK; + while(sd_get_card_state() != SdSpiStatusOK) { + if(furi_hal_cortex_timer_is_expired(timer)) { + res = RES_ERROR; + break; + } + } } furi_hal_sd_spi_handle = NULL; furi_hal_spi_release(&furi_hal_spi_bus_handle_sd_fast); + if(single_sector && res == RES_OK) { + sd_cache_put(sector, (uint32_t*)buff); + } + return res; /* USER CODE END READ */ } @@ -157,14 +197,25 @@ DRESULT USER_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { UNUSED(pdrv); DRESULT res = RES_ERROR; + sd_cache_invalidate_range(sector, sector + count); + furi_hal_spi_acquire(&furi_hal_spi_bus_handle_sd_fast); furi_hal_sd_spi_handle = &furi_hal_spi_bus_handle_sd_fast; - if(BSP_SD_WriteBlocks((uint32_t*)buff, (uint32_t)(sector), count, SD_DATATIMEOUT) == MSD_OK) { + if(sd_write_blocks((uint32_t*)buff, (uint32_t)(sector), count, SD_TIMEOUT_MS) == + SdSpiStatusOK) { + FuriHalCortexTimer timer = furi_hal_cortex_timer_get(SD_TIMEOUT_MS * 1000); + /* wait until the Write operation is finished */ - while(BSP_SD_GetCardState() != MSD_OK) { - } res = RES_OK; + while(sd_get_card_state() != SdSpiStatusOK) { + if(furi_hal_cortex_timer_is_expired(timer)) { + sd_cache_invalidate_all(); + + res = RES_ERROR; + break; + } + } } furi_hal_sd_spi_handle = NULL; @@ -187,7 +238,7 @@ DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) { /* USER CODE BEGIN IOCTL */ UNUSED(pdrv); DRESULT res = RES_ERROR; - BSP_SD_CardInfo CardInfo; + SD_CardInfo CardInfo; if(Stat & STA_NOINIT) return RES_NOTRDY; @@ -202,21 +253,21 @@ DRESULT USER_ioctl(BYTE pdrv, BYTE cmd, void* buff) { /* Get number of sectors on the disk (DWORD) */ case GET_SECTOR_COUNT: - BSP_SD_GetCardInfo(&CardInfo); + sd_get_card_info(&CardInfo); *(DWORD*)buff = CardInfo.LogBlockNbr; res = RES_OK; break; /* Get R/W sector size (WORD) */ case GET_SECTOR_SIZE: - BSP_SD_GetCardInfo(&CardInfo); + sd_get_card_info(&CardInfo); *(WORD*)buff = CardInfo.LogBlockSize; res = RES_OK; break; /* Get erase block size in unit of sector (DWORD) */ case GET_BLOCK_SIZE: - BSP_SD_GetCardInfo(&CardInfo); + sd_get_card_info(&CardInfo); *(DWORD*)buff = CardInfo.LogBlockSize; res = RES_OK; break; diff --git a/firmware/targets/f7/fatfs/user_diskio.h b/firmware/targets/f7/fatfs/user_diskio.h index 177723be1..12e0f27dc 100644 --- a/firmware/targets/f7/fatfs/user_diskio.h +++ b/firmware/targets/f7/fatfs/user_diskio.h @@ -30,7 +30,7 @@ extern "C" { /* USER CODE BEGIN 0 */ /* Includes ------------------------------------------------------------------*/ -#include "stm32_adafruit_sd.h" +#include "sd_spi_io.h" #include "fatfs/ff_gen_drv.h" /* Exported types ------------------------------------------------------------*/ /* Exported constants --------------------------------------------------------*/ diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index ad79ba33a..a887de5cd 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -52,6 +52,7 @@ void furi_hal_init() { furi_hal_version_init(); furi_hal_spi_config_init(); + furi_hal_spi_dma_init(); furi_hal_ibutton_init(); FURI_LOG_I(TAG, "iButton OK"); diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt.c b/firmware/targets/f7/furi_hal/furi_hal_bt.c index 4d2e4bc4e..198bb4454 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt.c @@ -54,25 +54,27 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = { }, }, }, - [FuriHalBtProfileHidKeyboard] = { - .start = furi_hal_bt_hid_start, - .stop = furi_hal_bt_hid_stop, - .config = - { - .adv_service_uuid = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, - .appearance_char = GAP_APPEARANCE_KEYBOARD, - .bonding_mode = true, - .pairing_method = GapPairingPinCodeVerifyYesNo, - .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, - .conn_param = - { - .conn_int_min = 0x18, // 30 ms - .conn_int_max = 0x24, // 45 ms - .slave_latency = 0, - .supervisor_timeout = 0, - }, - }, - }}; + [FuriHalBtProfileHidKeyboard] = + { + .start = furi_hal_bt_hid_start, + .stop = furi_hal_bt_hid_stop, + .config = + { + .adv_service_uuid = HUMAN_INTERFACE_DEVICE_SERVICE_UUID, + .appearance_char = GAP_APPEARANCE_KEYBOARD, + .bonding_mode = true, + .pairing_method = GapPairingPinCodeVerifyYesNo, + .mac_address = FURI_HAL_BT_DEFAULT_MAC_ADDR, + .conn_param = + { + .conn_int_min = 0x18, // 30 ms + .conn_int_max = 0x24, // 45 ms + .slave_latency = 0, + .supervisor_timeout = 0, + }, + }, + }, +}; FuriHalBtProfileConfig* current_profile = NULL; void furi_hal_bt_init() { diff --git a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c index be0bd2af3..4e6dc16c8 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_bt_hid.c @@ -64,6 +64,12 @@ static const uint8_t furi_hal_bt_hid_report_map_data[] = { HID_REPORT_COUNT(1), HID_REPORT_SIZE(8), HID_INPUT(HID_IOF_CONSTANT | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_USAGE_PAGE(HID_PAGE_LED), + HID_REPORT_COUNT(8), + HID_REPORT_SIZE(1), + HID_USAGE_MINIMUM(1), + HID_USAGE_MAXIMUM(8), + HID_OUTPUT(HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_REPORT_COUNT(FURI_HAL_BT_HID_KB_MAX_KEYS), HID_REPORT_SIZE(8), HID_LOGICAL_MINIMUM(0), @@ -196,6 +202,7 @@ void furi_hal_bt_hid_start() { if(!hid_svc_is_started()) { hid_svc_start(); } + // Configure HID Keyboard hid_svc_register_led_state_callback(furi_hal_bt_hid_led_state_cb, &hid_host_led_state); diff --git a/firmware/targets/f7/furi_hal/furi_hal_gpio.c b/firmware/targets/f7/furi_hal/furi_hal_gpio.c index a148a3af2..e8318afcf 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_gpio.c +++ b/firmware/targets/f7/furi_hal/furi_hal_gpio.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #define GET_SYSCFG_EXTI_PORT(gpio) \ @@ -224,85 +225,85 @@ static void furi_hal_gpio_int_call(uint16_t pin_num) { /* Interrupt handlers */ void EXTI0_IRQHandler(void) { if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_0)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0); furi_hal_gpio_int_call(0); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_0); } } void EXTI1_IRQHandler(void) { if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_1)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_1); furi_hal_gpio_int_call(1); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_1); } } void EXTI2_IRQHandler(void) { if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_2)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_2); furi_hal_gpio_int_call(2); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_2); } } void EXTI3_IRQHandler(void) { if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_3)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3); furi_hal_gpio_int_call(3); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3); } } void EXTI4_IRQHandler(void) { if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_4)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4); furi_hal_gpio_int_call(4); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4); } } void EXTI9_5_IRQHandler(void) { if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_5)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5); furi_hal_gpio_int_call(5); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5); } if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_6)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6); furi_hal_gpio_int_call(6); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6); } if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_7)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_7); furi_hal_gpio_int_call(7); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_7); } if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_8)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_8); furi_hal_gpio_int_call(8); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_8); } if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_9)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9); furi_hal_gpio_int_call(9); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9); } } void EXTI15_10_IRQHandler(void) { if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_10)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_10); furi_hal_gpio_int_call(10); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_10); } if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_11)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_11); furi_hal_gpio_int_call(11); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_11); } if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_12)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12); furi_hal_gpio_int_call(12); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_12); } if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_13)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13); furi_hal_gpio_int_call(13); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13); } if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_14)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_14); furi_hal_gpio_int_call(14); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_14); } if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_15)) { - LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_15); furi_hal_gpio_int_call(15); + LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_15); } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c index 0375893e7..c05cd69a8 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_ibutton.c +++ b/firmware/targets/f7/furi_hal/furi_hal_ibutton.c @@ -89,47 +89,16 @@ void furi_hal_ibutton_emulate_stop() { } } -void furi_hal_ibutton_start_drive() { - furi_hal_ibutton_pin_high(); +void furi_hal_ibutton_pin_configure() { + furi_hal_gpio_write(&ibutton_gpio, true); furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); } -void furi_hal_ibutton_start_drive_in_isr() { - furi_hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); - LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin); -} - -void furi_hal_ibutton_start_interrupt() { - furi_hal_ibutton_pin_high(); - furi_hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); -} - -void furi_hal_ibutton_start_interrupt_in_isr() { - furi_hal_gpio_init(&ibutton_gpio, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); - LL_EXTI_ClearFlag_0_31(ibutton_gpio.pin); -} - -void furi_hal_ibutton_stop() { - furi_hal_ibutton_pin_high(); +void furi_hal_ibutton_pin_reset() { + furi_hal_gpio_write(&ibutton_gpio, true); furi_hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } -void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context) { - furi_hal_gpio_add_int_callback(&ibutton_gpio, cb, context); -} - -void furi_hal_ibutton_remove_interrupt() { - furi_hal_gpio_remove_int_callback(&ibutton_gpio); -} - -void furi_hal_ibutton_pin_low() { - furi_hal_gpio_write(&ibutton_gpio, false); -} - -void furi_hal_ibutton_pin_high() { - furi_hal_gpio_write(&ibutton_gpio, true); -} - -bool furi_hal_ibutton_pin_get_level() { - return furi_hal_gpio_read(&ibutton_gpio); +void furi_hal_ibutton_pin_write(const bool state) { + furi_hal_gpio_write(&ibutton_gpio, state); } diff --git a/firmware/targets/f7/furi_hal/furi_hal_ibutton.h b/firmware/targets/f7/furi_hal/furi_hal_ibutton.h index fb57d628b..b723fe176 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_ibutton.h +++ b/firmware/targets/f7/furi_hal/furi_hal_ibutton.h @@ -7,7 +7,6 @@ #include #include -#include #ifdef __cplusplus extern "C" { @@ -18,70 +17,43 @@ typedef void (*FuriHalIbuttonEmulateCallback)(void* context); /** Initialize */ void furi_hal_ibutton_init(); +/** + * Start emulation timer + * @param period timer period + * @param callback timer callback + * @param context callback context + */ void furi_hal_ibutton_emulate_start( uint32_t period, FuriHalIbuttonEmulateCallback callback, void* context); +/** + * Update emulation timer period + * @param period new timer period + */ void furi_hal_ibutton_emulate_set_next(uint32_t period); +/** + * Stop emulation timer + */ void furi_hal_ibutton_emulate_stop(); /** - * Sets the pin to normal mode (open collector), and sets it to float + * Set the pin to normal mode (open collector), and sets it to float */ -void furi_hal_ibutton_start_drive(); - -/** - * Sets the pin to normal mode (open collector), and clears pin EXTI interrupt. - * Used in EXTI interrupt context. - */ -void furi_hal_ibutton_start_drive_in_isr(); - -/** - * Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and sets it to float - */ -void furi_hal_ibutton_start_interrupt(); - -/** - * Sets the pin to interrupt mode (EXTI interrupt on rise or fall), and clears pin EXTI interrupt. - * Used in EXTI interrupt context. - */ -void furi_hal_ibutton_start_interrupt_in_isr(); +void furi_hal_ibutton_pin_configure(); /** * Sets the pin to analog mode, and sets it to float */ -void furi_hal_ibutton_stop(); +void furi_hal_ibutton_pin_reset(); /** - * Attach interrupt callback to iButton pin - * @param cb callback - * @param context context + * iButton write pin + * @param state true / false */ -void furi_hal_ibutton_add_interrupt(GpioExtiCallback cb, void* context); - -/** - * Remove interrupt callback from iButton pin - */ -void furi_hal_ibutton_remove_interrupt(); - -/** - * Sets the pin to low - */ -void furi_hal_ibutton_pin_low(); - -/** - * Sets the pin to high (float in iButton pin modes) - */ -void furi_hal_ibutton_pin_high(); - -/** - * Get pin level - * @return true if level is high - * @return false if level is low - */ -bool furi_hal_ibutton_pin_get_level(); +void furi_hal_ibutton_pin_write(const bool state); #ifdef __cplusplus } diff --git a/firmware/targets/f7/furi_hal/furi_hal_infrared.c b/firmware/targets/f7/furi_hal/furi_hal_infrared.c index 5af43f4e5..b65ea42e1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_infrared.c +++ b/firmware/targets/f7/furi_hal/furi_hal_infrared.c @@ -13,13 +13,6 @@ #include #include -#define INFRARED_TX_DEBUG 0 - -#if INFRARED_TX_DEBUG == 1 -#define gpio_infrared_tx gpio_infrared_tx_debug -const GpioPin gpio_infrared_tx_debug = {.port = GPIOA, .pin = LL_GPIO_PIN_6}; -#endif - #define INFRARED_TIM_TX_DMA_BUFFER_SIZE 200 #define INFRARED_POLARITY_SHIFT 1 @@ -28,6 +21,15 @@ const GpioPin gpio_infrared_tx_debug = {.port = GPIOA, .pin = LL_GPIO_PIN_6}; #define INFRARED_TX_CCMR_LOW \ (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 + typedef struct { FuriHalInfraredRxCaptureCallback capture_callback; void* capture_context; @@ -70,6 +72,7 @@ typedef enum { static volatile InfraredState furi_hal_infrared_state = InfraredStateIdle; static InfraredTimTx infrared_tim_tx; static InfraredTimRx infrared_tim_rx; +static bool infrared_external_output; static void furi_hal_infrared_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_shift); static void furi_hal_infrared_async_tx_free_resources(void); @@ -80,6 +83,14 @@ static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void); static void furi_hal_infrared_tx_dma_polarity_isr(); static void furi_hal_infrared_tx_dma_isr(); +void furi_hal_infrared_set_debug_out(bool enable) { + infrared_external_output = enable; +} + +bool furi_hal_infrared_get_debug_out_status(void) { + return infrared_external_output; +} + static void furi_hal_infrared_tim_rx_isr() { static uint32_t previous_captured_ch2 = 0; @@ -213,15 +224,15 @@ void furi_hal_infrared_async_rx_set_timeout_isr_callback( } static void furi_hal_infrared_tx_dma_terminate(void) { - LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_DisableIT_TC(IR_DMA_CH1_DEF); + LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_DisableIT_TC(IR_DMA_CH2_DEF); furi_assert(furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress); - LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + 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); FuriStatus status = furi_semaphore_release(infrared_tim_tx.stop_semaphore); furi_check(status == FuriStatusOk); @@ -230,7 +241,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(DMA1, LL_DMA_CHANNEL_2); + uint32_t buffer_adr = LL_DMA_GetMemoryAddress(IR_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) { @@ -242,12 +253,13 @@ static uint8_t furi_hal_infrared_get_current_dma_tx_buffer(void) { } static void furi_hal_infrared_tx_dma_polarity_isr() { - if(LL_DMA_IsActiveFlag_TE1(DMA1)) { - LL_DMA_ClearFlag_TE1(DMA1); +#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + if(LL_DMA_IsActiveFlag_TE1(IR_DMA)) { + LL_DMA_ClearFlag_TE1(IR_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_TC1(DMA1) && LL_DMA_IsEnabledIT_TC(DMA1, LL_DMA_CHANNEL_1)) { - LL_DMA_ClearFlag_TC1(DMA1); + if(LL_DMA_IsActiveFlag_TC1(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH1_DEF)) { + LL_DMA_ClearFlag_TC1(IR_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTx) || @@ -257,25 +269,29 @@ static void furi_hal_infrared_tx_dma_polarity_isr() { uint8_t next_buf_num = furi_hal_infrared_get_current_dma_tx_buffer(); furi_hal_infrared_tx_dma_set_polarity(next_buf_num, 0); } +#else +#error Update this code. Would you kindly? +#endif } static void furi_hal_infrared_tx_dma_isr() { - if(LL_DMA_IsActiveFlag_TE2(DMA1)) { - LL_DMA_ClearFlag_TE2(DMA1); +#if IR_DMA_CH2_CHANNEL == LL_DMA_CHANNEL_2 + if(LL_DMA_IsActiveFlag_TE2(IR_DMA)) { + LL_DMA_ClearFlag_TE2(IR_DMA); furi_crash(NULL); } - if(LL_DMA_IsActiveFlag_HT2(DMA1) && LL_DMA_IsEnabledIT_HT(DMA1, LL_DMA_CHANNEL_2)) { - LL_DMA_ClearFlag_HT2(DMA1); + if(LL_DMA_IsActiveFlag_HT2(IR_DMA) && LL_DMA_IsEnabledIT_HT(IR_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_HT2(IR_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(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_DisableIT_HT(IR_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(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_DisableIT_HT(IR_DMA_CH2_DEF); } } else if(furi_hal_infrared_state == InfraredStateAsyncTxStopReq) { /* fallthrough */ @@ -283,8 +299,8 @@ static void furi_hal_infrared_tx_dma_isr() { furi_crash(NULL); } } - if(LL_DMA_IsActiveFlag_TC2(DMA1) && LL_DMA_IsEnabledIT_TC(DMA1, LL_DMA_CHANNEL_2)) { - LL_DMA_ClearFlag_TC2(DMA1); + if(LL_DMA_IsActiveFlag_TC2(IR_DMA) && LL_DMA_IsEnabledIT_TC(IR_DMA_CH2_DEF)) { + LL_DMA_ClearFlag_TC2(IR_DMA); furi_check( (furi_hal_infrared_state == InfraredStateAsyncTxStopInProgress) || (furi_hal_infrared_state == InfraredStateAsyncTxStopReq) || @@ -310,6 +326,9 @@ static void furi_hal_infrared_tx_dma_isr() { infrared_tim_tx.signal_sent_callback(infrared_tim_tx.signal_sent_context); } } +#else +#error Update this code. Would you kindly? +#endif } static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cycle) { @@ -323,25 +342,25 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc LL_TIM_EnableARRPreload(TIM1); LL_TIM_SetAutoReload( TIM1, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM1), freq)); -#if INFRARED_TX_DEBUG == 1 - LL_TIM_OC_SetCompareCH1(TIM1, ((LL_TIM_GetAutoReload(TIM1) + 1) * (1 - duty_cycle))); - LL_TIM_OC_EnablePreload(TIM1, 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); -#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_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); -#endif + 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_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); + } 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_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_DisableMasterSlaveMode(TIM1); LL_TIM_EnableAllOutputs(TIM1); LL_TIM_DisableIT_UPDATE(TIM1); @@ -353,11 +372,11 @@ 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_TX_DEBUG == 1 - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR1); -#else - dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR2); -#endif + if(infrared_external_output) { + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR1); + } else { + dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM1->CCMR2); + } dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL; dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; dma_config.Mode = LL_DMA_MODE_NORMAL; @@ -369,16 +388,19 @@ 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(DMA1, LL_DMA_CHANNEL_1, &dma_config); + LL_DMA_Init(IR_DMA_CH1_DEF, &dma_config); - LL_DMA_ClearFlag_TE1(DMA1); - LL_DMA_ClearFlag_TC1(DMA1); +#if IR_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + LL_DMA_ClearFlag_TE1(IR_DMA); + LL_DMA_ClearFlag_TC1(IR_DMA); +#else +#error Update this code. Would you kindly? +#endif - LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableIT_TE(IR_DMA_CH1_DEF); + LL_DMA_EnableIT_TC(IR_DMA_CH1_DEF); - furi_hal_interrupt_set_isr_ex( - FuriHalInterruptIdDma1Ch1, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); + furi_hal_interrupt_set_isr_ex(IR_DMA_CH1_IRQ, 4, furi_hal_infrared_tx_dma_polarity_isr, NULL); } static void furi_hal_infrared_configure_tim_rcr_dma_tx(void) { @@ -394,18 +416,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(DMA1, LL_DMA_CHANNEL_2, &dma_config); + LL_DMA_Init(IR_DMA_CH2_DEF, &dma_config); - LL_DMA_ClearFlag_TC2(DMA1); - LL_DMA_ClearFlag_HT2(DMA1); - LL_DMA_ClearFlag_TE2(DMA1); +#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); +#else +#error Update this code. Would you kindly? +#endif - LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_2); - LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_EnableIT_TC(IR_DMA_CH2_DEF); + LL_DMA_EnableIT_HT(IR_DMA_CH2_DEF); + LL_DMA_EnableIT_TE(IR_DMA_CH2_DEF); - furi_hal_interrupt_set_isr_ex( - FuriHalInterruptIdDma1Ch2, 5, furi_hal_infrared_tx_dma_isr, NULL); + furi_hal_interrupt_set_isr_ex(IR_DMA_CH2_IRQ, 5, furi_hal_infrared_tx_dma_isr, NULL); } static void furi_hal_infrared_tx_fill_buffer_last(uint8_t buf_num) { @@ -507,14 +532,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(DMA1, LL_DMA_CHANNEL_1); + bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH1_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_DisableChannel(IR_DMA_CH1_DEF); } - LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)buffer->polarity); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, buffer->size + polarity_shift); + LL_DMA_SetMemoryAddress(IR_DMA_CH1_DEF, (uint32_t)buffer->polarity); + LL_DMA_SetDataLength(IR_DMA_CH1_DEF, buffer->size + polarity_shift); if(channel_enabled) { - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableChannel(IR_DMA_CH1_DEF); } FURI_CRITICAL_EXIT(); } @@ -527,14 +552,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(DMA1, LL_DMA_CHANNEL_2); + bool channel_enabled = LL_DMA_IsEnabledChannel(IR_DMA_CH2_DEF); if(channel_enabled) { - LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_DisableChannel(IR_DMA_CH2_DEF); } - LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)buffer->data); - LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, buffer->size); + LL_DMA_SetMemoryAddress(IR_DMA_CH2_DEF, (uint32_t)buffer->data); + LL_DMA_SetDataLength(IR_DMA_CH2_DEF, buffer->size); if(channel_enabled) { - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_EnableChannel(IR_DMA_CH2_DEF); } FURI_CRITICAL_EXIT(); } @@ -544,9 +569,13 @@ static void furi_hal_infrared_async_tx_free_resources(void) { (furi_hal_infrared_state == InfraredStateIdle) || (furi_hal_infrared_state == InfraredStateAsyncTxStopped)); - furi_hal_gpio_init(&gpio_infrared_tx, GpioModeOutputOpenDrain, GpioPullDown, GpioSpeedLow); - furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL); - furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch2, NULL, NULL); + if(infrared_external_output) { + furi_hal_gpio_init(&gpio_ext_pa7, GpioModeOutputOpenDrain, GpioPullDown, GpioSpeedLow); + } else { + furi_hal_gpio_init(&gpio_infrared_tx, GpioModeOutputOpenDrain, 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_semaphore_free(infrared_tim_tx.stop_semaphore); @@ -597,15 +626,27 @@ 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(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_EnableChannel(IR_DMA_CH1_DEF); + LL_DMA_EnableChannel(IR_DMA_CH2_DEF); furi_delay_us(5); LL_TIM_GenerateEvent_UPDATE(TIM1); /* DMA -> TIMx_RCR */ furi_delay_us(5); - LL_GPIO_ResetOutputPin( - gpio_infrared_tx.port, gpio_infrared_tx.pin); /* when disable it prevents false pulse */ - furi_hal_gpio_init_ex( - &gpio_infrared_tx, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1); + if(infrared_external_output) { + LL_GPIO_ResetOutputPin( + gpio_ext_pa7.port, gpio_ext_pa7.pin); /* when disable it prevents false pulse */ + furi_hal_gpio_init_ex( + &gpio_ext_pa7, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1); + } else { + LL_GPIO_ResetOutputPin( + gpio_infrared_tx.port, + gpio_infrared_tx.pin); /* when disable it prevents false pulse */ + furi_hal_gpio_init_ex( + &gpio_infrared_tx, + GpioModeAltFunctionPushPull, + GpioPullUp, + GpioSpeedHigh, + GpioAltFn1TIM1); + } FURI_CRITICAL_ENTER(); LL_TIM_GenerateEvent_UPDATE(TIM1); /* TIMx_RCR -> Repetition counter */ diff --git a/firmware/targets/f7/furi_hal/furi_hal_interrupt.c b/firmware/targets/f7/furi_hal/furi_hal_interrupt.c index 1b1132d0c..b5639d230 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_interrupt.c +++ b/firmware/targets/f7/furi_hal/furi_hal_interrupt.c @@ -74,6 +74,21 @@ __attribute__((always_inline)) static inline void NVIC_EnableIRQ(furi_hal_interrupt_irqn[index]); } +__attribute__((always_inline)) static inline void + furi_hal_interrupt_clear_pending(FuriHalInterruptId index) { + NVIC_ClearPendingIRQ(furi_hal_interrupt_irqn[index]); +} + +__attribute__((always_inline)) static inline void + furi_hal_interrupt_get_pending(FuriHalInterruptId index) { + NVIC_GetPendingIRQ(furi_hal_interrupt_irqn[index]); +} + +__attribute__((always_inline)) static inline void + furi_hal_interrupt_set_pending(FuriHalInterruptId index) { + NVIC_SetPendingIRQ(furi_hal_interrupt_irqn[index]); +} + __attribute__((always_inline)) static inline void furi_hal_interrupt_disable(FuriHalInterruptId index) { NVIC_DisableIRQ(furi_hal_interrupt_irqn[index]); @@ -123,6 +138,7 @@ void furi_hal_interrupt_set_isr_ex( // Pre ISR clear furi_assert(furi_hal_interrupt_isr[index].isr != NULL); furi_hal_interrupt_disable(index); + furi_hal_interrupt_clear_pending(index); } furi_hal_interrupt_isr[index].isr = isr; @@ -131,6 +147,7 @@ void furi_hal_interrupt_set_isr_ex( if(isr) { // Post ISR set + furi_hal_interrupt_clear_pending(index); furi_hal_interrupt_enable(index, priority); } else { // Post ISR clear diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index 2d709620d..dd7c34ae7 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -341,14 +341,14 @@ bool furi_hal_power_is_otg_enabled() { return ret; } -float furi_hal_power_get_battery_charging_voltage() { +float furi_hal_power_get_battery_charge_voltage_limit() { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); float ret = (float)bq25896_get_vreg_voltage(&furi_hal_i2c_handle_power) / 1000.0f; furi_hal_i2c_release(&furi_hal_i2c_handle_power); return ret; } -void furi_hal_power_set_battery_charging_voltage(float voltage) { +void furi_hal_power_set_battery_charge_voltage_limit(float voltage) { furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); // Adding 0.0005 is necessary because 4.016f is 4.015999794000, which gets truncated bq25896_set_vreg_voltage(&furi_hal_i2c_handle_power, (uint16_t)(voltage * 1000.0f + 0.0005f)); @@ -486,7 +486,7 @@ void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context) property_value_out(&property_context, NULL, 2, "format", "major", "2"); property_value_out(&property_context, NULL, 2, "format", "minor", "1"); } else { - property_value_out(&property_context, NULL, 3, "power", "info", "major", "1"); + property_value_out(&property_context, NULL, 3, "power", "info", "major", "2"); property_value_out(&property_context, NULL, 3, "power", "info", "minor", "1"); } @@ -505,8 +505,10 @@ void furi_hal_power_info_get(PropertyValueCallback out, char sep, void* context) } property_value_out(&property_context, NULL, 2, "charge", "state", charge_state); - uint16_t charge_voltage = (uint16_t)(furi_hal_power_get_battery_charging_voltage() * 1000.f); - property_value_out(&property_context, "%u", 2, "charge", "voltage", charge_voltage); + uint16_t charge_voltage_limit = + (uint16_t)(furi_hal_power_get_battery_charge_voltage_limit() * 1000.f); + property_value_out( + &property_context, "%u", 3, "charge", "voltage", "limit", charge_voltage_limit); uint16_t voltage = (uint16_t)(furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge) * 1000.f); property_value_out(&property_context, "%u", 2, "battery", "voltage", voltage); diff --git a/firmware/targets/f7/furi_hal/furi_hal_random.c b/firmware/targets/f7/furi_hal/furi_hal_random.c index 780618052..f36407cc1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_random.c +++ b/firmware/targets/f7/furi_hal/furi_hal_random.c @@ -1,6 +1,7 @@ #include #include #include + #include #include diff --git a/firmware/targets/f7/furi_hal/furi_hal_rfid.c b/firmware/targets/f7/furi_hal/furi_hal_rfid.c index 0ade85e0a..145e49df2 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rfid.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rfid.c @@ -21,6 +21,14 @@ #define RFID_CAPTURE_IND_CH LL_TIM_CHANNEL_CH3 #define RFID_CAPTURE_DIR_CH LL_TIM_CHANNEL_CH4 +/* DMA Channels definition */ +#define RFID_DMA DMA2 +#define RFID_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1 +#define RFID_DMA_CH2_CHANNEL LL_DMA_CHANNEL_2 +#define RFID_DMA_CH1_IRQ FuriHalInterruptIdDma2Ch1 +#define RFID_DMA_CH1_DEF RFID_DMA, RFID_DMA_CH1_CHANNEL +#define RFID_DMA_CH2_DEF RFID_DMA, RFID_DMA_CH2_CHANNEL + typedef struct { FuriHalRfidEmulateCallback callback; FuriHalRfidDMACallback dma_callback; @@ -69,7 +77,7 @@ void furi_hal_rfid_init() { void furi_hal_rfid_pins_reset() { // ibutton bus disable - furi_hal_ibutton_stop(); + furi_hal_ibutton_pin_reset(); // pulldown rfid antenna furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); @@ -86,8 +94,8 @@ void furi_hal_rfid_pins_reset() { void furi_hal_rfid_pins_emulate() { // ibutton low - furi_hal_ibutton_start_drive(); - furi_hal_ibutton_pin_low(); + furi_hal_ibutton_pin_configure(); + furi_hal_ibutton_pin_write(false); // pull pin to timer out furi_hal_gpio_init_ex( @@ -107,8 +115,8 @@ void furi_hal_rfid_pins_emulate() { void furi_hal_rfid_pins_read() { // ibutton low - furi_hal_ibutton_start_drive(); - furi_hal_ibutton_pin_low(); + furi_hal_ibutton_pin_configure(); + furi_hal_ibutton_pin_write(false); // dont pull rfid antenna furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); @@ -302,15 +310,19 @@ void furi_hal_rfid_tim_read_capture_stop() { } static void furi_hal_rfid_dma_isr() { - if(LL_DMA_IsActiveFlag_HT1(DMA1)) { - LL_DMA_ClearFlag_HT1(DMA1); +#if RFID_DMA_CH1_CHANNEL == LL_DMA_CHANNEL_1 + if(LL_DMA_IsActiveFlag_HT1(RFID_DMA)) { + LL_DMA_ClearFlag_HT1(RFID_DMA); furi_hal_rfid->dma_callback(true, furi_hal_rfid->context); } - if(LL_DMA_IsActiveFlag_TC1(DMA1)) { - LL_DMA_ClearFlag_TC1(DMA1); + if(LL_DMA_IsActiveFlag_TC1(RFID_DMA)) { + LL_DMA_ClearFlag_TC1(RFID_DMA); furi_hal_rfid->dma_callback(false, furi_hal_rfid->context); } +#else +#error Update this code. Would you kindly? +#endif } void furi_hal_rfid_tim_emulate_dma_start( @@ -347,8 +359,8 @@ void furi_hal_rfid_tim_emulate_dma_start( dma_config.NbData = length; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; dma_config.Priority = LL_DMA_MODE_NORMAL; - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_Init(RFID_DMA_CH1_DEF, &dma_config); + LL_DMA_EnableChannel(RFID_DMA_CH1_DEF); // configure DMA "mem -> CCR3" channel #if FURI_HAL_RFID_EMULATE_TIMER_CHANNEL == LL_TIM_CHANNEL_CH3 @@ -366,13 +378,13 @@ void furi_hal_rfid_tim_emulate_dma_start( dma_config.NbData = length; dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP; dma_config.Priority = LL_DMA_MODE_NORMAL; - LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config); - LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_Init(RFID_DMA_CH2_DEF, &dma_config); + LL_DMA_EnableChannel(RFID_DMA_CH2_DEF); // attach interrupt to one of DMA channels - furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, furi_hal_rfid_dma_isr, NULL); - LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1); + furi_hal_interrupt_set_isr(RFID_DMA_CH1_IRQ, furi_hal_rfid_dma_isr, NULL); + LL_DMA_EnableIT_TC(RFID_DMA_CH1_DEF); + LL_DMA_EnableIT_HT(RFID_DMA_CH1_DEF); // start LL_TIM_EnableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); @@ -385,14 +397,14 @@ void furi_hal_rfid_tim_emulate_dma_stop() { LL_TIM_DisableCounter(FURI_HAL_RFID_EMULATE_TIMER); LL_TIM_DisableAllOutputs(FURI_HAL_RFID_EMULATE_TIMER); - furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL); - LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_DisableIT_HT(DMA1, LL_DMA_CHANNEL_1); + furi_hal_interrupt_set_isr(RFID_DMA_CH1_IRQ, NULL, NULL); + LL_DMA_DisableIT_TC(RFID_DMA_CH1_DEF); + LL_DMA_DisableIT_HT(RFID_DMA_CH1_DEF); FURI_CRITICAL_ENTER(); - LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_1); - LL_DMA_DeInit(DMA1, LL_DMA_CHANNEL_2); + LL_DMA_DeInit(RFID_DMA_CH1_DEF); + LL_DMA_DeInit(RFID_DMA_CH2_DEF); LL_TIM_DeInit(FURI_HAL_RFID_EMULATE_TIMER); FURI_CRITICAL_EXIT(); @@ -471,4 +483,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_rtc.c b/firmware/targets/f7/furi_hal/furi_hal_rtc.c index 72a2921c1..e011406ad 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_rtc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_rtc.c @@ -409,4 +409,4 @@ uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime) { timestamp += datetime->second; return timestamp; -} \ No newline at end of file +} diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.c b/firmware/targets/f7/furi_hal/furi_hal_subghz.c index d48dd5457..f4e7ad762 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.c +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.c @@ -39,6 +39,7 @@ volatile FuriHalSubGhz furi_hal_subghz = { .radio_type = SubGhzRadioInternal, .spi_bus_handle = &furi_hal_spi_bus_handle_subghz, .cc1101_g0_pin = &gpio_cc1101_g0, + .rolling_counter_mult = 1, }; bool furi_hal_subghz_set_radio_type(SubGhzRadioType state) { @@ -62,6 +63,14 @@ SubGhzRadioType furi_hal_subghz_get_radio_type(void) { return furi_hal_subghz.radio_type; } +uint8_t furi_hal_subghz_get_rolling_counter_mult(void) { + return furi_hal_subghz.rolling_counter_mult; +} + +void furi_hal_subghz_set_rolling_counter_mult(uint8_t mult) { + furi_hal_subghz.rolling_counter_mult = mult; +} + void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin) { furi_hal_subghz.async_mirror_pin = pin; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_subghz.h b/firmware/targets/f7/furi_hal/furi_hal_subghz.h index b19a71f9a..8ede17d32 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_subghz.h +++ b/firmware/targets/f7/furi_hal/furi_hal_subghz.h @@ -77,6 +77,7 @@ typedef struct { SubGhzRadioType radio_type; FuriHalSpiBusHandle* spi_bus_handle; const GpioPin* cc1101_g0_pin; + uint8_t rolling_counter_mult; } FuriHalSubGhz; extern volatile FuriHalSubGhz furi_hal_subghz; @@ -309,6 +310,16 @@ void furi_hal_subghz_enable_ext_power(void); */ void furi_hal_subghz_disable_ext_power(void); +/** Get the current rolling protocols counter ++ value + * @return uint8_t current value + */ +uint8_t furi_hal_subghz_get_rolling_counter_mult(void); + +/** Set the current rolling protocols counter ++ value + * @param mult uint8_t = 1, 2, 4, 8 + */ +void furi_hal_subghz_set_rolling_counter_mult(uint8_t mult); + #ifdef __cplusplus } #endif diff --git a/firmware/targets/f7/src/update.c b/firmware/targets/f7/src/update.c index b223a5dc3..d8d26eb7c 100644 --- a/firmware/targets/f7/src/update.c +++ b/firmware/targets/f7/src/update.c @@ -23,8 +23,8 @@ static FATFS* pfs = NULL; } static bool flipper_update_mount_sd() { - for(int i = 0; i < BSP_SD_MaxMountRetryCount(); ++i) { - if(BSP_SD_Init((i % 2) == 0) != MSD_OK) { + for(int i = 0; i < sd_max_mount_retry_count(); ++i) { + if(sd_init((i % 2) == 0) != SdSpiStatusOK) { /* Next attempt will be without card reset, let it settle */ furi_delay_ms(1000); continue; diff --git a/firmware/targets/furi_hal_include/furi_hal_infrared.h b/firmware/targets/furi_hal_include/furi_hal_infrared.h index 5fcea0661..bac3aba1e 100644 --- a/firmware/targets/furi_hal_include/furi_hal_infrared.h +++ b/firmware/targets/furi_hal_include/furi_hal_infrared.h @@ -48,6 +48,12 @@ typedef void (*FuriHalInfraredRxCaptureCallback)(void* ctx, bool level, uint32_t */ typedef void (*FuriHalInfraredRxTimeoutCallback)(void* ctx); +// Debug TX pin set +void furi_hal_infrared_set_debug_out(bool enable); + +// Debug TX pin get status +bool furi_hal_infrared_get_debug_out_status(void); + /** Initialize INFRARED RX timer to receive interrupts. * * It provides interrupts for every RX-signal edge changing with its duration. diff --git a/firmware/targets/furi_hal_include/furi_hal_power.h b/firmware/targets/furi_hal_include/furi_hal_power.h index 39a11e99f..462e20e41 100644 --- a/firmware/targets/furi_hal_include/furi_hal_power.h +++ b/firmware/targets/furi_hal_include/furi_hal_power.h @@ -121,21 +121,21 @@ void furi_hal_power_check_otg_status(); */ bool furi_hal_power_is_otg_enabled(); -/** Get battery charging voltage in V +/** Get battery charge voltage limit in V * * @return voltage in V */ -float furi_hal_power_get_battery_charging_voltage(); +float furi_hal_power_get_battery_charge_voltage_limit(); -/** Set battery charging voltage in V +/** Set battery charge voltage limit in V * - * Invalid values will be clamped to the nearest valid value. + * Invalid values will be clamped downward to the nearest valid value. * * @param voltage[in] voltage in V * * @return voltage in V */ -void furi_hal_power_set_battery_charging_voltage(float voltage); +void furi_hal_power_set_battery_charge_voltage_limit(float voltage); /** Get remaining battery battery capacity in mAh * diff --git a/furi/core/event_flag.c b/furi/core/event_flag.c index 87de65f2d..9406a581f 100644 --- a/furi/core/event_flag.c +++ b/furi/core/event_flag.c @@ -32,7 +32,7 @@ uint32_t furi_event_flag_set(FuriEventFlag* instance, uint32_t flags) { if(FURI_IS_IRQ_MODE()) { yield = pdFALSE; if(xEventGroupSetBitsFromISR(hEventGroup, (EventBits_t)flags, &yield) == pdFAIL) { - rflags = (uint32_t)FuriStatusErrorResource; + rflags = (uint32_t)FuriFlagErrorResource; } else { rflags = flags; portYIELD_FROM_ISR(yield); diff --git a/furi/core/log.c b/furi/core/log.c index a3967ed92..d910ecf21 100644 --- a/furi/core/log.c +++ b/furi/core/log.c @@ -28,27 +28,27 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form FuriString* string; string = furi_string_alloc(); - const char* color = FURI_LOG_CLR_RESET; + const char* color = _FURI_LOG_CLR_RESET; const char* log_letter = " "; switch(level) { case FuriLogLevelError: - color = FURI_LOG_CLR_E; + color = _FURI_LOG_CLR_E; log_letter = "E"; break; case FuriLogLevelWarn: - color = FURI_LOG_CLR_W; + color = _FURI_LOG_CLR_W; log_letter = "W"; break; case FuriLogLevelInfo: - color = FURI_LOG_CLR_I; + color = _FURI_LOG_CLR_I; log_letter = "I"; break; case FuriLogLevelDebug: - color = FURI_LOG_CLR_D; + color = _FURI_LOG_CLR_D; log_letter = "D"; break; case FuriLogLevelTrace: - color = FURI_LOG_CLR_T; + color = _FURI_LOG_CLR_T; log_letter = "T"; break; default: @@ -58,7 +58,7 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form // Timestamp furi_string_printf( string, - "%lu %s[%s][%s] " FURI_LOG_CLR_RESET, + "%lu %s[%s][%s] " _FURI_LOG_CLR_RESET, furi_log.timestamp(), color, log_letter, @@ -80,6 +80,23 @@ void furi_log_print_format(FuriLogLevel level, const char* tag, const char* form } } +void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) { + if(level <= furi_log.log_level && + furi_mutex_acquire(furi_log.mutex, FuriWaitForever) == FuriStatusOk) { + FuriString* string; + string = furi_string_alloc(); + va_list args; + va_start(args, format); + furi_string_vprintf(string, format, args); + va_end(args); + + furi_log.puts(furi_string_get_cstr(string)); + furi_string_free(string); + + furi_mutex_release(furi_log.mutex); + } +} + void furi_log_set_level(FuriLogLevel level) { if(level == FuriLogLevelDefault) { level = FURI_LOG_LEVEL_DEFAULT; diff --git a/furi/core/log.h b/furi/core/log.h index cb8b3d9cc..46ae7f007 100644 --- a/furi/core/log.h +++ b/furi/core/log.h @@ -22,21 +22,21 @@ typedef enum { FuriLogLevelTrace = 6, } FuriLogLevel; -#define FURI_LOG_CLR(clr) "\033[0;" clr "m" -#define FURI_LOG_CLR_RESET "\033[0m" +#define _FURI_LOG_CLR(clr) "\033[0;" clr "m" +#define _FURI_LOG_CLR_RESET "\033[0m" -#define FURI_LOG_CLR_BLACK "30" -#define FURI_LOG_CLR_RED "31" -#define FURI_LOG_CLR_GREEN "32" -#define FURI_LOG_CLR_BROWN "33" -#define FURI_LOG_CLR_BLUE "34" -#define FURI_LOG_CLR_PURPLE "35" +#define _FURI_LOG_CLR_BLACK "30" +#define _FURI_LOG_CLR_RED "31" +#define _FURI_LOG_CLR_GREEN "32" +#define _FURI_LOG_CLR_BROWN "33" +#define _FURI_LOG_CLR_BLUE "34" +#define _FURI_LOG_CLR_PURPLE "35" -#define FURI_LOG_CLR_E FURI_LOG_CLR(FURI_LOG_CLR_RED) -#define FURI_LOG_CLR_W FURI_LOG_CLR(FURI_LOG_CLR_BROWN) -#define FURI_LOG_CLR_I FURI_LOG_CLR(FURI_LOG_CLR_GREEN) -#define FURI_LOG_CLR_D FURI_LOG_CLR(FURI_LOG_CLR_BLUE) -#define FURI_LOG_CLR_T FURI_LOG_CLR(FURI_LOG_CLR_PURPLE) +#define _FURI_LOG_CLR_E _FURI_LOG_CLR(_FURI_LOG_CLR_RED) +#define _FURI_LOG_CLR_W _FURI_LOG_CLR(_FURI_LOG_CLR_BROWN) +#define _FURI_LOG_CLR_I _FURI_LOG_CLR(_FURI_LOG_CLR_GREEN) +#define _FURI_LOG_CLR_D _FURI_LOG_CLR(_FURI_LOG_CLR_BLUE) +#define _FURI_LOG_CLR_T _FURI_LOG_CLR(_FURI_LOG_CLR_PURPLE) typedef void (*FuriLogPuts)(const char* data); typedef uint32_t (*FuriLogTimestamp)(void); @@ -54,6 +54,15 @@ void furi_log_init(); void furi_log_print_format(FuriLogLevel level, const char* tag, const char* format, ...) _ATTRIBUTE((__format__(__printf__, 3, 4))); +/** Print log record + * + * @param level + * @param format + * @param ... + */ +void furi_log_print_raw_format(FuriLogLevel level, const char* format, ...) + _ATTRIBUTE((__format__(__printf__, 2, 3))); + /** Set log level * * @param[in] level The level @@ -95,6 +104,22 @@ void furi_log_set_timestamp(FuriLogTimestamp timestamp); #define FURI_LOG_T(tag, format, ...) \ furi_log_print_format(FuriLogLevelTrace, tag, format, ##__VA_ARGS__) +/** Log methods + * + * @param format The raw format + * @param ... VA Args + */ +#define FURI_LOG_RAW_E(format, ...) \ + furi_log_print_raw_format(FuriLogLevelError, format, ##__VA_ARGS__) +#define FURI_LOG_RAW_W(format, ...) \ + furi_log_print_raw_format(FuriLogLevelWarn, format, ##__VA_ARGS__) +#define FURI_LOG_RAW_I(format, ...) \ + furi_log_print_raw_format(FuriLogLevelInfo, format, ##__VA_ARGS__) +#define FURI_LOG_RAW_D(format, ...) \ + furi_log_print_raw_format(FuriLogLevelDebug, format, ##__VA_ARGS__) +#define FURI_LOG_RAW_T(format, ...) \ + furi_log_print_raw_format(FuriLogLevelTrace, format, ##__VA_ARGS__) + #ifdef __cplusplus } #endif diff --git a/furi/core/thread.c b/furi/core/thread.c index ef9560b4a..ea9f45e84 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -96,9 +96,9 @@ static void furi_thread_body(void* context) { furi_assert(thread->state == FuriThreadStateRunning); if(thread->is_service) { - FURI_LOG_E( + FURI_LOG_W( TAG, - "%s service thread exited. Thread memory cannot be reclaimed.", + "%s service thread TCB memory will not be reclaimed", thread->name ? thread->name : ""); } @@ -195,6 +195,15 @@ void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority) { thread->priority = priority; } +void furi_thread_set_current_priority(FuriThreadPriority priority) { + UBaseType_t new_priority = priority ? priority : FuriThreadPriorityNormal; + vTaskPrioritySet(NULL, new_priority); +} + +FuriThreadPriority furi_thread_get_current_priority() { + return (FuriThreadPriority)uxTaskPriorityGet(NULL); +} + void furi_thread_set_state_callback(FuriThread* thread, FuriThreadStateCallback callback) { furi_assert(thread); furi_assert(thread->state == FuriThreadStateStopped); diff --git a/furi/core/thread.h b/furi/core/thread.h index 1542d5bf0..2675f7cee 100644 --- a/furi/core/thread.h +++ b/furi/core/thread.h @@ -122,6 +122,18 @@ void furi_thread_set_context(FuriThread* thread, void* context); */ void furi_thread_set_priority(FuriThread* thread, FuriThreadPriority priority); +/** Set current thread priority + * + * @param priority FuriThreadPriority value + */ +void furi_thread_set_current_priority(FuriThreadPriority priority); + +/** Get current thread priority + * + * @return FuriThreadPriority value + */ +FuriThreadPriority furi_thread_get_current_priority(); + /** Set FuriThread state change callback * * @param thread FuriThread instance diff --git a/furi/flipper.c b/furi/flipper.c index 73899e58b..d16a84a10 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -3,6 +3,7 @@ #include #include #include +#include #define TAG "Flipper" @@ -29,10 +30,10 @@ static void flipper_print_version(const char* target, const Version* version) { void flipper_init() { flipper_print_version("Firmware", furi_hal_version_get_firmware_version()); - FURI_LOG_I(TAG, "starting services"); + FURI_LOG_I(TAG, "Boot mode %d, starting services", furi_hal_rtc_get_boot_mode()); for(size_t i = 0; i < FLIPPER_SERVICES_COUNT; i++) { - FURI_LOG_I(TAG, "starting service %s", FLIPPER_SERVICES[i].name); + FURI_LOG_I(TAG, "Starting service %s", FLIPPER_SERVICES[i].name); FuriThread* thread = furi_thread_alloc_ex( FLIPPER_SERVICES[i].name, @@ -44,7 +45,7 @@ void flipper_init() { furi_thread_start(thread); } - FURI_LOG_I(TAG, "services startup complete"); + FURI_LOG_I(TAG, "Startup complete"); } void vApplicationGetIdleTaskMemory( diff --git a/lib/STM32CubeWB.scons b/lib/STM32CubeWB.scons index a1b484ad1..cbdde9814 100644 --- a/lib/STM32CubeWB.scons +++ b/lib/STM32CubeWB.scons @@ -14,15 +14,9 @@ env.Append( "USE_FULL_LL_DRIVER", ], SDK_HEADERS=[ - *env.GlobRecursive( - "*_ll_*.h", - "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/", - exclude="*usb.h", - ), + *env.GlobRecursive("*_ll_*.h", "#/lib/STM32CubeWB/Drivers/STM32WBxx_HAL_Driver/Inc/", exclude="*usb.h"), File("STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h"), - File( - "STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h" - ), + File("STM32CubeWB/Middlewares/Third_Party/FreeRTOS/Source/include/stream_buffer.h"), ], ) diff --git a/lib/drivers/bq25896.c b/lib/drivers/bq25896.c index 7e3008d62..4c1d687cb 100644 --- a/lib/drivers/bq25896.c +++ b/lib/drivers/bq25896.c @@ -140,19 +140,16 @@ uint16_t bq25896_get_vreg_voltage(FuriHalI2cBusHandle* handle) { void bq25896_set_vreg_voltage(FuriHalI2cBusHandle* handle, uint16_t vreg_voltage) { if(vreg_voltage < 3840) { - // Minimum value is 3840 mV - bq25896_regs.r06.VREG = 0; - } else { - // Find the nearest voltage value (subtract offset, divide into sections) - // Values are truncated downward as needed (e.g. 4200mV -> 4192 mV) - bq25896_regs.r06.VREG = (uint8_t)((vreg_voltage - 3840) / 16); + // Minimum valid value is 3840 mV + vreg_voltage = 3840; + } else if(vreg_voltage > 4208) { + // Maximum safe value is 4208 mV + vreg_voltage = 4208; } - // Do not allow values above 23 (0x17, 4208mV) - // Exceeding 4.2v will overcharge the battery! - if(bq25896_regs.r06.VREG > 23) { - bq25896_regs.r06.VREG = 23; - } + // Find the nearest voltage value (subtract offset, divide into sections) + // Values are truncated downward as needed (e.g. 4200mV -> 4192 mV) + bq25896_regs.r06.VREG = (uint8_t)((vreg_voltage - 3840) / 16); // Apply changes furi_hal_i2c_write_reg_8( diff --git a/lib/drivers/bq25896.h b/lib/drivers/bq25896.h index c8a8526a1..f3d1d0e05 100644 --- a/lib/drivers/bq25896.h +++ b/lib/drivers/bq25896.h @@ -36,10 +36,10 @@ void bq25896_disable_otg(FuriHalI2cBusHandle* handle); /** Is otg enabled */ bool bq25896_is_otg_enabled(FuriHalI2cBusHandle* handle); -/** Get VREG (charging) voltage in mV */ +/** Get VREG (charging limit) voltage in mV */ uint16_t bq25896_get_vreg_voltage(FuriHalI2cBusHandle* handle); -/** Set VREG (charging) voltage in mV +/** Set VREG (charging limit) voltage in mV * * Valid range: 3840mV - 4208mV, in steps of 16mV */ diff --git a/lib/drivers/cc1101.c b/lib/drivers/cc1101.c index d563c30c3..d0feb0218 100644 --- a/lib/drivers/cc1101.c +++ b/lib/drivers/cc1101.c @@ -150,9 +150,8 @@ uint8_t cc1101_write_fifo(FuriHalSpiBusHandle* handle, const uint8_t* data, uint } uint8_t cc1101_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* data, uint8_t* size) { - uint8_t buff_tx[64]; - buff_tx[0] = CC1101_FIFO | CC1101_READ | CC1101_BURST; - uint8_t buff_rx[2]; + uint8_t buff_trx[2]; + buff_trx[0] = CC1101_FIFO | CC1101_READ | CC1101_BURST; // Start transaction // Wait IC to become ready @@ -160,15 +159,15 @@ uint8_t cc1101_read_fifo(FuriHalSpiBusHandle* handle, uint8_t* data, uint8_t* si ; // First byte - packet length - furi_hal_spi_bus_trx(handle, buff_tx, buff_rx, 2, CC1101_TIMEOUT); + furi_hal_spi_bus_trx(handle, buff_trx, buff_trx, 2, CC1101_TIMEOUT); // Check that the packet is placed in the receive buffer - if(buff_rx[1] > 64) { + if(buff_trx[1] > 64) { *size = 64; } else { - *size = buff_rx[1]; + *size = buff_trx[1]; } - furi_hal_spi_bus_trx(handle, &buff_tx[1], data, *size, CC1101_TIMEOUT); + furi_hal_spi_bus_trx(handle, NULL, data, *size, CC1101_TIMEOUT); return *size; -} +} \ No newline at end of file diff --git a/lib/misc.scons b/lib/misc.scons index b0afa932a..7a70670d1 100644 --- a/lib/misc.scons +++ b/lib/misc.scons @@ -1,5 +1,7 @@ Import("env") +from fbt.util import GLOB_FILE_EXCLUSION + env.Append( CPPPATH=[ "#/lib/digital_signal", @@ -41,7 +43,11 @@ libs_plain = [ ] for lib in libs_plain: - sources += Glob(lib + "/*.c*", source=True) + sources += Glob( + lib + "/*.c*", + exclude=GLOB_FILE_EXCLUSION, + source=True, + ) lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/one_wire/ibutton/ibutton_worker.c b/lib/one_wire/ibutton/ibutton_worker.c index 9d5ea3897..1fe39b5e5 100644 --- a/lib/one_wire/ibutton/ibutton_worker.c +++ b/lib/one_wire/ibutton/ibutton_worker.c @@ -25,8 +25,8 @@ iButtonWorker* ibutton_worker_alloc() { iButtonWorker* worker = malloc(sizeof(iButtonWorker)); worker->key_p = NULL; worker->key_data = malloc(ibutton_key_get_max_size()); - worker->host = onewire_host_alloc(); - worker->slave = onewire_slave_alloc(); + worker->host = onewire_host_alloc(&ibutton_gpio); + worker->slave = onewire_slave_alloc(&ibutton_gpio); worker->writer = ibutton_writer_alloc(worker->host); worker->device = onewire_device_alloc(0, 0, 0, 0, 0, 0, 0, 0); worker->messages = furi_message_queue_alloc(1, sizeof(iButtonMessage)); diff --git a/lib/one_wire/ibutton/ibutton_worker_modes.c b/lib/one_wire/ibutton/ibutton_worker_modes.c index b284940e7..4f7f0855a 100644 --- a/lib/one_wire/ibutton/ibutton_worker_modes.c +++ b/lib/one_wire/ibutton/ibutton_worker_modes.c @@ -234,16 +234,11 @@ void ibutton_worker_emulate_timer_cb(void* context) { furi_assert(context); iButtonWorker* worker = context; - LevelDuration level = + const LevelDuration level_duration = protocol_dict_encoder_yield(worker->protocols, worker->protocol_to_encode); - furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level)); - - if(level_duration_get_level(level)) { - furi_hal_ibutton_pin_high(); - } else { - furi_hal_ibutton_pin_low(); - } + furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level_duration)); + furi_hal_ibutton_pin_write(level_duration_get_level(level_duration)); } void ibutton_worker_emulate_timer_start(iButtonWorker* worker) { @@ -266,7 +261,7 @@ void ibutton_worker_emulate_timer_start(iButtonWorker* worker) { protocol_dict_set_data(worker->protocols, worker->protocol_to_encode, key_id, key_size); protocol_dict_encoder_start(worker->protocols, worker->protocol_to_encode); - furi_hal_ibutton_start_drive(); + furi_hal_ibutton_pin_configure(); furi_hal_ibutton_emulate_start(0, ibutton_worker_emulate_timer_cb, worker); } diff --git a/lib/one_wire/one_wire_host.c b/lib/one_wire/one_wire_host.c index 654b9e45d..f3d3d3c4d 100644 --- a/lib/one_wire/one_wire_host.c +++ b/lib/one_wire/one_wire_host.c @@ -1,18 +1,19 @@ #include -#include + #include "one_wire_host.h" #include "one_wire_host_timing.h" struct OneWireHost { - // global search state - unsigned char saved_rom[8]; + const GpioPin* gpio_pin; + unsigned char saved_rom[8]; /** < global search state */ uint8_t last_discrepancy; uint8_t last_family_discrepancy; bool last_device_flag; }; -OneWireHost* onewire_host_alloc() { +OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin) { OneWireHost* host = malloc(sizeof(OneWireHost)); + host->gpio_pin = gpio_pin; onewire_host_reset_search(host); return host; } @@ -23,49 +24,47 @@ void onewire_host_free(OneWireHost* host) { } bool onewire_host_reset(OneWireHost* host) { - UNUSED(host); uint8_t r; uint8_t retries = 125; // wait until the gpio is high - furi_hal_ibutton_pin_high(); + furi_hal_gpio_write(host->gpio_pin, true); do { if(--retries == 0) return 0; furi_delay_us(2); - } while(!furi_hal_ibutton_pin_get_level()); + } while(!furi_hal_gpio_read(host->gpio_pin)); // pre delay furi_delay_us(OWH_RESET_DELAY_PRE); // drive low - furi_hal_ibutton_pin_low(); + furi_hal_gpio_write(host->gpio_pin, false); furi_delay_us(OWH_RESET_DRIVE); // release - furi_hal_ibutton_pin_high(); + furi_hal_gpio_write(host->gpio_pin, true); furi_delay_us(OWH_RESET_RELEASE); // read and post delay - r = !furi_hal_ibutton_pin_get_level(); + r = !furi_hal_gpio_read(host->gpio_pin); furi_delay_us(OWH_RESET_DELAY_POST); return r; } bool onewire_host_read_bit(OneWireHost* host) { - UNUSED(host); bool result; // drive low - furi_hal_ibutton_pin_low(); + furi_hal_gpio_write(host->gpio_pin, false); furi_delay_us(OWH_READ_DRIVE); // release - furi_hal_ibutton_pin_high(); + furi_hal_gpio_write(host->gpio_pin, true); furi_delay_us(OWH_READ_RELEASE); // read and post delay - result = furi_hal_ibutton_pin_get_level(); + result = furi_hal_gpio_read(host->gpio_pin); furi_delay_us(OWH_READ_DELAY_POST); return result; @@ -90,22 +89,21 @@ void onewire_host_read_bytes(OneWireHost* host, uint8_t* buffer, uint16_t count) } void onewire_host_write_bit(OneWireHost* host, bool value) { - UNUSED(host); if(value) { // drive low - furi_hal_ibutton_pin_low(); + furi_hal_gpio_write(host->gpio_pin, false); furi_delay_us(OWH_WRITE_1_DRIVE); // release - furi_hal_ibutton_pin_high(); + furi_hal_gpio_write(host->gpio_pin, true); furi_delay_us(OWH_WRITE_1_RELEASE); } else { // drive low - furi_hal_ibutton_pin_low(); + furi_hal_gpio_write(host->gpio_pin, false); furi_delay_us(OWH_WRITE_0_DRIVE); // release - furi_hal_ibutton_pin_high(); + furi_hal_gpio_write(host->gpio_pin, true); furi_delay_us(OWH_WRITE_0_RELEASE); } } @@ -123,13 +121,13 @@ void onewire_host_skip(OneWireHost* host) { } void onewire_host_start(OneWireHost* host) { - UNUSED(host); - furi_hal_ibutton_start_drive(); + furi_hal_gpio_write(host->gpio_pin, true); + furi_hal_gpio_init(host->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); } void onewire_host_stop(OneWireHost* host) { - UNUSED(host); - furi_hal_ibutton_stop(); + furi_hal_gpio_write(host->gpio_pin, true); + furi_hal_gpio_init(host->gpio_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); } void onewire_host_reset_search(OneWireHost* host) { @@ -150,7 +148,7 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code) { host->last_device_flag = false; } -uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSearchMode mode) { +uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode) { uint8_t id_bit_number; uint8_t last_zero, rom_byte_number, search_result; uint8_t id_bit, cmp_id_bit; @@ -259,7 +257,7 @@ uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSear host->last_family_discrepancy = 0; search_result = false; } else { - for(int i = 0; i < 8; i++) newAddr[i] = host->saved_rom[i]; + for(int i = 0; i < 8; i++) new_addr[i] = host->saved_rom[i]; } return search_result; diff --git a/lib/one_wire/one_wire_host.h b/lib/one_wire/one_wire_host.h index 5b55ee8dd..9c01abc11 100644 --- a/lib/one_wire/one_wire_host.h +++ b/lib/one_wire/one_wire_host.h @@ -22,10 +22,10 @@ typedef struct OneWireHost OneWireHost; /** * Allocate onewire host bus - * @param gpio + * @param pin * @return OneWireHost* */ -OneWireHost* onewire_host_alloc(); +OneWireHost* onewire_host_alloc(const GpioPin* gpio_pin); /** * Deallocate onewire host bus @@ -114,7 +114,7 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code); * @param mode * @return uint8_t */ -uint8_t onewire_host_search(OneWireHost* host, uint8_t* newAddr, OneWireHostSearchMode mode); +uint8_t onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearchMode mode); #ifdef __cplusplus } diff --git a/lib/one_wire/one_wire_slave.c b/lib/one_wire/one_wire_slave.c index ad9c34b19..4b54c4f99 100644 --- a/lib/one_wire/one_wire_slave.c +++ b/lib/one_wire/one_wire_slave.c @@ -27,6 +27,7 @@ typedef enum { } OneWireSlaveError; struct OneWireSlave { + const GpioPin* gpio_pin; OneWireSlaveError error; OneWireDevice* device; OneWireSlaveResultCallback result_cb; @@ -35,15 +36,15 @@ struct OneWireSlave { /*********************** PRIVATE ***********************/ -uint32_t onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, const bool pin_value) { - UNUSED(bus); +static uint32_t + onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, const bool pin_value) { uint32_t start = DWT->CYCCNT; uint32_t time_ticks = time * furi_hal_cortex_instructions_per_microsecond(); uint32_t time_captured; do { //-V1044 time_captured = DWT->CYCCNT; - if(furi_hal_ibutton_pin_get_level() != pin_value) { + if(furi_hal_gpio_read(bus->gpio_pin) != pin_value) { uint32_t remaining_time = time_ticks - (time_captured - start); remaining_time /= furi_hal_cortex_instructions_per_microsecond(); return remaining_time; @@ -53,14 +54,14 @@ uint32_t onewire_slave_wait_while_gpio_is(OneWireSlave* bus, uint32_t time, cons return 0; } -bool onewire_slave_show_presence(OneWireSlave* bus) { +static bool onewire_slave_show_presence(OneWireSlave* bus) { // wait while master delay presence check onewire_slave_wait_while_gpio_is(bus, OWS_PRESENCE_TIMEOUT, true); // show presence - furi_hal_ibutton_pin_low(); + furi_hal_gpio_write(bus->gpio_pin, false); furi_delay_us(OWS_PRESENCE_MIN); - furi_hal_ibutton_pin_high(); + furi_hal_gpio_write(bus->gpio_pin, true); // somebody also can show presence const uint32_t wait_low_time = OWS_PRESENCE_MAX - OWS_PRESENCE_MIN; @@ -74,7 +75,7 @@ bool onewire_slave_show_presence(OneWireSlave* bus) { return true; } -bool onewire_slave_receive_bit(OneWireSlave* bus) { +static bool onewire_slave_receive_bit(OneWireSlave* bus) { // wait while bus is low uint32_t time = OWS_SLOT_MAX; time = onewire_slave_wait_while_gpio_is(bus, time, false); @@ -98,7 +99,7 @@ bool onewire_slave_receive_bit(OneWireSlave* bus) { return (time > 0); } -bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { +static bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { const bool write_zero = !value; // wait while bus is low @@ -119,7 +120,7 @@ bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { // choose write time if(write_zero) { - furi_hal_ibutton_pin_low(); + furi_hal_gpio_write(bus->gpio_pin, false); time = OWS_WRITE_ZERO; } else { time = OWS_READ_MAX; @@ -127,12 +128,12 @@ bool onewire_slave_send_bit(OneWireSlave* bus, bool value) { // hold line for ZERO or ONE time furi_delay_us(time); - furi_hal_ibutton_pin_high(); + furi_hal_gpio_write(bus->gpio_pin, true); return true; } -void onewire_slave_cmd_search_rom(OneWireSlave* bus) { +static void onewire_slave_cmd_search_rom(OneWireSlave* bus) { const uint8_t key_bytes = 8; uint8_t* key = onewire_device_get_id_p(bus->device); @@ -151,7 +152,7 @@ void onewire_slave_cmd_search_rom(OneWireSlave* bus) { } } -bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) { +static bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) { uint8_t cmd; onewire_slave_receive(bus, &cmd, 1); @@ -178,14 +179,14 @@ bool onewire_slave_receive_and_process_cmd(OneWireSlave* bus) { } } -bool onewire_slave_bus_start(OneWireSlave* bus) { +static bool onewire_slave_bus_start(OneWireSlave* bus) { bool result = true; if(bus->device == NULL) { result = false; } else { FURI_CRITICAL_ENTER(); - furi_hal_ibutton_start_drive_in_isr(); + furi_hal_gpio_init(bus->gpio_pin, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow); bus->error = NO_ERROR; if(onewire_slave_show_presence(bus)) { @@ -197,7 +198,7 @@ bool onewire_slave_bus_start(OneWireSlave* bus) { result = false; } - furi_hal_ibutton_start_interrupt_in_isr(); + furi_hal_gpio_init(bus->gpio_pin, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); FURI_CRITICAL_EXIT(); } @@ -207,7 +208,7 @@ bool onewire_slave_bus_start(OneWireSlave* bus) { static void exti_cb(void* context) { OneWireSlave* bus = context; - volatile bool input_state = furi_hal_ibutton_pin_get_level(); + volatile bool input_state = furi_hal_gpio_read(bus->gpio_pin); static uint32_t pulse_start = 0; if(input_state) { @@ -234,8 +235,9 @@ static void exti_cb(void* context) { /*********************** PUBLIC ***********************/ -OneWireSlave* onewire_slave_alloc() { +OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin) { OneWireSlave* bus = malloc(sizeof(OneWireSlave)); + bus->gpio_pin = gpio_pin; bus->error = NO_ERROR; bus->device = NULL; bus->result_cb = NULL; @@ -249,14 +251,15 @@ void onewire_slave_free(OneWireSlave* bus) { } void onewire_slave_start(OneWireSlave* bus) { - furi_hal_ibutton_add_interrupt(exti_cb, bus); - furi_hal_ibutton_start_interrupt(); + furi_hal_gpio_add_int_callback(bus->gpio_pin, exti_cb, bus); + furi_hal_gpio_write(bus->gpio_pin, true); + furi_hal_gpio_init(bus->gpio_pin, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedLow); } void onewire_slave_stop(OneWireSlave* bus) { - UNUSED(bus); - furi_hal_ibutton_stop(); - furi_hal_ibutton_remove_interrupt(); + furi_hal_gpio_write(bus->gpio_pin, true); + furi_hal_gpio_init(bus->gpio_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow); + furi_hal_gpio_remove_int_callback(bus->gpio_pin); } void onewire_slave_attach(OneWireSlave* bus, OneWireDevice* device) { @@ -282,7 +285,7 @@ void onewire_slave_set_result_callback( bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t data_length) { uint8_t bytes_sent = 0; - furi_hal_ibutton_pin_high(); + furi_hal_gpio_write(bus->gpio_pin, true); // bytes loop for(; bytes_sent < data_length; ++bytes_sent) { @@ -304,7 +307,7 @@ bool onewire_slave_send(OneWireSlave* bus, const uint8_t* address, const uint8_t bool onewire_slave_receive(OneWireSlave* bus, uint8_t* data, const uint8_t data_length) { uint8_t bytes_received = 0; - furi_hal_ibutton_pin_high(); + furi_hal_gpio_write(bus->gpio_pin, true); for(; bytes_received < data_length; ++bytes_received) { uint8_t value = 0; diff --git a/lib/one_wire/one_wire_slave.h b/lib/one_wire/one_wire_slave.h index 82e9f5523..2e5db3a1c 100644 --- a/lib/one_wire/one_wire_slave.h +++ b/lib/one_wire/one_wire_slave.h @@ -19,10 +19,10 @@ typedef void (*OneWireSlaveResultCallback)(void* context); /** * Allocate onewire slave - * @param pin + * @param gpio_pin * @return OneWireSlave* */ -OneWireSlave* onewire_slave_alloc(); +OneWireSlave* onewire_slave_alloc(const GpioPin* gpio_pin); /** * Free onewire slave diff --git a/lib/subghz/blocks/generic.c b/lib/subghz/blocks/generic.c index 3d59adc82..54a401e05 100644 --- a/lib/subghz/blocks/generic.c +++ b/lib/subghz/blocks/generic.c @@ -78,6 +78,16 @@ bool subghz_block_generic_serialize( FURI_LOG_E(TAG, "Unable to add Key"); break; } + + // Nice One - Manual adding support + if(instance->data_count_bit == 72 && + (strcmp(instance->protocol_name, "Nice FloR-S") == 0)) { + uint32_t temp = (instance->data_2 >> 4) & 0xFFFFF; + if(!flipper_format_write_uint32(flipper_format, "Data", &temp, 1)) { + FURI_LOG_E(TAG, "Unable to add Data"); + break; + } + } res = true; } while(false); furi_string_free(temp_str); diff --git a/lib/subghz/helpers/subghz_config_preset_custom.c b/lib/subghz/helpers/subghz_config_preset_custom.c deleted file mode 100644 index 73b732d48..000000000 --- a/lib/subghz/helpers/subghz_config_preset_custom.c +++ /dev/null @@ -1,326 +0,0 @@ -#include "subghz_config_preset_custom.h" - -#include -#include -#include // UNUSED() -#include // furi_assert() -#include // log2(), floor() - -#include - -// https://www.ti.com/lit/ds/symlink/cc1101.pdf?ts=1671943815135 -// page 35. -// 12 Data Rate Programming -// -#define DATARATE_FUNC_CHIP_FOSC 26000000.0 /* 26MHz */ -#define DATARATE_FUNC_DIVIDER (1 << 28) /* 2 pow 28 */ -#define DATARATE_FUNC_MULTIPLIER \ - (DATARATE_FUNC_CHIP_FOSC / DATARATE_FUNC_DIVIDER) /* should be 0.09685754 */ - -#define DATARATE_EXP_FORMULA_DIVISIBLE (1 << 20) /* 2 pow 20 */ -#define DATARATE_EXP_FORMULA_MULTIPLIER \ - (DATARATE_EXP_FORMULA_DIVISIBLE / DATARATE_FUNC_CHIP_FOSC) /* should be 0.04032984 */ - -#define DATARATE_MNT_FORMULA_DIVISIBLE (1 << 28) /* 2 pow 28 */ -#define DATARATE_MNT_FORMULA_MULTIPLIER \ - (DATARATE_MNT_FORMULA_DIVISIBLE / DATARATE_FUNC_CHIP_FOSC) /* should be 10.3244406 */ -// - -#define SUGHZ_CONFIG_TAG "SubGHz_Config" - -uint8_t furi_hal_subghz_preset_ook_custom_async_regs[PRESET_OOK_CUSTOM_ADVANCED_AM_SIZE] = {0}; - -/** Check if cursom preset is AM (OOK) modulation - * - * This will check MOD_FORMAT bits in CC1101_MDMCFG2 register - * If preset data doesn have this register - will return false. - * This function will not fail in any case - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -bool subghz_preset_custom_is_ook_modulation(const uint8_t* preset_data, uint8_t data_len) { - if(preset_data != NULL) { - for(uint8_t i = 2; i <= data_len; i += 2) { - if(preset_data[i - 2] == CC1101_MDMCFG2) { - return (preset_data[i - 1] & 0b01110000) == 0x30; - } - } - } - return false; -} - -/** Get bandwidth value from preset data. - * - * This will get HIGHER bits in CC1101_MDMCFG4 register - * If CC1101_MDMCFG4 is not found in preset data - will return - * CH_BANDWIDTH_INVALID (0xFF) - * If there is ANY low 4 bits in returned value - the value is invalid - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -uint8_t subghz_preset_custom_get_bandwidth(const uint8_t* preset_data, uint8_t data_len) { - if(preset_data != NULL) { - for(uint8_t i = 2; i <= data_len; i += 2) { - if(preset_data[i - 2] == CC1101_MDMCFG4) { - return (preset_data[i - 1] & 0b11110000); - } - } - } - return CH_BANDWIDTH_INVALID; -} - -/** Set bandwidth value to preset data. - * - * This will set HIGHER bits in CC1101_MDMCFG4 register - * If CC1101_MDMCFG4 is not found in preset data - will do nothing and return false - * If there are ANY low 4 bits in provided value - they will be ignored - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - * @param value New bandwidth value. See macros definition for possible values - */ -bool subghz_preset_custom_set_bandwidth(uint8_t* preset_data, uint8_t data_len, uint8_t value) { - if(preset_data != NULL) { - for(uint8_t i = 2; i <= data_len; i += 2) { - if(preset_data[i - 2] == CC1101_MDMCFG4) { - preset_data[i - 1] = (preset_data[i - 1] & 0b00001111) | (0b11110000 & value); - return true; - } - } - } - return false; -} - -/** Get data rate value from preset data. - * - * This will get DRATE_M and DRATE_E bits from CC1101_MDMCFG3 and CC1101_MDMCFG4 registers - * and calculate the value for 26MHz chip oscillator by formula from datasheet. - * - * If CC1101_MDMCFG[3:4] are not found in preset data - will return `-1` - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -float subghz_preset_custom_get_datarate(const uint8_t* preset_data, uint8_t data_len) { - if(preset_data != NULL) { - uint8_t mantissa = 0xFF; - uint8_t exponent = 0xFF; // Invalid, only 4 lower bits are singificant - - uint8_t step = 0; - - for(uint8_t i = 2; i <= data_len && step < 2; i += 2) { - if(preset_data[i - 2] == CC1101_MDMCFG4) { - exponent = preset_data[i - 1] & 0b00001111; - step++; - } else if(preset_data[i - 2] == CC1101_MDMCFG3) { - mantissa = preset_data[i - 1]; - step++; - } - } - - if(step == 2) { - return (float)((256 + mantissa) * (1 << exponent) * DATARATE_FUNC_MULTIPLIER); - } - } - return -1; -} - -/** Set data rate value to preset data. - * - * This will update DRATE_M and DRATE_E bits from CC1101_MDMCFG3 and CC1101_MDMCFG4 registers - * with calculated values for 26MHz chip oscillator by formula from datasheet. - * - * If CC1101_MDMCFG[3:4] are not found in preset data - will return false - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - * @param value value in kBaud - */ -bool subghz_preset_custom_set_datarate(uint8_t* preset_data, uint8_t data_len, float value) { - if(preset_data != NULL) { - uint8_t* pMantissa = NULL; - uint8_t* pExponent = NULL; - - uint8_t step = 0; - for(uint8_t i = 2; i <= data_len && step < 2; i += 2) { - if(preset_data[i - 2] == CC1101_MDMCFG4) { - pExponent = &preset_data[i - 1]; - step++; - } else if(preset_data[i - 2] == CC1101_MDMCFG3) { - pMantissa = &preset_data[i - 1]; - step++; - } - } - - // Has both registers in data - calculate values - if(step == 2) { - // │ value * 2^20 │ - // DRATE_E = │log2(──────────────)│ - // └ Fosc ┘ - - double exponent = floor(log2(value * DATARATE_EXP_FORMULA_MULTIPLIER)); - uint8_t datarate_e = (uint8_t)exponent; - - // value * 2^28 - // DRATE_M = (────────────────────) - 256 - // Fosc * 2^DRATE_E - double mantissa = - floor((value * DATARATE_MNT_FORMULA_MULTIPLIER) / (1 << datarate_e) + 0.5) - 256; - - // If DRATE_M is rounded to the nearest integer and becomes 256, increment DRATE_E and use DRATE_M = 0. - if(mantissa >= 256) { - mantissa = 0; - datarate_e += 1; - } - uint8_t datarate_m = (uint8_t)mantissa; - - *pExponent = (*pExponent & 0b11110000) | (datarate_e & 0b00001111); - *pMantissa = datarate_m; - - return true; - } - } - - return false; -} - -/** Print datarate value to string - * - * This is just convenience function - * - * @param datarate datarate obtained from `subghz_preset_custom_get_datarate` function - * @param string Target print buffer - * @param size Target print buffer size - */ -void subghz_preset_custom_printf_datarate(float datarate, char* string, uint8_t size) { - float kBaudRate = datarate / 1000.0f; - snprintf( - string, - size, - "%lu.%02lu kBd", - (uint32_t)(kBaudRate), // decimal part - (uint32_t)((kBaudRate - (uint32_t)kBaudRate) * 100) // fractional part multiplied by 100 - ); -} - -/** Get Manchester encoding/decoding flag value from preset data. - * - * This will get MANCHESTER_EN (3-rd) bit in CC1101_MDMCFG2 register - * If CC1101_MDMCFG2 is not found in preset data - will return false - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -bool subghz_preset_custom_get_machester_enable(const uint8_t* preset_data, uint8_t data_len) { - if(preset_data != NULL) { - for(uint8_t i = 2; i <= data_len; i += 2) { - if(preset_data[i - 2] == CC1101_MDMCFG2) { - return (preset_data[i - 1] & 0b00001000); - } - } - } - return false; -} - -/** Set Manchester encoding/decoding flag value to preset data. - * - * This will set MANCHESTER_EN (3-rd) bit in CC1101_MDMCFG2 register - * If CC1101_MDMCFG2 is not found in preset data - will return false - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -bool subghz_preset_custom_set_machester_enable(uint8_t* preset_data, uint8_t data_len, bool value) { - if(preset_data != NULL) { - for(uint8_t i = 2; i <= data_len; i += 2) { - if(preset_data[i - 2] == CC1101_MDMCFG2) { - preset_data[i - 1] = (preset_data[i - 1] & 0b11110111) | (0b00001000 * value); - return true; - } - } - } - return false; -} - -/** - * Initialize custom preset data - */ -void subghz_preset_custom_init_advanced_am_preset() { - FURI_LOG_D(SUGHZ_CONFIG_TAG, "Initializing AM preset with custom Modem configuration"); - - if(furi_hal_subghz_preset_ook_custom_async_regs[0]) { - // already initialized - FURI_LOG_D(SUGHZ_CONFIG_TAG, "Already initialized"); - return; - } - - // Copy default AM270 preset - memcpy( - &furi_hal_subghz_preset_ook_custom_async_regs, - &furi_hal_subghz_preset_ook_270khz_async_regs, - sizeof(furi_hal_subghz_preset_ook_270khz_async_regs)); - - const uint8_t ModemConfigStart = 4; - -#if FURI_DEBUG - const uint8_t ModemConfigEnd = ModemConfigStart + MODEM_CONFIG_REGISTERS_COUNT; - for(uint8_t i = ModemConfigStart; i < ModemConfigEnd; ++i) { - // Check we'll overwrite correct settings - furi_assert( - furi_hal_subghz_preset_ook_custom_async_regs[i * 2 + 0] == - furi_hal_subghz_custom_modulation_regs[i - ModemConfigStart][0]); - } -#endif - - // Copy CUSTOM Modem preset - memcpy( - &furi_hal_subghz_preset_ook_custom_async_regs[ModemConfigStart * 2], - &furi_hal_subghz_custom_modulation_regs, - sizeof(furi_hal_subghz_custom_modulation_regs)); - - // Copy default AM270 patable - memcpy( - &furi_hal_subghz_preset_ook_custom_async_regs[sizeof( - furi_hal_subghz_preset_ook_270khz_async_regs)], - &furi_hal_subghz_preset_ook_async_patable, - sizeof(furi_hal_subghz_preset_ook_async_patable)); - - // Here at the end we should have - // 00 00 - -#if FURI_DEBUG - FURI_LOG_D(SUGHZ_CONFIG_TAG, "Custom OOK preset created"); - - for(uint8_t i = 0; i < PRESET_OOK_CUSTOM_ADVANCED_AM_SIZE; i += 2) { - FURI_LOG_D( - SUGHZ_CONFIG_TAG, - "Register: 0x%hhX, Value: 0x%hhX", - furi_hal_subghz_preset_ook_custom_async_regs[i * 2 + 0], - furi_hal_subghz_preset_ook_custom_async_regs[i * 2 + 1]); - } -#endif - - FURI_LOG_D(SUGHZ_CONFIG_TAG, "Done"); -} - -/** - * Create subghz preset file with custom am preset - * this is used for preset initialization if subghz app - */ -FlipperFormat* subghz_preset_custom_advanced_am_preset_alloc() { - FlipperFormat* advanced_am_preset = flipper_format_string_alloc(); - - subghz_preset_custom_init_advanced_am_preset(); - - flipper_format_write_hex( - advanced_am_preset, - (const char*)"Custom_preset_data", - (const uint8_t*)&furi_hal_subghz_preset_ook_custom_async_regs[0], - sizeof(furi_hal_subghz_preset_ook_custom_async_regs)); - - flipper_format_rewind(advanced_am_preset); - - return advanced_am_preset; -} \ No newline at end of file diff --git a/lib/subghz/helpers/subghz_config_preset_custom.h b/lib/subghz/helpers/subghz_config_preset_custom.h deleted file mode 100644 index 318197f5d..000000000 --- a/lib/subghz/helpers/subghz_config_preset_custom.h +++ /dev/null @@ -1,193 +0,0 @@ -#pragma once - -#include -#include /* memcpy() */ - -#define ADVANCED_AM_PRESET_NAME "AM*" - -// Awailable bandwidth values -// Setup in MDMCFG4 register -#define CH_BANDWIDTH_058 0b11110000 -#define CH_BANDWIDTH_068 0b11100000 -#define CH_BANDWIDTH_081 0b11010000 -#define CH_BANDWIDTH_102 0b11000000 - -#define CH_BANDWIDTH_116 0b10110000 -#define CH_BANDWIDTH_135 0b10100000 -#define CH_BANDWIDTH_162 0b10010000 -#define CH_BANDWIDTH_203 0b10000000 - -#define CH_BANDWIDTH_232 0b01110000 -#define CH_BANDWIDTH_270 0b01100000 -#define CH_BANDWIDTH_325 0b01010000 -#define CH_BANDWIDTH_406 0b01000000 - -#define CH_BANDWIDTH_464 0b00110000 -#define CH_BANDWIDTH_541 0b00100000 -#define CH_BANDWIDTH_650 0b00010000 -#define CH_BANDWIDTH_812 0b00000000 - -#define CH_BANDWIDTH_INVALID 0xFF - -static const uint8_t subghz_preset_custom_bandwidth_values[] = { - CH_BANDWIDTH_058, - CH_BANDWIDTH_068, - CH_BANDWIDTH_081, - CH_BANDWIDTH_102, - - CH_BANDWIDTH_116, - CH_BANDWIDTH_135, - CH_BANDWIDTH_162, - CH_BANDWIDTH_203, - - CH_BANDWIDTH_232, - CH_BANDWIDTH_270, - CH_BANDWIDTH_325, - CH_BANDWIDTH_406, - - CH_BANDWIDTH_464, - CH_BANDWIDTH_541, - CH_BANDWIDTH_650, - CH_BANDWIDTH_812, -}; -#define CH_BANDWIDTH_NUM (sizeof(subghz_preset_custom_bandwidth_values) / sizeof(uint8_t)) - -#define DATARATE_EXPONENT_3_79_kBaud 0b00000111 // 7 -#define DATARATE_MANTISSA_3_79_kBaud 0x32 - -#define CHANNEL_SPACING_25_EXPONENT 0b00000000 /* last bit */ -#define CHANNEL_SPACING_25_MANTISSA 0x00 - -#define MODEM_CONFIG_REGISTERS_COUNT 5 -#define PRESET_OOK_CUSTOM_ADVANCED_AM_SIZE \ - sizeof(furi_hal_subghz_preset_ook_270khz_async_regs) + \ - sizeof(furi_hal_subghz_preset_ook_async_patable) - -extern uint8_t furi_hal_subghz_preset_ook_custom_async_regs[PRESET_OOK_CUSTOM_ADVANCED_AM_SIZE]; - -static const uint8_t furi_hal_subghz_custom_modulation_regs[MODEM_CONFIG_REGISTERS_COUNT][2] = { - // Channel spacing is 25kHz, no Forward Error Correction, 2 preamble bytes (will be ignored) - {CC1101_MDMCFG0, CHANNEL_SPACING_25_MANTISSA}, - {CC1101_MDMCFG1, 0x00 | CHANNEL_SPACING_25_EXPONENT}, - - // [0:2] SYNC_MODE = 00 // No preamble/sync - // [3:3] MANCHESTER_EN = 0 // Disable - // [4:6] MOD_FORMAT = 03 // Format ASK/OOK - // [7:7] DEM_DCFILT_OFF = 0 // Enable - {CC1101_MDMCFG2, 0x30}, - - // 3.79 kBaud data rate (mantissa in 3rd register) - {CC1101_MDMCFG3, DATARATE_MANTISSA_3_79_kBaud}, - - // 270.8333 kHz Rx BW filer (hi) and 3.79 kBaud data rate (exponent in 4th register) - {CC1101_MDMCFG4, DATARATE_EXPONENT_3_79_kBaud | CH_BANDWIDTH_270}, -}; - -#ifdef __cplusplus -extern "C" { -#endif - -/** Check if cursom preset is AM (OOK) modulation - * - * This will check MOD_FORMAT bits in CC1101_MDMCFG2 register - * If preset data doesn have this register - will return false. - * This function will not fail in any case - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -bool subghz_preset_custom_is_ook_modulation(const uint8_t* preset_data, uint8_t data_len); - -/** Get bandwidth value from preset data. - * - * This will get HIGHER bits in CC1101_MDMCFG4 register - * If CC1101_MDMCFG4 is not found in preset data - will return - * CH_BANDWIDTH_INVALID (0xFF) - * If there is ANY low 4 bits in returned value - the value is invalid - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -uint8_t subghz_preset_custom_get_bandwidth(const uint8_t* preset_data, uint8_t data_len); - -/** Set bandwidth value to preset data. - * - * This will set HIGHER bits in CC1101_MDMCFG4 register - * If CC1101_MDMCFG4 is not found in preset data - will do nothing and return false - * If there are ANY low 4 bits in provided value - they will be ignored - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - * @param value New bandwidth value. See macros definition for possible values - */ -bool subghz_preset_custom_set_bandwidth(uint8_t* preset_data, uint8_t data_len, uint8_t value); - -/** Get data rate value from preset data. - * - * This will get DRATE_M and DRATE_E bits from CC1101_MDMCFG3 and CC1101_MDMCFG4 registers - * and calculate the value for 26MHz chip oscillator by formula from datasheet. - * - * If CC1101_MDMCFG[3:4] are not found in preset data - will return `-1` - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -float subghz_preset_custom_get_datarate(const uint8_t* preset_data, uint8_t data_len); - -/** Set data rate value to preset data. - * - * This will update DRATE_M and DRATE_E bits from CC1101_MDMCFG3 and CC1101_MDMCFG4 registers - * with calculated values for 26MHz chip oscillator by formula from datasheet. - * - * If CC1101_MDMCFG[3:4] are not found in preset data - will return false - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - * @param value value in kBaud - */ -bool subghz_preset_custom_set_datarate(uint8_t* preset_data, uint8_t data_len, float value); - -/** Print datarate value to string - * - * This is just conviniece function - * - * @param datarate datarate obtained from `subghz_preset_custom_get_datarate` function - * @param string Target print buffer - * @param size Target print buffer size - */ -void subghz_preset_custom_printf_datarate(float datarate, char* string, uint8_t size); - -/** Get Manchester encoding/decoding flag value from preset data. - * - * This will get MANCHESTER_EN (3-rd) bit in CC1101_MDMCFG2 register - * If CC1101_MDMCFG2 is not found in preset data - will return false - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -bool subghz_preset_custom_get_machester_enable(const uint8_t* preset_data, uint8_t data_len); - -/** Set Manchester encoding/decoding flag value to preset data. - * - * This will set MANCHESTER_EN (3-rd) bit in CC1101_MDMCFG2 register - * If CC1101_MDMCFG2 is not found in preset data - will return false - * - * @param preset_data Custom preset data (registers and patable) - * @param data_len Data length - */ -bool subghz_preset_custom_set_machester_enable(uint8_t* preset_data, uint8_t data_len, bool value); - -/** - * Initialize advanced am custom preset - */ -void subghz_preset_custom_init_advanced_am_preset(); - -/** - * Create subghz preset file with custom am preset - * this is used for preset initialization if subghz app - */ -struct FlipperFormat* subghz_preset_custom_advanced_am_preset_alloc(); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/lib/subghz/protocols/alutech_at_4n.c b/lib/subghz/protocols/alutech_at_4n.c index ab2ff0b31..15887cd6d 100644 --- a/lib/subghz/protocols/alutech_at_4n.c +++ b/lib/subghz/protocols/alutech_at_4n.c @@ -77,6 +77,25 @@ const SubGhzProtocol subghz_protocol_alutech_at_4n = { .encoder = &subghz_protocol_alutech_at_4n_encoder, }; +static uint8_t al_btn_temp_id; +static uint8_t al_btn_temp_id_original; + +void alutech_set_btn(uint8_t b) { + al_btn_temp_id = b; +} + +uint8_t alutech_get_original_btn() { + return al_btn_temp_id_original; +} + +uint8_t alutech_get_custom_btn() { + return al_btn_temp_id; +} + +void alutech_reset_original_btn() { + al_btn_temp_id_original = 0; +} + void* subghz_protocol_encoder_alutech_at_4n_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolEncoderAlutech_at_4n* instance = @@ -255,8 +274,6 @@ static uint64_t subghz_protocol_alutech_at_4n_encrypt(uint64_t data, const char* static bool subghz_protocol_alutech_at_4n_gen_data( SubGhzProtocolEncoderAlutech_at_4n* instance, uint8_t btn) { - UNUSED(btn); - uint64_t data = subghz_protocol_blocks_reverse_key(instance->generic.data, 64); data = subghz_protocol_alutech_at_4n_decrypt( @@ -269,13 +286,17 @@ static bool subghz_protocol_alutech_at_4n_gen_data( } if(instance->generic.cnt < 0xFFFF) { - instance->generic.cnt++; + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } else if(instance->generic.cnt >= 0xFFFF) { instance->generic.cnt = 0; } crc = subghz_protocol_alutech_at_4n_decrypt_data_crc((uint8_t)(instance->generic.cnt & 0xFF)); data = (uint64_t)crc << 56 | (uint64_t)instance->generic.serial << 24 | - (uint32_t)instance->generic.cnt << 8 | instance->generic.btn; + (uint32_t)instance->generic.cnt << 8 | btn; data = subghz_protocol_alutech_at_4n_encrypt( data, instance->alutech_at_4n_rainbow_table_file_name); @@ -306,7 +327,7 @@ bool subghz_protocol_alutech_at_4n_create_data( /** * Generating an upload from data. - * @param instance Pointer to a SubGhzProtocolEncoderKeeloq instance + * @param instance Pointer to a SubGhzProtocolEncoderAlutech instance * @return true On success */ static bool subghz_protocol_encoder_alutech_at_4n_get_upload( @@ -314,6 +335,104 @@ static bool subghz_protocol_encoder_alutech_at_4n_get_upload( uint8_t btn) { furi_assert(instance); + // Save original button for later use + if(al_btn_temp_id_original == 0) { + al_btn_temp_id_original = btn; + } + + // Set custom button + if(al_btn_temp_id == 1) { + switch(al_btn_temp_id_original) { + case 0x11: + btn = 0x22; + break; + case 0x22: + btn = 0x11; + break; + case 0xFF: + btn = 0x11; + break; + case 0x44: + btn = 0x11; + break; + case 0x33: + btn = 0x11; + break; + + default: + break; + } + } + if(al_btn_temp_id == 2) { + switch(al_btn_temp_id_original) { + case 0x11: + btn = 0x44; + break; + case 0x22: + btn = 0x44; + break; + case 0xFF: + btn = 0x44; + break; + case 0x44: + btn = 0xFF; + break; + case 0x33: + btn = 0x44; + break; + + default: + break; + } + } + if(al_btn_temp_id == 3) { + switch(al_btn_temp_id_original) { + case 0x11: + btn = 0x33; + break; + case 0x22: + btn = 0x33; + break; + case 0xFF: + btn = 0x33; + break; + case 0x44: + btn = 0x33; + break; + case 0x33: + btn = 0x22; + break; + + default: + break; + } + } + if(al_btn_temp_id == 4) { + switch(al_btn_temp_id_original) { + case 0x11: + btn = 0xFF; + break; + case 0x22: + btn = 0xFF; + break; + case 0xFF: + btn = 0x22; + break; + case 0x44: + btn = 0x22; + break; + case 0x33: + btn = 0xFF; + break; + + default: + break; + } + } + + if((al_btn_temp_id == 0) && (al_btn_temp_id_original != 0)) { + btn = al_btn_temp_id_original; + } //gen new key if(subghz_protocol_alutech_at_4n_gen_data(instance, btn)) { //ToDo if you need to add a callback to automatically update the data on the display @@ -608,6 +727,11 @@ static void subghz_protocol_alutech_at_4n_remote_controller( instance->cnt = 0; instance->serial = 0; } + + // Save original button for later use + if(al_btn_temp_id_original == 0) { + al_btn_temp_id_original = instance->btn; + } } uint8_t subghz_protocol_decoder_alutech_at_4n_get_hash_data(void* context) { @@ -682,4 +806,4 @@ void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* instance->generic.serial, instance->generic.btn, instance->generic.cnt); -} \ No newline at end of file +} diff --git a/lib/subghz/protocols/alutech_at_4n.h b/lib/subghz/protocols/alutech_at_4n.h index 185d89b06..b0ac056dd 100644 --- a/lib/subghz/protocols/alutech_at_4n.h +++ b/lib/subghz/protocols/alutech_at_4n.h @@ -10,6 +10,14 @@ extern const SubGhzProtocolDecoder subghz_protocol_alutech_at_4n_decoder; extern const SubGhzProtocolEncoder subghz_protocol_alutech_at_4n_encoder; extern const SubGhzProtocol subghz_protocol_alutech_at_4n; +// Custom buttons +void alutech_set_btn(uint8_t b); + +uint8_t alutech_get_original_btn(); +uint8_t alutech_get_custom_btn(); + +void alutech_reset_original_btn(); + /** * Allocate SubGhzProtocolEncoderAlutech_at_4n. * @param environment Pointer to a SubGhzEnvironment instance @@ -125,4 +133,4 @@ bool subghz_protocol_decoder_alutech_at_4n_deserialize( * @param context Pointer to a SubGhzProtocolDecoderAlutech_at_4n instance * @param output Resulting text */ -void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* output); \ No newline at end of file +void subghz_protocol_decoder_alutech_at_4n_get_string(void* context, FuriString* output); diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index d12e5976c..45403d279 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -136,7 +136,11 @@ static void uint8_t pack[8] = {}; if(instance->generic.cnt < 0xFFFF) { - instance->generic.cnt++; + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } else if(instance->generic.cnt >= 0xFFFF) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/faac_slh.c b/lib/subghz/protocols/faac_slh.c index 7572bd8ab..4b69ae73d 100644 --- a/lib/subghz/protocols/faac_slh.c +++ b/lib/subghz/protocols/faac_slh.c @@ -110,7 +110,7 @@ void subghz_protocol_encoder_faac_slh_free(void* context) { } static bool subghz_protocol_faac_slh_gen_data(SubGhzProtocolEncoderFaacSLH* instance) { - instance->generic.cnt++; + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); uint32_t fix = instance->generic.serial << 4 | instance->generic.btn; uint32_t hop = 0; uint32_t decrypt = 0; diff --git a/lib/subghz/protocols/keeloq.c b/lib/subghz/protocols/keeloq.c index a0970de4d..a58a95ed6 100644 --- a/lib/subghz/protocols/keeloq.c +++ b/lib/subghz/protocols/keeloq.c @@ -85,7 +85,29 @@ const SubGhzProtocol subghz_protocol_keeloq = { }; static const char* mfname; -static int kl_type; +static uint8_t kl_type; +static uint8_t btn_temp_id; +static uint8_t btn_temp_id_original; +static bool bft_prog_mode; +static uint16_t temp_counter; + +void keeloq_set_btn(uint8_t b) { + btn_temp_id = b; +} + +uint8_t keeloq_get_original_btn() { + return btn_temp_id_original; +} + +uint8_t keeloq_get_custom_btn() { + return btn_temp_id; +} + +void keeloq_reset_original_btn() { + btn_temp_id_original = 0; + temp_counter = 0; + bft_prog_mode = false; +} void keeloq_reset_mfname() { mfname = ""; @@ -136,17 +158,11 @@ void subghz_protocol_encoder_keeloq_free(void* context) { * @param instance Pointer to a SubGhzProtocolEncoderKeeloq* instance * @param btn Button number, 4 bit */ -static bool subghz_protocol_keeloq_gen_data(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) { - if(instance->generic.cnt < 0xFFFF) { - instance->generic.cnt++; - } else if(instance->generic.cnt >= 0xFFFF) { - instance->generic.cnt = 0; - } +static bool subghz_protocol_keeloq_gen_data( + SubGhzProtocolEncoderKeeloq* instance, + uint8_t btn, + bool counter_up) { uint32_t fix = (uint32_t)btn << 28 | instance->generic.serial; - uint32_t decrypt = (uint32_t)btn << 28 | - (instance->generic.serial & 0x3FF) - << 16 | //ToDo in some protocols the discriminator is 0 - instance->generic.cnt; uint32_t hop = 0; uint64_t man = 0; uint64_t code_found_reverse; @@ -155,31 +171,63 @@ static bool subghz_protocol_keeloq_gen_data(SubGhzProtocolEncoderKeeloq* instanc instance->manufacture_name = ""; } - // DTM Neo uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode -> 12bit normal learning - if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) || - (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || - (strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0)) { - decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt; + // BFT programming mode on / off conditions + if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn == 0xF)) { + bft_prog_mode = true; } - - // Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning - if((strcmp(instance->manufacture_name, "NICE_Smilo") == 0) || - (strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) || - (strcmp(instance->manufacture_name, "JCM_Tech") == 0) || - (strcmp(instance->manufacture_name, "Normstahl") == 0)) { - decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt; + if((strcmp(instance->manufacture_name, "BFT") == 0) && (btn != 0xF) && bft_prog_mode) { + bft_prog_mode = false; } + // If we using BFT programming mode we will trasmit its seed in hop part like original remote + if(bft_prog_mode) { + hop = instance->generic.seed; + } + if(counter_up && !bft_prog_mode) { + if(instance->generic.cnt < 0xFFFF) { + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } + } + if(!bft_prog_mode) { + uint32_t decrypt = (uint32_t)btn << 28 | + (instance->generic.serial & 0x3FF) + << 16 | //ToDo in some protocols the discriminator is 0 + instance->generic.cnt; + // DTM Neo uses 12bit -> simple learning -- FAAC_RC,XT , Mutanco_Mutancode -> 12bit normal learning + if((strcmp(instance->manufacture_name, "DTM_Neo") == 0) || + (strcmp(instance->manufacture_name, "FAAC_RC,XT") == 0) || + (strcmp(instance->manufacture_name, "Mutanco_Mutancode") == 0)) { + decrypt = btn << 28 | (instance->generic.serial & 0xFFF) << 16 | instance->generic.cnt; + } - if(strcmp(instance->manufacture_name, "Unknown") == 0) { - code_found_reverse = subghz_protocol_blocks_reverse_key( - instance->generic.data, instance->generic.data_count_bit); - hop = code_found_reverse & 0x00000000ffffffff; - } else if(strcmp(instance->manufacture_name, "AN-Motors") == 0) { - hop = (instance->generic.cnt & 0xFF) << 24 | (instance->generic.cnt & 0xFF) << 16 | - (instance->generic.btn & 0xF) << 12 | 0x404; - } else if(strcmp(instance->manufacture_name, "HCS101") == 0) { - hop = instance->generic.cnt << 16 | (instance->generic.btn & 0xF) << 12 | 0x000; - } else { + // Nice Smilo, MHouse, JCM, Normstahl -> 8bit serial - simple learning + if((strcmp(instance->manufacture_name, "NICE_Smilo") == 0) || + (strcmp(instance->manufacture_name, "NICE_MHOUSE") == 0) || + (strcmp(instance->manufacture_name, "JCM_Tech") == 0) || + (strcmp(instance->manufacture_name, "Normstahl") == 0)) { + decrypt = btn << 28 | (instance->generic.serial & 0xFF) << 16 | instance->generic.cnt; + } + + // Beninca -> 4bit serial - simple XOR + if(strcmp(instance->manufacture_name, "Beninca") == 0) { + decrypt = btn << 28 | (instance->generic.serial & 0xF) << 16 | instance->generic.cnt; + } + + if(strcmp(instance->manufacture_name, "Unknown") == 0) { + code_found_reverse = subghz_protocol_blocks_reverse_key( + instance->generic.data, instance->generic.data_count_bit); + hop = code_found_reverse & 0x00000000ffffffff; + } else if(strcmp(instance->manufacture_name, "AN-Motors") == 0) { + hop = (instance->generic.cnt & 0xFF) << 24 | (instance->generic.cnt & 0xFF) << 16 | + (btn & 0xF) << 12 | 0x404; + } else if(strcmp(instance->manufacture_name, "HCS101") == 0) { + hop = instance->generic.cnt << 16 | (btn & 0xF) << 12 | 0x000; + } else { for M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) { res = strcmp(furi_string_get_cstr(manufacture_code->name), instance->manufacture_name); @@ -238,6 +286,7 @@ static bool subghz_protocol_keeloq_gen_data(SubGhzProtocolEncoderKeeloq* instanc break; } } + } } if(hop) { uint64_t yek = (uint64_t)fix << 32 | hop; @@ -261,7 +310,7 @@ bool subghz_protocol_keeloq_create_data( instance->generic.cnt = cnt; instance->manufacture_name = manufacture_name; instance->generic.data_count_bit = 64; - bool res = subghz_protocol_keeloq_gen_data(instance, btn); + bool res = subghz_protocol_keeloq_gen_data(instance, btn, false); if(res) { res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } @@ -286,7 +335,7 @@ bool subghz_protocol_keeloq_bft_create_data( instance->manufacture_name = manufacture_name; instance->generic.data_count_bit = 64; // roguuemaster don't steal.!!!! - bool res = subghz_protocol_keeloq_gen_data(instance, btn); + bool res = subghz_protocol_keeloq_gen_data(instance, btn, false); if(res) { res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } @@ -302,9 +351,132 @@ static bool subghz_protocol_encoder_keeloq_get_upload(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) { furi_assert(instance); - //gen new key - if(subghz_protocol_keeloq_gen_data(instance, btn)) { - //ToDo if you need to add a callback to automatically update the data on the display + // Save original button + if(btn_temp_id_original == 0) { + btn_temp_id_original = btn; + } + + if(instance->manufacture_name == 0x0) { + instance->manufacture_name = ""; + } + if(bft_prog_mode) { + instance->manufacture_name = "BFT"; + } + uint8_t klq_last_custom_btn = 0xA; + if(strcmp(instance->manufacture_name, "BFT") == 0) { + klq_last_custom_btn = 0xF; + } + + // Set custom button + if(btn_temp_id == 1) { + switch(btn_temp_id_original) { + case 0x1: + btn = 0x2; + break; + case 0x2: + btn = 0x1; + break; + case 0xA: + btn = 0x1; + break; + case 0x4: + btn = 0x1; + break; + case 0x8: + btn = 0x1; + break; + case 0xF: + btn = 0x1; + break; + + default: + break; + } + } + if(btn_temp_id == 2) { + switch(btn_temp_id_original) { + case 0x1: + btn = 0x4; + break; + case 0x2: + btn = 0x4; + break; + case 0xA: + btn = 0x4; + break; + case 0x4: + btn = klq_last_custom_btn; + break; + case 0x8: + btn = 0x4; + break; + case 0xF: + btn = 0x4; + break; + + default: + break; + } + } + if(btn_temp_id == 3) { + switch(btn_temp_id_original) { + case 0x1: + btn = 0x8; + break; + case 0x2: + btn = 0x8; + break; + case 0xA: + btn = 0x8; + break; + case 0x4: + btn = 0x8; + break; + case 0x8: + btn = 0x2; + break; + case 0xF: + btn = 0x8; + break; + + default: + break; + } + } + if(btn_temp_id == 4) { + switch(btn_temp_id_original) { + case 0x1: + btn = klq_last_custom_btn; + break; + case 0x2: + btn = klq_last_custom_btn; + break; + case 0xA: + btn = 0x2; + break; + case 0x4: + btn = 0x2; + break; + case 0x8: + btn = klq_last_custom_btn; + break; + case 0xF: + btn = 0x2; + break; + + default: + break; + } + } + + if((btn_temp_id == 0) && (btn_temp_id_original != 0)) { + btn = btn_temp_id_original; + } + + // Generate new key + + if(subghz_protocol_keeloq_gen_data(instance, btn, true)) { + // OK } else { return false; } @@ -459,6 +631,8 @@ void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) { instance->keystore = subghz_environment_get_keystore(environment); instance->manufacture_from_file = furi_string_alloc(); + bft_prog_mode = false; + return instance; } @@ -575,7 +749,7 @@ void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t dur /** * Validation of decrypt data. * @param instance Pointer to a SubGhzBlockGeneric instance - * @param decrypt Decrypd data + * @param decrypt Decrypted data * @param btn Button number, 4 bit * @param end_serial decrement the last 10 bits of the serial number * @return true On success @@ -957,23 +1131,38 @@ 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; - // 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; - instance->cnt = key_hop >> 16; - } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { - *manufacture_name = "HCS101"; - mfname = *manufacture_name; - instance->cnt = key_hop >> 16; + + // If we are in BFT programming mode we will set previous remembered counter and skip mf keys check + if(!bft_prog_mode) { + // 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; + instance->cnt = key_hop >> 16; + } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) { + *manufacture_name = "HCS101"; + mfname = *manufacture_name; + instance->cnt = key_hop >> 16; + } else { + subghz_protocol_keeloq_check_remote_controller_selector( + instance, key_fix, key_hop, keystore, manufacture_name); + } + temp_counter = instance->cnt; + } else { - subghz_protocol_keeloq_check_remote_controller_selector( - instance, key_fix, key_hop, keystore, manufacture_name); + *manufacture_name = "BFT"; + mfname = *manufacture_name; + instance->cnt = temp_counter; } instance->serial = key_fix & 0x0FFFFFFF; instance->btn = key_fix >> 28; + + // Save original button for later use + if(btn_temp_id_original == 0) { + btn_temp_id_original = instance->btn; + } } uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context) { diff --git a/lib/subghz/protocols/keeloq.h b/lib/subghz/protocols/keeloq.h index 7b0cfc3bd..9ddf17d89 100644 --- a/lib/subghz/protocols/keeloq.h +++ b/lib/subghz/protocols/keeloq.h @@ -15,6 +15,13 @@ void keeloq_reset_mfname(); void keeloq_reset_kl_type(); +void keeloq_set_btn(uint8_t b); + +uint8_t keeloq_get_original_btn(); +uint8_t keeloq_get_custom_btn(); + +void keeloq_reset_original_btn(); + /** * Allocate SubGhzProtocolEncoderKeeloq. * @param environment Pointer to a SubGhzEnvironment instance diff --git a/lib/subghz/protocols/kinggates_stylo_4k.c b/lib/subghz/protocols/kinggates_stylo_4k.c index 5f2a83d77..1823a072a 100644 --- a/lib/subghz/protocols/kinggates_stylo_4k.c +++ b/lib/subghz/protocols/kinggates_stylo_4k.c @@ -156,7 +156,11 @@ static bool subghz_protocol_kinggates_stylo_4k_gen_data( instance->generic.cnt = decrypt & 0xFFFF; if(instance->generic.cnt < 0xFFFF) { - instance->generic.cnt++; + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } else if(instance->generic.cnt >= 0xFFFF) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index d3a2d6acd..135bd4972 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -84,6 +84,25 @@ const SubGhzProtocol subghz_protocol_nice_flor_s = { .encoder = &subghz_protocol_nice_flor_s_encoder, }; +static uint8_t n_btn_temp_id; +static uint8_t n_btn_temp_id_original; + +void nice_flors_set_btn(uint8_t b) { + n_btn_temp_id = b; +} + +uint8_t nice_flors_get_original_btn() { + return n_btn_temp_id_original; +} + +uint8_t nice_flors_get_custom_btn() { + return n_btn_temp_id; +} + +void nice_flors_reset_original_btn() { + n_btn_temp_id_original = 0; +} + static void subghz_protocol_nice_flor_s_remote_controller( SubGhzBlockGeneric* instance, const char* file_name); @@ -128,6 +147,74 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( size_t index = 0; btn = instance->generic.btn; + // Save original button for later use + if(n_btn_temp_id_original == 0) { + n_btn_temp_id_original = btn; + } + + // Set custom button + if(n_btn_temp_id == 1) { + switch(n_btn_temp_id_original) { + case 0x1: + btn = 0x2; + break; + case 0x2: + btn = 0x1; + break; + case 0x4: + btn = 0x1; + break; + case 0x8: + btn = 0x1; + break; + + default: + break; + } + } + if(n_btn_temp_id == 2) { + switch(n_btn_temp_id_original) { + case 0x1: + btn = 0x4; + break; + case 0x2: + btn = 0x4; + break; + case 0x4: + btn = 0x2; + break; + case 0x8: + btn = 0x4; + break; + + default: + break; + } + } + if(n_btn_temp_id == 3) { + switch(n_btn_temp_id_original) { + case 0x1: + btn = 0x8; + break; + case 0x2: + btn = 0x8; + break; + case 0x4: + btn = 0x8; + break; + case 0x8: + btn = 0x2; + break; + + default: + break; + } + } + + if((n_btn_temp_id == 0) && (n_btn_temp_id_original != 0)) { + btn = n_btn_temp_id_original; + } + size_t size_upload = ((instance->generic.data_count_bit * 2) + ((37 + 2 + 2) * 2) * 16); if(size_upload > instance->encoder.size_upload) { FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer."); @@ -136,7 +223,11 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( } if(instance->generic.cnt < 0xFFFF) { - instance->generic.cnt++; + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } else if(instance->generic.cnt >= 0xFFFF) { instance->generic.cnt = 0; } @@ -452,18 +543,36 @@ bool subghz_protocol_nice_flor_s_create_data( uint32_t serial, uint8_t btn, uint16_t cnt, - SubGhzRadioPreset* preset) { + SubGhzRadioPreset* preset, + bool nice_one) { furi_assert(context); SubGhzProtocolEncoderNiceFlorS* instance = context; instance->generic.serial = serial; instance->generic.cnt = cnt; - instance->generic.data_count_bit = 52; + if(nice_one) { + instance->generic.data_count_bit = NICE_ONE_COUNT_BIT; + } else { + instance->generic.data_count_bit = 52; + } uint64_t decrypt = ((uint64_t)instance->generic.serial << 16) | instance->generic.cnt; uint64_t enc_part = subghz_protocol_nice_flor_s_encrypt( decrypt, instance->nice_flor_s_rainbow_table_file_name); uint8_t byte = btn << 4 | (0xF ^ btn ^ 0x3); instance->generic.data = (uint64_t)byte << 44 | enc_part; + if(instance->generic.data_count_bit == NICE_ONE_COUNT_BIT) { + uint8_t add_data[10] = {0}; + for(size_t i = 0; i < 7; i++) { + add_data[i] = (instance->generic.data >> (48 - i * 8)) & 0xFF; + } + subghz_protocol_nice_one_get_data(add_data, 0, 0); + instance->generic.data_2 = 0; + for(size_t j = 7; j < 10; j++) { + instance->generic.data_2 <<= 8; + instance->generic.data_2 += add_data[j]; + } + } + bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); return res; @@ -642,6 +751,11 @@ static void subghz_protocol_nice_flor_s_remote_controller( instance->serial = (decrypt >> 16) & 0xFFFFFFF; instance->btn = (decrypt >> 48) & 0xF; } + + // Save original button for later use + if(n_btn_temp_id_original == 0) { + n_btn_temp_id_original = instance->btn; + } } uint8_t subghz_protocol_decoder_nice_flor_s_get_hash_data(void* context) { @@ -735,4 +849,4 @@ void subghz_protocol_decoder_nice_flor_s_get_string(void* context, FuriString* o instance->generic.cnt, instance->generic.btn); } -} \ No newline at end of file +} diff --git a/lib/subghz/protocols/nice_flor_s.h b/lib/subghz/protocols/nice_flor_s.h index e333fc979..3b22db304 100644 --- a/lib/subghz/protocols/nice_flor_s.h +++ b/lib/subghz/protocols/nice_flor_s.h @@ -11,6 +11,14 @@ extern const SubGhzProtocolDecoder subghz_protocol_nice_flor_s_decoder; extern const SubGhzProtocolEncoder subghz_protocol_nice_flor_s_encoder; extern const SubGhzProtocol subghz_protocol_nice_flor_s; +// Custom buttons +void nice_flors_set_btn(uint8_t b); + +uint8_t nice_flors_get_original_btn(); +uint8_t nice_flors_get_custom_btn(); + +void nice_flors_reset_original_btn(); + /** * Allocate SubGhzProtocolEncoderNiceFlorS. * @param environment Pointer to a SubGhzEnvironment instance @@ -55,6 +63,7 @@ uint64_t subghz_protocol_nice_flor_s_encrypt(uint64_t data, const char* file_nam * @param btn Button number, 4 bit * @param cnt Counter value, 16 bit * @param preset Modulation, SubGhzRadioPreset + * @param nice_one Nice One if true, Nice Flor S if false * @return true On success */ bool subghz_protocol_nice_flor_s_create_data( @@ -63,7 +72,8 @@ bool subghz_protocol_nice_flor_s_create_data( uint32_t serial, uint8_t btn, uint16_t cnt, - SubGhzRadioPreset* preset); + SubGhzRadioPreset* preset, + bool nice_one); /** * Allocate SubGhzProtocolDecoderNiceFlorS. diff --git a/lib/subghz/protocols/pocsag.c b/lib/subghz/protocols/pocsag.c deleted file mode 100644 index cd531660b..000000000 --- a/lib/subghz/protocols/pocsag.c +++ /dev/null @@ -1,363 +0,0 @@ -#include "pocsag.h" - -#include -#include "../blocks/const.h" -#include "../blocks/decoder.h" -#include "../blocks/generic.h" -#include "../blocks/math.h" -#include -#include - -#define TAG "POCSAG" - -static const SubGhzBlockConst pocsag_const = { - .te_short = 833, - .te_delta = 100, -}; - -// Minimal amount of sync bits (interleaving zeros and ones) -#define POCSAG_MIN_SYNC_BITS 32 -#define POCSAG_CW_BITS 32 -#define POCSAG_CW_MASK 0xFFFFFFFF -#define POCSAG_FRAME_SYNC_CODE 0x7CD215D8 -#define POCSAG_IDLE_CODE_WORD 0x7A89C197 - -#define POCSAG_FUNC_NUM 0 -#define POCSAG_FUNC_ALERT1 1 -#define POCSAG_FUNC_ALERT2 2 -#define POCSAG_FUNC_ALPHANUM 3 - -static const char* func_msg[] = {"num: ", "alert", "alert: ", "msg: "}; -static const char* bcd_chars = "*U -)("; - -struct SubGhzProtocolDecoderPocsag { - SubGhzProtocolDecoderBase base; - - SubGhzBlockDecoder decoder; - SubGhzBlockGeneric generic; - - uint8_t codeword_idx; - uint32_t ric; - uint8_t func; - - // partially decoded character - uint8_t char_bits; - uint8_t char_data; - - // message being decoded - FuriString* msg; - - // Done messages, ready to be serialized/deserialized - FuriString* done_msg; -}; - -typedef struct SubGhzProtocolDecoderPocsag SubGhzProtocolDecoderPocsag; - -typedef enum { - PocsagDecoderStepReset = 0, - PocsagDecoderStepFoundSync, - PocsagDecoderStepFoundPreamble, - PocsagDecoderStepMessage, -} PocsagDecoderStep; - -void* subghz_protocol_decoder_pocsag_alloc(SubGhzEnvironment* environment) { - UNUSED(environment); - - SubGhzProtocolDecoderPocsag* instance = malloc(sizeof(SubGhzProtocolDecoderPocsag)); - instance->base.protocol = &subghz_protocol_pocsag; - instance->generic.protocol_name = instance->base.protocol->name; - instance->msg = furi_string_alloc(); - instance->done_msg = furi_string_alloc(); - return instance; -} - -void subghz_protocol_decoder_pocsag_free(void* context) { - furi_assert(context); - SubGhzProtocolDecoderPocsag* instance = context; - furi_string_free(instance->msg); - furi_string_free(instance->done_msg); - free(instance); -} - -void subghz_protocol_decoder_pocsag_reset(void* context) { - furi_assert(context); - SubGhzProtocolDecoderPocsag* instance = context; - - instance->decoder.parser_step = PocsagDecoderStepReset; - instance->decoder.decode_data = 0UL; - instance->decoder.decode_count_bit = 0; - instance->codeword_idx = 0; - instance->char_bits = 0; - instance->char_data = 0; - furi_string_reset(instance->msg); - furi_string_reset(instance->done_msg); -} - -static void pocsag_decode_address_word(SubGhzProtocolDecoderPocsag* instance, uint32_t data) { - instance->ric = (data >> 13); - instance->ric = (instance->ric << 3) | (instance->codeword_idx >> 1); - instance->func = (data >> 11) & 0b11; -} - -static bool decode_message_alphanumeric(SubGhzProtocolDecoderPocsag* instance, uint32_t data) { - for(uint8_t i = 0; i < 20; i++) { - instance->char_data >>= 1; - if(data & (1 << 30)) { - instance->char_data |= 1 << 6; - } - instance->char_bits++; - if(instance->char_bits == 7) { - if(instance->char_data == 0) return false; - furi_string_push_back(instance->msg, instance->char_data); - instance->char_data = 0; - instance->char_bits = 0; - } - data <<= 1; - } - return true; -} - -static void decode_message_numeric(SubGhzProtocolDecoderPocsag* instance, uint32_t data) { - // 5 groups with 4 bits each - uint8_t val; - for(uint8_t i = 0; i < 5; i++) { - val = (data >> (27 - i * 4)) & 0b1111; - // reverse the order of 4 bits - val = (val & 0x5) << 1 | (val & 0xA) >> 1; - val = (val & 0x3) << 2 | (val & 0xC) >> 2; - - if(val <= 9) - val += '0'; - else - val = bcd_chars[val - 10]; - furi_string_push_back(instance->msg, val); - } -} - -// decode message word, maintaining instance state for partial decoding. Return true if more data -// might follow or false if end of message reached. -static bool pocsag_decode_message_word(SubGhzProtocolDecoderPocsag* instance, uint32_t data) { - switch(instance->func) { - case POCSAG_FUNC_ALERT2: - case POCSAG_FUNC_ALPHANUM: - return decode_message_alphanumeric(instance, data); - - case POCSAG_FUNC_NUM: - decode_message_numeric(instance, data); - return true; - } - return false; -} - -// Function called when current message got decoded, but other messages might follow -static void pocsag_message_done(SubGhzProtocolDecoderPocsag* instance) { - // append the message to the long-term storage string - furi_string_cat_printf(instance->done_msg, "RIC: %" PRIu32 ", ", instance->ric); - furi_string_cat_str(instance->done_msg, func_msg[instance->func]); - if(instance->func != POCSAG_FUNC_ALERT1) { - furi_string_cat(instance->done_msg, instance->msg); - } - furi_string_cat_str(instance->done_msg, "\r\n"); - - // reset the state - instance->char_bits = 0; - instance->char_data = 0; - furi_string_reset(instance->msg); -} - -void subghz_protocol_decoder_pocsag_feed(void* context, bool level, uint32_t duration) { - furi_assert(context); - SubGhzProtocolDecoderPocsag* instance = context; - - // reset state - waiting for 32 bits of interleaving 1s and 0s - if(instance->decoder.parser_step == PocsagDecoderStepReset) { - if(DURATION_DIFF(duration, pocsag_const.te_short) < pocsag_const.te_delta) { - // POCSAG signals are inverted - subghz_protocol_blocks_add_bit(&instance->decoder, !level); - - if(instance->decoder.decode_count_bit == POCSAG_MIN_SYNC_BITS) { - instance->decoder.parser_step = PocsagDecoderStepFoundSync; - } - } else if(instance->decoder.decode_count_bit > 0) { - subghz_protocol_decoder_pocsag_reset(context); - } - return; - } - - int bits_count = duration / pocsag_const.te_short; - uint32_t extra = duration - pocsag_const.te_short * bits_count; - - if(DURATION_DIFF(extra, pocsag_const.te_short) < pocsag_const.te_delta) - bits_count++; - else if(extra > pocsag_const.te_delta) { - // in non-reset state we faced the error signal - we reached the end of the packet, flush data - if(furi_string_size(instance->done_msg) > 0) { - if(instance->base.callback) - instance->base.callback(&instance->base, instance->base.context); - } - subghz_protocol_decoder_pocsag_reset(context); - return; - } - - uint32_t codeword; - - // handle state machine for every incoming bit - while(bits_count-- > 0) { - subghz_protocol_blocks_add_bit(&instance->decoder, !level); - - switch(instance->decoder.parser_step) { - case PocsagDecoderStepFoundSync: - if((instance->decoder.decode_data & POCSAG_CW_MASK) == POCSAG_FRAME_SYNC_CODE) { - instance->decoder.parser_step = PocsagDecoderStepFoundPreamble; - instance->decoder.decode_count_bit = 0; - instance->decoder.decode_data = 0UL; - } - break; - case PocsagDecoderStepFoundPreamble: - // handle codewords - if(instance->decoder.decode_count_bit == POCSAG_CW_BITS) { - codeword = (uint32_t)(instance->decoder.decode_data & POCSAG_CW_MASK); - switch(codeword) { - case POCSAG_IDLE_CODE_WORD: - instance->codeword_idx++; - break; - case POCSAG_FRAME_SYNC_CODE: - instance->codeword_idx = 0; - break; - default: - // Here we expect only address messages - if(codeword >> 31 == 0) { - pocsag_decode_address_word(instance, codeword); - instance->decoder.parser_step = PocsagDecoderStepMessage; - } - instance->codeword_idx++; - } - instance->decoder.decode_count_bit = 0; - instance->decoder.decode_data = 0UL; - } - break; - - case PocsagDecoderStepMessage: - if(instance->decoder.decode_count_bit == POCSAG_CW_BITS) { - codeword = (uint32_t)(instance->decoder.decode_data & POCSAG_CW_MASK); - switch(codeword) { - case POCSAG_IDLE_CODE_WORD: - // Idle during the message stops the message - instance->codeword_idx++; - instance->decoder.parser_step = PocsagDecoderStepFoundPreamble; - pocsag_message_done(instance); - break; - case POCSAG_FRAME_SYNC_CODE: - instance->codeword_idx = 0; - break; - default: - // In this state, both address and message words can arrive - if(codeword >> 31 == 0) { - pocsag_message_done(instance); - pocsag_decode_address_word(instance, codeword); - } else { - if(!pocsag_decode_message_word(instance, codeword)) { - instance->decoder.parser_step = PocsagDecoderStepFoundPreamble; - pocsag_message_done(instance); - } - } - instance->codeword_idx++; - } - instance->decoder.decode_count_bit = 0; - instance->decoder.decode_data = 0UL; - } - break; - } - } -} - -uint8_t subghz_protocol_decoder_pocsag_get_hash_data(void* context) { - furi_assert(context); - SubGhzProtocolDecoderPocsag* instance = context; - uint8_t hash = 0; - for(size_t i = 0; i < furi_string_size(instance->done_msg); i++) - hash ^= furi_string_get_char(instance->done_msg, i); - return hash; -} - -bool subghz_protocol_decoder_pocsag_serialize( - void* context, - FlipperFormat* flipper_format, - SubGhzRadioPreset* preset) { - furi_assert(context); - SubGhzProtocolDecoderPocsag* instance = context; - uint32_t msg_len; - - if(!subghz_block_generic_serialize(&instance->generic, flipper_format, preset)) return false; - - msg_len = furi_string_size(instance->done_msg); - if(!flipper_format_write_uint32(flipper_format, "MsgLen", &msg_len, 1)) { - FURI_LOG_E(TAG, "Error adding MsgLen"); - return false; - } - - uint8_t* s = (uint8_t*)furi_string_get_cstr(instance->done_msg); - if(!flipper_format_write_hex(flipper_format, "Msg", s, msg_len)) { - FURI_LOG_E(TAG, "Error adding Msg"); - return false; - } - return true; -} - -bool subghz_protocol_decoder_pocsag_deserialize(void* context, FlipperFormat* flipper_format) { - furi_assert(context); - SubGhzProtocolDecoderPocsag* instance = context; - bool ret = false; - uint32_t msg_len; - uint8_t* buf; - - do { - if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) { - break; - } - - if(!flipper_format_read_uint32(flipper_format, "MsgLen", &msg_len, 1)) { - FURI_LOG_E(TAG, "Missing MsgLen"); - break; - } - - buf = malloc(msg_len); - if(!flipper_format_read_hex(flipper_format, "Msg", buf, msg_len)) { - FURI_LOG_E(TAG, "Missing Msg"); - free(buf); - break; - } - furi_string_set_strn(instance->done_msg, (const char*)buf, msg_len); - free(buf); - - ret = true; - } while(false); - return ret; -} - -void subhz_protocol_decoder_pocsag_get_string(void* context, FuriString* output) { - furi_assert(context); - SubGhzProtocolDecoderPocsag* instance = context; - furi_string_cat_printf(output, "%s\r\n", instance->generic.protocol_name); - furi_string_cat(output, instance->done_msg); -} - -const SubGhzProtocolDecoder subghz_protocol_pocsag_decoder = { - .alloc = subghz_protocol_decoder_pocsag_alloc, - .free = subghz_protocol_decoder_pocsag_free, - .reset = subghz_protocol_decoder_pocsag_reset, - .feed = subghz_protocol_decoder_pocsag_feed, - .get_hash_data = subghz_protocol_decoder_pocsag_get_hash_data, - .serialize = subghz_protocol_decoder_pocsag_serialize, - .deserialize = subghz_protocol_decoder_pocsag_deserialize, - .get_string = subhz_protocol_decoder_pocsag_get_string, -}; - -const SubGhzProtocol subghz_protocol_pocsag = { - .name = SUBGHZ_PROTOCOL_POCSAG_NAME, - .type = SubGhzProtocolTypeStatic, - .flag = SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Save | - SubGhzProtocolFlag_Load, - - .decoder = &subghz_protocol_pocsag_decoder, -}; diff --git a/lib/subghz/protocols/pocsag.h b/lib/subghz/protocols/pocsag.h deleted file mode 100644 index 5700e2401..000000000 --- a/lib/subghz/protocols/pocsag.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "base.h" - -#define SUBGHZ_PROTOCOL_POCSAG_NAME "POCSAG" - -extern const SubGhzProtocol subghz_protocol_pocsag; diff --git a/lib/subghz/protocols/secplus_v2.c b/lib/subghz/protocols/secplus_v2.c index bcef90dad..9f8c31654 100644 --- a/lib/subghz/protocols/secplus_v2.c +++ b/lib/subghz/protocols/secplus_v2.c @@ -379,7 +379,8 @@ static void subghz_protocol_secplus_v2_encode(SubGhzProtocolEncoderSecPlus_v2* i uint8_t roll_1[9] = {0}; uint8_t roll_2[9] = {0}; - instance->generic.cnt++; + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + //ToDo it is not known what value the counter starts if(instance->generic.cnt > 0xFFFFFFF) instance->generic.cnt = 0xE500000; uint32_t rolling = subghz_protocol_blocks_reverse_key(instance->generic.cnt, 28); diff --git a/lib/subghz/protocols/somfy_keytis.c b/lib/subghz/protocols/somfy_keytis.c index ab9202cc3..1bcd89f42 100644 --- a/lib/subghz/protocols/somfy_keytis.c +++ b/lib/subghz/protocols/somfy_keytis.c @@ -131,7 +131,11 @@ static bool instance->generic.serial = data & 0xFFFFFF; if(instance->generic.cnt < 0xFFFF) { - instance->generic.cnt++; + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } else if(instance->generic.cnt >= 0xFFFF) { instance->generic.cnt = 0; } diff --git a/lib/subghz/protocols/somfy_telis.c b/lib/subghz/protocols/somfy_telis.c index 96997c581..5d6b1c6f3 100644 --- a/lib/subghz/protocols/somfy_telis.c +++ b/lib/subghz/protocols/somfy_telis.c @@ -73,6 +73,25 @@ const SubGhzProtocol subghz_protocol_somfy_telis = { .encoder = &subghz_protocol_somfy_telis_encoder, }; +static uint8_t st_btn_temp_id; +static uint8_t st_btn_temp_id_original; + +void somfy_telis_set_btn(uint8_t b) { + st_btn_temp_id = b; +} + +uint8_t somfy_telis_get_original_btn() { + return st_btn_temp_id_original; +} + +uint8_t somfy_telis_get_custom_btn() { + return st_btn_temp_id; +} + +void somfy_telis_reset_original_btn() { + st_btn_temp_id_original = 0; +} + void* subghz_protocol_encoder_somfy_telis_alloc(SubGhzEnvironment* environment) { UNUSED(environment); SubGhzProtocolEncoderSomfyTelis* instance = malloc(sizeof(SubGhzProtocolEncoderSomfyTelis)); @@ -95,23 +114,104 @@ void subghz_protocol_encoder_somfy_telis_free(void* context) { free(instance); } -static bool - subghz_protocol_somfy_telis_gen_data(SubGhzProtocolEncoderSomfyTelis* instance, uint8_t btn) { - UNUSED(btn); +static bool subghz_protocol_somfy_telis_gen_data( + SubGhzProtocolEncoderSomfyTelis* instance, + uint8_t btn, + bool new_remote) { + // If we doing a clone we will use its data uint64_t data = instance->generic.data ^ (instance->generic.data >> 8); - instance->generic.btn = (data >> 44) & 0xF; // ctrl - instance->generic.cnt = (data >> 24) & 0xFFFF; // rolling code - instance->generic.serial = data & 0xFFFFFF; // address + if(!new_remote) { + instance->generic.btn = (data >> 44) & 0xF; // ctrl + btn = instance->generic.btn; + instance->generic.cnt = (data >> 24) & 0xFFFF; // rolling code + instance->generic.serial = data & 0xFFFFFF; // address + } + + // Save original button for later use + if(st_btn_temp_id_original == 0) { + st_btn_temp_id_original = btn; + } + + // Set custom button + if(st_btn_temp_id == 1) { + switch(st_btn_temp_id_original) { + case 0x1: + btn = 0x2; + break; + case 0x2: + btn = 0x1; + break; + case 0x4: + btn = 0x1; + break; + case 0x8: + btn = 0x1; + break; + + default: + break; + } + } + if(st_btn_temp_id == 2) { + switch(st_btn_temp_id_original) { + case 0x1: + btn = 0x4; + break; + case 0x2: + btn = 0x4; + break; + case 0x4: + btn = 0x2; + break; + case 0x8: + btn = 0x4; + break; + + default: + break; + } + } + if(st_btn_temp_id == 3) { + switch(st_btn_temp_id_original) { + case 0x1: + btn = 0x8; + break; + case 0x2: + btn = 0x8; + break; + case 0x4: + btn = 0x8; + break; + case 0x8: + btn = 0x2; + break; + + default: + break; + } + } + + if((st_btn_temp_id == 0) && (st_btn_temp_id_original != 0)) { + btn = st_btn_temp_id_original; + } if(instance->generic.cnt < 0xFFFF) { - instance->generic.cnt++; + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } else if(instance->generic.cnt >= 0xFFFF) { instance->generic.cnt = 0; } uint8_t frame[7]; - frame[0] = data >> 48; - frame[1] = instance->generic.btn << 4; + if(!new_remote) { + frame[0] = data >> 48; + } else { + frame[0] = 0xA7; + } + frame[1] = btn << 4; frame[2] = instance->generic.cnt >> 8; frame[3] = instance->generic.cnt; frame[4] = instance->generic.serial >> 16; @@ -150,7 +250,7 @@ bool subghz_protocol_somfy_telis_create_data( instance->generic.serial = serial; instance->generic.cnt = cnt; instance->generic.data_count_bit = 56; - bool res = subghz_protocol_somfy_telis_gen_data(instance, btn); + bool res = subghz_protocol_somfy_telis_gen_data(instance, btn, true); if(res) { res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset); } @@ -168,7 +268,7 @@ static bool subghz_protocol_encoder_somfy_telis_get_upload( furi_assert(instance); //gen new key - if(subghz_protocol_somfy_telis_gen_data(instance, btn)) { + if(subghz_protocol_somfy_telis_gen_data(instance, btn, false)) { //ToDo if you need to add a callback to automatically update the data on the display } else { return false; @@ -579,6 +679,11 @@ static void subghz_protocol_somfy_telis_check_remote_controller(SubGhzBlockGener instance->btn = (data >> 44) & 0xF; // ctrl instance->cnt = (data >> 24) & 0xFFFF; // rolling code instance->serial = data & 0xFFFFFF; // address + + // Save original button for later use + if(st_btn_temp_id_original == 0) { + st_btn_temp_id_original = instance->btn; + } } /** diff --git a/lib/subghz/protocols/somfy_telis.h b/lib/subghz/protocols/somfy_telis.h index b5e989866..bca58b64b 100644 --- a/lib/subghz/protocols/somfy_telis.h +++ b/lib/subghz/protocols/somfy_telis.h @@ -11,6 +11,14 @@ extern const SubGhzProtocolDecoder subghz_protocol_somfy_telis_decoder; extern const SubGhzProtocolEncoder subghz_protocol_somfy_telis_encoder; extern const SubGhzProtocol subghz_protocol_somfy_telis; +// Custom buttons +void somfy_telis_set_btn(uint8_t b); + +uint8_t somfy_telis_get_original_btn(); +uint8_t somfy_telis_get_custom_btn(); + +void somfy_telis_reset_original_btn(); + /** * Allocate SubGhzProtocolEncoderSomfyTelis. * @param environment Pointer to a SubGhzEnvironment instance diff --git a/lib/subghz/protocols/star_line.c b/lib/subghz/protocols/star_line.c index 3066c6e2b..e09e7e951 100644 --- a/lib/subghz/protocols/star_line.c +++ b/lib/subghz/protocols/star_line.c @@ -139,7 +139,11 @@ void subghz_protocol_encoder_star_line_free(void* context) { static bool subghz_protocol_star_line_gen_data(SubGhzProtocolEncoderStarLine* instance, uint8_t btn) { if(instance->generic.cnt < 0xFFFF) { - instance->generic.cnt++; + if((instance->generic.cnt + furi_hal_subghz_get_rolling_counter_mult()) >= 0xFFFF) { + instance->generic.cnt = 0; + } else { + instance->generic.cnt += furi_hal_subghz_get_rolling_counter_mult(); + } } else if(instance->generic.cnt >= 0xFFFF) { instance->generic.cnt = 0; } diff --git a/lib/subghz/subghz_keystore.h b/lib/subghz/subghz_keystore.h index 43f8356d0..06ae8adae 100644 --- a/lib/subghz/subghz_keystore.h +++ b/lib/subghz/subghz_keystore.h @@ -77,4 +77,4 @@ bool subghz_keystore_raw_get_data(const char* file_name, size_t offset, uint8_t* #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/lib/toolbox/level_duration.h b/lib/toolbox/level_duration.h index 9406cef31..7618344ac 100644 --- a/lib/toolbox/level_duration.h +++ b/lib/toolbox/level_duration.h @@ -13,8 +13,8 @@ #define LEVEL_DURATION_RESERVED 0x800000U typedef struct { - uint32_t level; - uint32_t duration; + uint32_t duration : 30; + uint8_t level : 2; } LevelDuration; static inline LevelDuration level_duration_make(bool level, uint32_t duration) { diff --git a/scripts/assets.py b/scripts/assets.py index c1a9f8097..0520c9fb6 100755 --- a/scripts/assets.py +++ b/scripts/assets.py @@ -5,7 +5,6 @@ from flipper.app import App from flipper.assets.icon import file2image import os -import shutil import pathlib ICONS_SUPPORTED_FORMATS = ["png"] @@ -289,7 +288,6 @@ class Main(App): self.logger.info(f"Packing") dolphin.pack(self.args.output_directory, self.args.symbol_name) self.logger.info(f"Complete") - __import__("time").sleep(2) return 0 diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 4f960de83..7ee86de02 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -51,7 +51,6 @@ class FlipperApplication: stack_size: int = 2048 icon: Optional[str] = None order: int = 0 - link: Optional[str] = "" sdk_headers: List[str] = field(default_factory=list) targets: List[str] = field(default_factory=lambda: ["all"]) @@ -325,7 +324,6 @@ class ApplicationsCGenerator: .name = "{app.name}", .stack_size = {app.stack_size}, .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .link = "{f"{app.link}" if app.link else "NULL"}", .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" def generate(self): diff --git a/scripts/fbt/util.py b/scripts/fbt/util.py index ee7562058..7bdaea031 100644 --- a/scripts/fbt/util.py +++ b/scripts/fbt/util.py @@ -8,6 +8,10 @@ import os WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") +# Used by default when globbing for files with GlobRecursive +# Excludes all files ending with ~, usually created by editors as backup files +GLOB_FILE_EXCLUSION = ["*~"] + def tempfile_arg_esc_func(arg): arg = quote_spaces(arg) diff --git a/scripts/fbt_tools/fbt_assets.py b/scripts/fbt_tools/fbt_assets.py index e17487358..d2a58f3fb 100644 --- a/scripts/fbt_tools/fbt_assets.py +++ b/scripts/fbt_tools/fbt_assets.py @@ -27,9 +27,7 @@ def proto_emitter(target, source, env): def dolphin_emitter(target, source, env): res_root_dir = source[0].Dir(env["DOLPHIN_RES_TYPE"]) source = [res_root_dir] - source.extend( - env.GlobRecursive("*.*", res_root_dir.srcnode()), - ) + source.extend(env.GlobRecursive("*.*", res_root_dir.srcnode())) target_base_dir = target[0] env.Replace(_DOLPHIN_OUT_DIR=target[0]) diff --git a/scripts/fbt_tools/fbt_debugopts.py b/scripts/fbt_tools/fbt_debugopts.py index f4b021c20..9abe59893 100644 --- a/scripts/fbt_tools/fbt_debugopts.py +++ b/scripts/fbt_tools/fbt_debugopts.py @@ -47,6 +47,7 @@ def generate(env, **kw): "source ${FBT_DEBUG_DIR}/gdbinit", ], GDBOPTS_BLACKMAGIC=[ + "-q", "-ex", "monitor swdp_scan", "-ex", diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index e1c7641db..214afd8af 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -169,7 +169,6 @@ def prepare_app_metadata(target, source, env): sdk_cache = SdkCache(env["SDK_DEFINITION"].path, load_version_only=True) if not sdk_cache.is_buildable(): - print(target, source, env) raise UserError( "SDK version is not finalized, please review changes and re-run operation" ) diff --git a/scripts/fbt_tools/fbt_sdk.py b/scripts/fbt_tools/fbt_sdk.py index 48faf2125..3a37eacc9 100644 --- a/scripts/fbt_tools/fbt_sdk.py +++ b/scripts/fbt_tools/fbt_sdk.py @@ -219,7 +219,9 @@ def gen_sdk_data(sdk_cache: SdkCache): def _check_sdk_is_up2date(sdk_cache: SdkCache): if not sdk_cache.is_buildable(): - print("Working with WIP SDK. Expect failures") + raise UserError( + "SDK version is not finalized, please review changes and re-run operation" + ) def validate_sdk_cache(source, target, env): diff --git a/scripts/fbt_tools/sconsrecursiveglob.py b/scripts/fbt_tools/sconsrecursiveglob.py index 32ff55ea1..fbcee965b 100644 --- a/scripts/fbt_tools/sconsrecursiveglob.py +++ b/scripts/fbt_tools/sconsrecursiveglob.py @@ -1,7 +1,11 @@ import SCons +from SCons.Script import Flatten +from fbt.util import GLOB_FILE_EXCLUSION -def GlobRecursive(env, pattern, node=".", exclude=None): +def GlobRecursive(env, pattern, node=".", exclude=[]): + exclude = list(set(Flatten(exclude) + GLOB_FILE_EXCLUSION)) + # print(f"Starting glob for {pattern} from {node} (exclude: {exclude})") results = [] if isinstance(node, str): node = env.Dir(node) @@ -13,7 +17,7 @@ def GlobRecursive(env, pattern, node=".", exclude=None): source=True, exclude=exclude, ) - # print(f"Glob for {pattern} from {node}: {results}") + # print(f"Glob result for {pattern} from {node}: {results}") return results diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index 1863cd2bb..cbd1320b6 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -3,7 +3,6 @@ import logging import os import sys import shutil -import pathlib from collections import Counter from flipper.utils.fff import * @@ -34,7 +33,6 @@ class DolphinBubbleAnimation: min_level: int, max_level: int, weight: int, - subpath: str = None, ): # Manifest self.name = name @@ -43,7 +41,6 @@ class DolphinBubbleAnimation: self.min_level = min_level self.max_level = max_level self.weight = weight - self.subpath = subpath # Meta and data self.meta = {} self.frames = [] @@ -186,12 +183,7 @@ class DolphinBubbleAnimation: bubble["_NextBubbleIndex"] = bubble_index + 1 def save(self, output_directory: str): - if self.subpath: - animation_directory = os.path.join( - output_directory, self.subpath, self.name - ) - else: - animation_directory = os.path.join(output_directory, self.name) + animation_directory = os.path.join(output_directory, self.name) os.makedirs(animation_directory, exist_ok=True) meta_filename = os.path.join(animation_directory, "meta.txt") @@ -263,8 +255,8 @@ class DolphinManifest: self.animations = [] self.logger = logging.getLogger("DolphinManifest") - def load(self, loc: str, subpath: str = None): - manifest_filename = os.path.join(loc, "manifest.txt") + def load(self, source_directory: str): + manifest_filename = os.path.join(source_directory, "manifest.txt") file = FlipperFormatFile() file.load(manifest_filename) @@ -294,17 +286,11 @@ class DolphinManifest: # Initialize animation animation = DolphinBubbleAnimation( - name, - min_butthurt, - max_butthurt, - min_level, - max_level, - weight, - subpath, + name, min_butthurt, max_butthurt, min_level, max_level, weight ) # Load Animation meta and frames - animation.load(os.path.join(loc, name)) + animation.load(os.path.join(source_directory, name)) # Add to array self.animations.append(animation) @@ -373,20 +359,11 @@ class Dolphin: self.manifest = DolphinManifest() self.logger = logging.getLogger("Dolphin") - def load(self, input_directory, dirs: list = None): - if dirs: - input = str(pathlib.Path(input_directory).absolute()) - for path in dirs: - path = str(pathlib.Path(path).absolute()) - assert os.path.isdir(path) - # Load Manifest - self.logger.info(f"Loading directory {path}") - self.manifest.load(path, subpath=path.removeprefix(input + os.sep)) - else: - assert os.path.isdir(input_directory) - # Load Manifest - self.logger.info(f"Loading directory {input_directory}") - self.manifest.load(input_directory) + def load(self, source_directory: str): + assert os.path.isdir(source_directory) + # Load Manifest + self.logger.info(f"Loading directory {source_directory}") + self.manifest.load(source_directory) def pack(self, output_directory: str, symbol_name: str = None): self.manifest.save(output_directory, symbol_name) diff --git a/scripts/flipper/assets/icon.py b/scripts/flipper/assets/icon.py index ed85b024e..f0dae25be 100644 --- a/scripts/flipper/assets/icon.py +++ b/scripts/flipper/assets/icon.py @@ -105,7 +105,7 @@ def file2image(file): data_enc = bytearray([len(data_enc) & 0xFF, len(data_enc) >> 8]) + data_enc # Use encoded data only if its length less than original, including header - if len(data_enc) < len(data_bin) + 1: + if len(data_enc) + 2 < len(data_bin) + 1: data = b"\x01\x00" + data_enc else: data = b"\x00" + data_bin diff --git a/scripts/merge_report_qa.py b/scripts/merge_report_qa.py index c0707848e..caa742408 100755 --- a/scripts/merge_report_qa.py +++ b/scripts/merge_report_qa.py @@ -17,7 +17,7 @@ def parse_args(): def checkCommitMessage(msg): - regex = re.compile(r"^'?\[FL-\d+\]") + regex = re.compile(r"^'?\[(FL-\d+,?\s?)+\]") if regex.match(msg): return True return False diff --git a/scripts/runfap.py b/scripts/runfap.py index 9f544fd90..410b3e7d2 100644 --- a/scripts/runfap.py +++ b/scripts/runfap.py @@ -16,11 +16,11 @@ class Main(App): def init(self): self.parser.add_argument("-p", "--port", help="CDC Port", default="auto") self.parser.add_argument( - "-l", - "--launch", + "-n", + "--no-launch", dest="launch_app", - action="store_true", - help="Launch app", + action="store_false", + help="Don't launch app", ) self.parser.add_argument("fap_src_path", help="App file to upload") @@ -91,11 +91,14 @@ class Main(App): self.logger.error(f"Error: upload failed: {storage.last_error}") return -3 - storage.send_and_wait_eol(f'loader open "Applications" {fap_dst_path}\r') - result = storage.read.until(storage.CLI_EOL) - if len(result): - self.logger.error(f"Unexpected response: {result.decode('ascii')}") - return -4 + if self.args.launch_app: + storage.send_and_wait_eol( + f'loader open "Applications" {fap_dst_path}\r' + ) + result = storage.read.until(storage.CLI_EOL) + if len(result): + self.logger.error(f"Unexpected response: {result.decode('ascii')}") + return -4 return 0 finally: diff --git a/scripts/sconsdist.py b/scripts/sconsdist.py index ce261954c..0fa120d87 100644 --- a/scripts/sconsdist.py +++ b/scripts/sconsdist.py @@ -166,13 +166,11 @@ class Main(App): ) ) bundle_args.extend(self.other_args) - log_custom_fz_name = environ.get("CUSTOM_FLIPPER_NAME", None) or "" - if ( - (log_custom_fz_name != "") - and (len(log_custom_fz_name) <= 8) - and (log_custom_fz_name.isalnum()) - and (log_custom_fz_name.isascii()) - ): + log_custom_fz_name = ( + environ.get("CUSTOM_FLIPPER_NAME", None) + or "" + ) + if (log_custom_fz_name != "") and (len(log_custom_fz_name) <= 8) and (log_custom_fz_name.isalnum()) and (log_custom_fz_name.isascii()): self.logger.info( f"Flipper Custom Name is set:\n\tName: {log_custom_fz_name} : length - {len(log_custom_fz_name)} chars" ) diff --git a/scripts/update.py b/scripts/update.py index 3259c5b09..2b0157260 100755 --- a/scripts/update.py +++ b/scripts/update.py @@ -199,7 +199,7 @@ class Main(App): def disclaimer(self): self.logger.error( - "You might brick you device into a state in which you'd need an SWD programmer to fix it." + "You might brick your device into a state in which you'd need an SWD programmer to fix it." ) self.logger.error( "Please confirm that you REALLY want to do that with --I-understand-what-I-am-doing=yes" diff --git a/scripts/version.py b/scripts/version.py index ed2e83162..6ae83099d 100644 --- a/scripts/version.py +++ b/scripts/version.py @@ -1,4 +1,5 @@ #!/usb/bin/env python3 +VERSION = "XFW-0041" from flipper.app import App @@ -11,24 +12,9 @@ from datetime import date, datetime class GitVersion: def __init__(self, source_dir): self.source_dir = source_dir - self.gitlist = [ - ("commit", "rev-parse --short HEAD"), - ("branch", "rev-parse --abbrev-ref"), - ("branch_num", "rev-list -count HEAD"), - ] def get_version_info(self): - commit = branch = branch_num = "XFW-0041" - - # We dont use an `or` in commands that we expect to fail. It will serve no function. - # We also dont try;exept an entire block of code. This is bad practise. We only try the single part that we expect to fail! - # Furthermore, traceback.format_exc() is a thing. Fucking use it. JFC - - for git_tuple in self.gitlist: - try: - exec(f"{git_tuple[0]} = {self._exec_git(git_tuple[1])}") - except: - exec(f'{git_tuple[0]} = "Unknown"') + commit = self._exec_git("rev-parse --short HEAD") or "unknown" dirty = False try: @@ -39,35 +25,49 @@ class GitVersion: # If WORKFLOW_BRANCH_OR_TAG is set in environment, is has precedence # (set by CI) + branch = ( + os.environ.get("WORKFLOW_BRANCH_OR_TAG", None) + or VERSION + or self._exec_git("rev-parse --abbrev-ref HEAD") + or "unknown" + ) - custom_fz_name = os.environ.get("CUSTOM_FLIPPER_NAME", None) or "" + branch_num = self._exec_git("rev-list --count HEAD") or "n/a" - force_no_dirty = os.environ.get("FORCE_NO_DIRTY", None) or "" + version = ( + os.environ.get("DIST_SUFFIX", None) + or VERSION + or "unknown" + ) - if force_no_dirty != "": + custom_fz_name = ( + os.environ.get("CUSTOM_FLIPPER_NAME", None) + or "" + ) + + force_no_dirty = ( + os.environ.get("FORCE_NO_DIRTY", None) + or "" + ) + if (force_no_dirty != ""): dirty = False - if ( - (custom_fz_name != "") - and (len(custom_fz_name) <= 8) - and (custom_fz_name.isalnum()) - and (custom_fz_name.isascii()) - ): + if (custom_fz_name != "") and (len(custom_fz_name) <= 8) and (custom_fz_name.isalnum()) and (custom_fz_name.isascii()): return { "GIT_COMMIT": commit, - "GIT_BRANCH": "dev", + "GIT_BRANCH": branch, "GIT_BRANCH_NUM": branch_num, "FURI_CUSTOM_FLIPPER_NAME": custom_fz_name, - "VERSION": "0.74.3", - "BUILD_DIRTY": 0, + "VERSION": version, + "BUILD_DIRTY": dirty and 1 or 0, } else: return { "GIT_COMMIT": commit, - "GIT_BRANCH": "dev", + "GIT_BRANCH": branch, "GIT_BRANCH_NUM": branch_num, - "VERSION": "0.74.3", - "BUILD_DIRTY": 0, + "VERSION": version, + "BUILD_DIRTY": dirty and 1 or 0, } def _exec_git(self, args): diff --git a/test_iso7816_helpers.c b/test_iso7816_helpers.c deleted file mode 100644 index 91d420dd1..000000000 --- a/test_iso7816_helpers.c +++ /dev/null @@ -1,243 +0,0 @@ -#include -#include - -#include "lib/nfc/helpers/iso7816.h" - -#define COLOR_RED "\033[0;31m" -#define COLOR_GREEN "\033[0;32m" -#define COLOR_RESET "\033[0;0m" - -#define num_elements(A) (sizeof(A)/sizeof(A[0])) - -//TODO: do something with ISO7816-4 Table 9 — Interindustry data objects for tag allocation authority -//0x06 Object identifier (encoding specified in ISO/IEC 8825-1, see examples in annex A) -//0x41 Country code (encoding specified in ISO 3166-1 [1] ) and optional national data -//0x42 Issuer identification number (encoding and registration specified in ISO/IEC 7812-1 [3] ) and optional issuer data -//0x4F Application identifier (AID, encoding specified in 8.2.1.2) - -void print_hex(const uint8_t* data, size_t length) { - for(size_t i=0; i -#include -#include -#include - -#include "applications/main/nfc/test_bac_creds.h" //TODO: remove - -#include "lib/nfc/protocols/mrtd_helpers.h" - -// gcc -o test_mrtd_helpers -Wall -Ilib/mbedtls/include -Itoolchain/x86_64-linux/arm-none-eabi/include/ lib/nfc/protocols/mrtd_helpers.c lib/mbedtls/library/sha1.c lib/mbedtls/library/des.c lib/mbedtls/library/platform_util.c test_mrtd_helpers.c - -#define COLOR_RED "\033[0;31m" -#define COLOR_GREEN "\033[0;32m" -#define COLOR_RESET "\033[0;0m" - -void print_hex(const uint8_t* data, size_t length) { - for(uint8_t i=0; i